Yahoo JapanとOAuth(signpost利用)してみる。

Yahoo JapanとID連携したいという仕事があった。
Yahooが終わった後には他の所とも連携するらしく拡張性がないとだめ。
さらにJavaでやるとのこと。Javarの自分としては面白そうだったので首をつっこんでみた。

まずは拡張性ということでどこでも使えそうなライブラリーを探してみた。

Googleコード
http://oauth.googlecode.com/svn/code/

signpost
http://code.google.com/p/oauth-signpost/

scribe
http://oauth.net/code/

色々触ってみて、signpostが一番綺麗に書けそうなので、signpostを利用。

inquisitorさんの所にサンプルがあった。
http://blog.unfindable.net/archives/788

これを使ってみた。

動かない・・・。

こんなメッセージが返ってくる。

oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key,oauth_signature_method,oauth_signature,oauth_timestamp,oauth_nonce
要するにパラメーターがついていませんよ。

そんなことないはずだと思い、全く同じコードでTwitterさんにリクエストを投げてみる→動いた。

送り先のURLをhttpsからhttpに変更して、パケットキャプチャしてみた。

0000   41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 3a 20 4f  Authorization: O
0010 41 75 74 68 20 6f 61 75 74 68 5f 63 61 6c 6c 62 Auth oauth_callb
0020 61 63 6b 3d 22 6f 6f 62 22 2c 20 6f 61 75 74 68 ack="oob", oauth
0030 5f 63 6f 6e 73 75 6d 65 72 5f 6b 65 79 3d 22 64 _consumer_key="d

パラメーター間にスペースが入っている。
signpostのほうを見てみる。

public class AuthorizationHeaderSigningStrategy implements SigningStrategy {

private static final long serialVersionUID = 1L;

public String writeSignature(String signature, HttpRequest request,
HttpParameters requestParameters) {
StringBuilder sb = new StringBuilder();

sb.append("OAuth ");

// add the realm parameter, if any
if (requestParameters.containsKey("realm")) {
sb.append(requestParameters.getAsHeaderElement("realm"));
sb.append(", ");
}

// add all (x_)oauth parameters
HttpParameters oauthParams = requestParameters.getOAuthParameters();
oauthParams.put(OAuth.OAUTH_SIGNATURE, signature, true);

Iterator iter = oauthParams.keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
sb.append(oauthParams.getAsHeaderElement(key));
if (iter.hasNext()) {
sb.append(", ");
}
}

String header = sb.toString();
OAuth.debugOut("Auth Header", header);
request.setHeader(OAuth.HTTP_AUTHORIZATION_HEADER, header);

return header;
}

}

Yahoo専用のSigningStrategyを作ってみる。

public class YahooAuthorizationHeaderSigningStrategy implements SigningStrategy {

private static final long serialVersionUID = 1L;

public String writeSignature(String signature, HttpRequest request,
HttpParameters requestParameters) {
StringBuilder sb = new StringBuilder();

sb.append("OAuth ");

// add the realm parameter, if any
if (requestParameters.containsKey("realm")) {
sb.append(requestParameters.getAsHeaderElement("realm"));
sb.append(",");
}

// add all (x_)oauth parameters
HttpParameters oauthParams = requestParameters.getOAuthParameters();
oauthParams.put(OAuth.OAUTH_SIGNATURE, signature, true);

Iterator iter = oauthParams.keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
sb.append(oauthParams.getAsHeaderElement(key));
if (iter.hasNext()) {
sb.append(",");
}
}

String header = sb.toString();
OAuth.debugOut("Auth Header", header);
request.setHeader(OAuth.HTTP_AUTHORIZATION_HEADER, header);

return header;
}

}

見にくいけど、スペースを削ってある。

使い方(inquisitorさんのほぼコピペ。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.basic.DefaultOAuthProvider;

public class OAuthTest {
public static void main(String[] args) throws Exception {
OAuthConsumer consumer = new DefaultOAuthConsumer(
"consumer-key",
"consumer-secret");

consumer.setSigningStrategy(new YahooAuthorizationHeaderSigningStrategy());

OAuthProvider provider = new DefaultOAuthProvider(
"https://auth.login.yahoo.co.jp/oauth/v2/get_request_token",
"https://auth.login.yahoo.co.jp/oauth/v2/get_token",
"https://auth.login.yahoo.co.jp/oauth/v2/request_auth");

String authUrl = provider.retrieveRequestToken(consumer,
OAuth.OUT_OF_BAND);
System.out.println("このURLにアクセスし、表示されるPINを入力してください。");
System.out.println(authUrl);
System.out.print("PIN:");

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String pin = br.readLine();

provider.retrieveAccessToken(consumer, pin);
System.out.println("Access token: " + consumer.getToken());
System.out.println("Token secret: " + consumer.getTokenSecret());
String guid = provider.getResponseParameters().get("xoauth_yahoo_guid")
.first();
System.out.println("GUID: " + guid);
}
}

GUIDがあるので、あとはこれを使ってやればYahooさんのAPIを使える。
その時にもYahooAuthorizationHeaderSigningStrategy使う必要あり。

感想:
見やすいようにしたのかなぜスペース入れたんだろう。
そしてなぜスペースくらい許可してくれないんだろう。