Zend Framework でサイボウズLiveに XAuth 認証してみる


無料で使えるグループウェアのサイボウズLiveですが、実はAPIも用意されていて自前のプログラムから掲示板データなどを取得することも出来ます。

ただ、現在公開されているサンプルの多くが OAuth による実装となっていて、例えば夜間バッチで一日分の書き込みデータをまとめて取得する、というような使い方ができません。

しかしAPIのドキュメントを読む限り、どうやらXAuth型の通信もできる様子。そこで数少ない情報を頼りに自前で実装してみることにしました。使用するのは Zend Framework 1.12.3 です。

OAuth と XAuth での実装の違い

そもそも OAuth や XAuth がどういった技術かという話は既に解説サイトがたくさんあるため割愛しますが、XAuth で実装する以上、OAuth で見られるようなログイン画面やコールバックURLという概念が存在しません。ログインアカウントはあくまでもプログラム上で API に渡してやる必要があります。

APIのドキュメントを読むと下記のように書かれていました。
https://developer.cybozulive.com/doc/current/pub/authorize.html#id3

ユーザーが明示的に端末にインストールして使うアプリケーションの場合は、xAuth を使って認証ステップを省略できます。 アクセストークンを取得するためのエンドポイント (https://api.cybozulive.com/oauth/token) に、OAuth で必要な署名情報と 以下のパラメータを POST してください。ユーザーのパスワードを送信しますので、プロトコルは必ず https:// を使ってください。

・x_auth_username : サイボウズ Live のユーザー名です
・x_auth_password : サイボウズ Live のパスワードです
・x_auth_mode : 値は client_auth のみ有効です。

認証に成功するとアクセストークンが返されます。アクセストークンはコンシューマーが保管してください。

……情報はこれだけです。しかし、XAuth なのだからアクセストークンの取得と同時にアカウント情報も渡せと言われている、ということは伝わりました。

何はともあれ、さっそく Zend Framework で実装してみましょう。

アクセストークンを取得してみる

さて、Zend での実装を始めたいところですが、どうやら Zend Framework には XAuth 用のクラスが用意されていないようです(2.x系ならあるのでしょうか?)。仕方がないので OAuth 用の Zend_Oauth_Consumer で代用してみましょう。


$config = array(
		'siteUrl'			=> 'https://api.cybozulive.com/',
		'requestTokenUrl'	=> 'https://api.cybozulive.com/oauth/initiate',
		'accessTokenUrl'	=> 'https://api.cybozulive.com/oauth/token',
		'authorizeUrl'		=> 'https://api.cybozulive.com/oauth/authorize',
		'consumerKey'		=> '## コンシューマートークン・キー ##',
		'consumerSecret'	=> '## コンシューマートークン・シークレット ##',
);

$param = array(
		'x_auth_mode'			=> 'client_auth',
		'x_auth_username'		=> '## サイボウズLiveのログインアカウント ##',
		'x_auth_password'		=> '## サイボウズLiveのパスワード ##'
);

$consumer = new Zend_Oauth_Consumer($config);

// ここで詰まる…。
// var_dump($consumer->getAccessToken($param));

これでアクセストークンを取得することが出来る…と思いきや、この実装だと肝心の getAccessToken に渡す引数が足りません。Zend_Oauth_Consumer は OAuth 用のクラスなので、まず getRequestToken を実行してリクエストトークンを取得し、そのトークンを引数として getAccessToken を実行するという前提になっています。

しかし、前述の通り XAuth にはコールバックURLという概念が無いため、そもそもリクエストトークンを取得するという処理が存在しません。さて困ったぞということで色々と考えたのですが、ならば getRequestToken 関数の接続先を accessTokenUrl に偽装してみたらどうか、ということに気づきました。具体的には下記のようになります。

// ★requestTokenUrlがaccessTokenUrlと同じになっている点に注意!
// authorizeUrlは無くても良さそうだが、関数内で使用しているようなので設定している
$config = array(
		'siteUrl'			=> 'https://api.cybozulive.com/',
		'requestTokenUrl'	=> 'https://api.cybozulive.com/oauth/token',
		'accessTokenUrl'	=> 'https://api.cybozulive.com/oauth/token',
		'authorizeUrl'		=> 'https://api.cybozulive.com/oauth/authorize',
		'consumerKey'		=> '## コンシューマートークン・キー ##',
		'consumerSecret'	=> '## コンシューマートークン・シークレット ##',
);

$param = array(
		'x_auth_mode'			=> 'client_auth',
		'x_auth_username'		=> '## サイボウズLiveのログインアカウント ##',
		'x_auth_password'		=> '## サイボウズLiveのパスワード ##'
);

$consumer = new Zend_Oauth_Consumer($config);

// ★アクセストークンを取得する場面だが、getRequestTokenを実行
var_dump($consumer->getRequestToken($param));

getRequestToken の戻り値を確認すると、Zend_Oauth_Token_Request という型に oauth_token と oauth_token_secret が設定されたものが返って来ていました。これで一応、アクセストークンを取得することは出来たようです。

掲示板データの取得

ではこのアクセストークンを用いて、サイボウズLive上に書き込まれた掲示板データを取得してみたいと思います……が、前の手順で「getRequestToken の接続先を偽装して AccessToken を取得する」という方法を用いたがために、取得したアクセストークンが Zend_Oauth_Token_Request の型に入った状態になっています。本来アクセストークンは getAccessToken 関数で取得するため、Zend_Oauth_Http_AccessToken の型で取得できることになります。この型だと掲示板データのエンドポイントにアクセスするための機能なども提供されるのですが、Zend_Oauth_Token_Request にはそれがありません。

仕方がないので Zend_Http_Client を利用して接続してみましょう。Zend_Http_Client はシンプルなHTTP/HTTPSアクセスを提供するクラスですが、XAuth とは結局特定の URI を叩いているに過ぎないので、引数さえ揃えてやれば Zend_Http_Client でも代用できるはずです。

// (上と同じなので省略)

// ★アクセストークンを取得する場面だが、getRequestTokenを実行
var_dump($consumer->getRequestToken($param));

// ここから掲示板データの取得処理		
$client = new Zend_Http_Client();
$client->setUri('https://api.cybozulive.com/api/board/V2');
$client->setMethod(Zend_Http_Client::GET);

$bbsParam = array(
		'embed-comment'		=> 'true',
		'group'				=> '1:111111',  // サイボウズのグループのID。アンダーバーをコロンに代える必要あり。
		'max-results'		=> '100',
		'start-index'		=> '0'
);

さて、ここで問題になってくるのが引数の作り方です。実は、XAuth で渡すべきパラメータはそう単純ではありません。APIの資料にも「OAuth で必要な署名情報と以下のパラメータ」と記載されており、本来 OAuth で投げるべきパラメータも設定する必要があります。この中には「oauth_signature」という OAuth 通信に必要なパラメータを連結した上で暗号化したもの等も含まれており、自前で実装するにはかなりの手間がかかります。

ではどうするかという話ですが、OAuth のパラメータなのだから OAuth のクラスに作らせてみましょう。先ほど話に出た Zend_Oauth_Http_AccessToken を new し、うまいこと引数を作る関数だけを外部から呼び出せないか試してみます。

// (上と同じなので省略)

// ★アクセストークンを取得する場面だが、getRequestTokenを実行
var_dump($consumer->getRequestToken($param));

// ここから掲示板データの取得処理		
$client = new Zend_Http_Client();
$client->setUri('https://api.cybozulive.com/api/board/V2');
$client->setMethod(Zend_Http_Client::GET);

$bbsParam = array(
		'embed-comment'		=> 'true',
		'group'				=> '1:111111',  // サイボウズのグループのID。アンダーバーをコロンに代える必要あり。
		'max-results'		=> '100',
		'start-index'		=> '0'
);

$consumer->setHttpClient($client);

$accessToken = new Zend_Oauth_Http_AccessToken($consumer);
$accessToken->setMethod(Zend_Http_Client::GET);
$accessToken->setParameters($bbsParam);

$params = $accessToken->assembleParams();

$client->setParameterGet($params);

$response = $client->request();
var_dump($response->getBody());

これでうまく行くはず…と思っていたのですが、実際に動かしたところなぜか「oauth_signature が一致しない」と怒られてしまいました。調べてみたところ、どうやら assembleParams 関数は内部的に accessTokenUrl を接続先にする前提で oauth_signature を組み立てており、今回のように掲示板のURIを指定することは出来ないようです。

しかし、あと一歩のところまで来ているのだからここで断念する手はありません。使用される URI が異なるのであれば、正しい URI を返すように拡張してやればいいだけです。

// Zend_Oauth_Consumerを拡張したクラスを作成する
class Sysdays_Http_XAuth_Consumer extends Zend_Oauth_Consumer {
	
	public function getAccessTokenUrl() {
		return $this->getHttpClient()->getUri(true);
	}
}

このように、Zend_Oauth_Consumer 内でアクセストークンURIを取得しようとした際に HttpClient が持つ URI に挿げ替えてやりましょう。HttpClient には掲示板 API の URI が設定されているので、これで掲示板のエンドポイントに接続出来ます。

まとめると、下記のようなソースコードになります。

// Zend_Oauth_Consumerを拡張したクラスを作成する
class Sysdays_Http_XAuth_Consumer extends Zend_Oauth_Consumer {
	
	public function getAccessTokenUrl() {
		return $this->getHttpClient()->getUri(true);
	}
}
// ★requestTokenUrlがaccessTokenUrlと同じになっている点に注意!
// authorizeUrlは無くても良さそうだが、関数内で使用しているようなので設定している
$config = array(
		'siteUrl'			=> 'https://api.cybozulive.com/',
		'requestTokenUrl'	=> 'https://api.cybozulive.com/oauth/token',
		'accessTokenUrl'	=> 'https://api.cybozulive.com/oauth/token',
		'authorizeUrl'		=> 'https://api.cybozulive.com/oauth/authorize',
		'consumerKey'		=> '## コンシューマートークン・キー ##',
		'consumerSecret'	=> '## コンシューマートークン・シークレット ##',
);

$param = array(
		'x_auth_mode'			=> 'client_auth',
		'x_auth_username'		=> '## サイボウズLiveのログインアカウント ##',
		'x_auth_password'		=> '## サイボウズLiveのパスワード ##'
);

// ★Zend_Oauth_Consumerではなく、それを拡張したSysdays_Http_XAuth_Consumerを使用する
$consumer = new Sysdays_Http_XAuth_Consumer($config);

// ★アクセストークンを取得する場面だが、getRequestTokenを実行
var_dump($consumer->getRequestToken($param));

// ここから掲示板データの取得処理		
$client = new Zend_Http_Client();
$client->setUri('https://api.cybozulive.com/api/board/V2');
$client->setMethod(Zend_Http_Client::GET);

$bbsParam = array(
		'embed-comment'		=> 'true',
		'group'				=> '1:111111',  // サイボウズのグループのID。アンダーバーをコロンに代える必要あり。
		'max-results'		=> '100',
		'start-index'		=> '0'
);

$consumer->setHttpClient($client);

$accessToken = new Zend_Oauth_Http_AccessToken($consumer);
$accessToken->setMethod(Zend_Http_Client::GET);
$accessToken->setParameters($bbsParam);

$params = $accessToken->assembleParams();

$client->setParameterGet($params);

$response = $client->request();
var_dump($response->getBody());

これでようやく、掲示板データを取得することが出来ました。


宮野 清隆株式会社シスデイズ代表取締役社長
プロジェクトマネージャ・アプリケーションエンジニア・テクニカルエンジニアなど、
多数の高度情報処理資格を保有するITのスペシャリスト。2008年にシスデイズを設立し、代表に就任。
2012年より上位2%のIQを保有するものだけが参加できる団体「JAPAN MENSA」に所属。
2014年よりJAPAN MENSA財務担当、2016年よりJAPAN MENSA副会長に就任。
お問い合わせ

同じカテゴリの記事