
ここまでサンプルを元にEvernoteにアクセスしてきましたが、
SimpleOAuthRequestの中身を見てOAuthアクセスへの理解を
深めておきましょう。。。。って思ったんですけど、PLANTEXTでアクセスしているので
HMAC-SHA1でアクセスしてみましょう。
以下が元ソースです。
見られる場合は展開してください。
- /**
- * Copyright 2008 by EverNote Corporation. All rights reserved.
- */
- package com.evernote.oauth.consumer;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Random;
- /**
- * This is a very simple implementation of an OAuth consumer request which can
- * be used to ask an OAuth service provider for either a Request Token or
- * an Access Token. It only handles PLAINTEXT authentication, and it only goes
- * over a GET transport. As a result, it should only be used over SSL.
- *
- * @author Dave Engberg
- */
- public class SimpleOAuthRequest {
- /**
- * Random number generator for creating OAuth nonces
- */
- private static final Random random = new Random();
- /**
- * The URL of the OAuth service Provider that we should hit to request a
- * token.
- */
- private String providerUrl;
- /**
- * A mapping containing all of the OAuth parameters that will be passed in
- * the reply.
- */
- private Map<string, string=""> parameters = new HashMap<string, string="">();
- /**
- * Constructs a request object that can be used to make token requests from
- * an OAuth provider.
- *
- * @param providerUrl the base URL to request a Request or Access token
- * @param consumerKey the OAuth consumer key, given by the Service Provider
- * @param consumerSecret the OAuth consumer secret, given by the Provider
- * @param tokenSecret if non-null, this is the previous oauth_token_secret
- * that should be used in signing this request. If null, this will assume
- * that this message does not include a token secret in its signature
- */
- public SimpleOAuthRequest(String providerUrl, String consumerKey,
- String consumerSecret, String tokenSecret) {
- this.providerUrl = providerUrl;
- setParameter("oauth_consumer_key", consumerKey);
- String signature = consumerSecret + "&";
- if (tokenSecret != null) {
- signature += tokenSecret;
- }
- setParameter("oauth_signature", signature);
- setParameter("oauth_signature_method", "PLAINTEXT");
- setParameter("oauth_timestamp",
- Long.toString(System.currentTimeMillis() / 1000));
- setParameter("oauth_nonce",
- Long.toHexString(random.nextLong()));
- setParameter("oauth_version", "1.0");
- }
- /**
- * Sets one of the query string parameters for the request that will be
- * made to the OAuth provider. The value will be URL encoded before adding
- * to the URL.
- *
- * @param name the name of the parameter to be set
- * @param value the string value, unencoded
- */
- public void setParameter(String name, String value) {
- parameters.put(name, value);
- }
- /**
- * Encodes this request as a single URL that can be opened.
- */
- public String encode() throws IOException {
- StringBuilder sb = new StringBuilder();
- sb.append(providerUrl);
- boolean firstParam = providerUrl.indexOf('?') < 0;
- for (Map.Entry<string, string=""> parameter : parameters.entrySet()) {
- if (firstParam) {
- sb.append('?');
- firstParam = false;
- } else {
- sb.append('&');
- }
- sb.append(parameter.getKey());
- sb.append('=');
- sb.append(URLEncoder.encode(parameter.getValue(), "UTF-8"));
- }
- return sb.toString();
- }
- /**
- * Sends the request to the OAuth Provider, and returns the set of reply
- * parameters, mapped from name to decoded value.
- *
- * @throws IOException if a problem occurs making the request or getting the
- * reply.
- */
- public Map<string,string> sendRequest() throws IOException {
- HttpURLConnection connection =
- (HttpURLConnection)(new URL(encode())).openConnection();
- int responseCode = connection.getResponseCode();
- if (responseCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Server returned error code: " + responseCode +
- " " + connection.getResponseMessage());
- }
- BufferedReader bufferedReader = new BufferedReader(
- new InputStreamReader(connection.getInputStream()));
- String result = bufferedReader.readLine();
- Map<string,string> responseParameters = new HashMap<string,string>();
- for (String param : result.split("&")) {
- int equalsAt = param.indexOf('=');
- if (equalsAt > 0) {
- String name = param.substring(0, equalsAt);
- String value =
- URLDecoder.decode(param.substring(equalsAt + 1), "UTF-8");
- responseParameters.put(name, value);
- }
- }
- return responseParameters;
- }
- }
- </string,string></string,string></string,string></string,></string,></string,>
これをHMAC-SHA1で処理を行う場合は、oauth_signatureの指定に
・HTTPメソッド
・リクエストURL
・リクエストパタメータ
これらをURLエンコードして、&で結合してHMAC-SHA1で16進のダイジェスト値を作って
Base64エンコード後、URLエンコードした値をoauth_signatureに指定します。
オリジナルでEvernoteRequestクラスを作成してアクセスしてみましょう。
※動作確認用なので汚いのは許して><
以下がHMAC-SHA1でアクセスしたソース
- /**
- * Copyright 2008 by EverNote Corporation. All rights reserved.
- */
- package jp.co.ziro.evernote.controller;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.UnsupportedEncodingException;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- import java.security.InvalidKeyException;
- import java.security.NoSuchAlgorithmException;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Random;
- import java.util.TreeMap;
- import java.util.logging.Logger;
- import javax.crypto.Mac;
- import javax.crypto.spec.SecretKeySpec;
- import org.apache.commons.codec.binary.Base64;
- import org.slim3.util.ApplicationMessage;
- /**
- * This is a very simple implementation of an OAuth consumer request which can
- * be used to ask an OAuth service provider for either a Request Token or an
- * Access Token. It only handles PLAINTEXT authentication, and it only goes over
- * a GET transport. As a result, it should only be used over SSL.
- *
- * @author Dave Engberg
- */
- public class EvernoteRequest {
- @SuppressWarnings("unused")
- private static Logger logger = Logger.getLogger(EvernoteRequest.class.getName());
- private static final String consumerKey = ApplicationMessage
- .get("evernote.api.key");
- private static final String consumerSecret = ApplicationMessage
- .get("evernote.api.secret");
- private static final String urlBase = ApplicationMessage
- .get("evernote.api.baseUrl");
- private static final String requestUrl = urlBase
- + ApplicationMessage.get("evernote.api.requestTokenUrl");
- /**
- * ベースのURL
- * @return
- */
- public static String getBaseUrl() {
- return urlBase;
- }
- /**
- * Random number generator for creating OAuth nonces
- */
- private static final Random random = new Random();
- /**
- * A mapping containing all of the OAuth parameters that will be passed in
- * the reply.
- */
- private Map<string, string=""> parameters = new TreeMap<string, string="">();
- /**
- * Constructs a request object that can be used to make token requests from
- * an OAuth provider.
- */
- public EvernoteRequest() {
- setParameter("oauth_consumer_key", consumerKey);
- //暗号化を行う
- setParameter("oauth_signature_method", "HMAC-SHA1");
- setParameter("oauth_timestamp", getTimestamp());
- setParameter("oauth_nonce", Long.toHexString(random.nextLong()));
- setParameter("oauth_version", "1.0");
- }
- /**
- * タイムスタンプを作成
- * @return
- */
- private String getTimestamp() {
- return Long.toString(System.currentTimeMillis() / 1000);
- }
- /**
- * Sets one of the query string parameters for the request that will be made
- * to the OAuth provider. The value will be URL encoded before adding to the
- * URL.
- *
- * @param name
- * the name of the parameter to be set
- * @param value
- * the string value, unencoded
- */
- public void setParameter(String name, String value) {
- parameters.put(name, value);
- }
- /**
- * Encodes this request as a single URL that can be opened.
- */
- private String encode() {
- return requestUrl + "?" + join();
- }
- /**
- * HTTP引数の連結
- * @return
- */
- private String join() {
- StringBuilder sb = new StringBuilder();
- boolean firstParam = true;
- for (Map.Entry<string, string=""> parameter : parameters.entrySet()) {
- if (firstParam) {
- firstParam = false;
- } else {
- sb.append('&');
- }
- sb.append(parameter.getKey());
- sb.append('=');
- try {
- sb.append(URLEncoder.encode(parameter.getValue(), CHARSET));
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("エンコード時の例外", e);
- }
- }
- return sb.toString();
- }
- /**
- * 文字コード
- */
- private static final String CHARSET = "UTF-8";
- /**
- * キー作成用のGETメソッド名
- */
- private static final String REQUEST_METHOD = "GET";
- /**
- * Sends the request to the OAuth Provider, and returns the set of reply
- * parameters, mapped from name to decoded value.
- *
- * @throws IOException
- * if a problem occurs making the request or getting the reply.
- */
- public Map<string, string=""> sendRequest(String tokenSecret) throws IOException {
- // 署名対象のテキストを作成
- String secret = consumerSecret + "&";
- if (tokenSecret != null) {
- secret += tokenSecret;
- }
- String hmac = "HmacSHA1";
- String encodeUrl = URLEncoder.encode(requestUrl,CHARSET);
- String encodeJoin = URLEncoder.encode(join(),CHARSET);
- String signatureBaseString = REQUEST_METHOD + "&" + encodeUrl + "&" + encodeJoin;
- logger.info(signatureBaseString);
- byte[] secretyKeyBytes = secret.getBytes(CHARSET);
- SecretKeySpec secretKeySpec = new SecretKeySpec(secretyKeyBytes,hmac);
- Mac mac;
- try {
- mac = Mac.getInstance(hmac);
- mac.init(secretKeySpec);
- } catch (NoSuchAlgorithmException e1) {
- throw new RuntimeException("暗号化インスタンス取得失敗",e1);
- } catch (InvalidKeyException e1) {
- throw new RuntimeException("暗号化インスタンス取得失敗",e1);
- }
- String signature = null;
- byte[] data;
- byte[] rawHmac;
- try {
- data = signatureBaseString.getBytes(CHARSET);
- rawHmac = mac.doFinal(data);
- Base64 encoder = new Base64();
- signature = new String(encoder.encode(rawHmac));
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(CHARSET + " is unsupported!", e);
- }
- setParameter("oauth_signature", signature);
- HttpURLConnection connection = (HttpURLConnection) (new URL(encode())).openConnection();
- int responseCode = connection.getResponseCode();
- // リクエストが正常じゃない場合
- if (responseCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Server returned error code: " + responseCode
- + " " + connection.getResponseMessage());
- }
- return createResponseMap(connection);
- }
- /**
- * レスポンスの値を取得
- *
- * @param connection
- * @return
- */
- private Map<string, string=""> createResponseMap(HttpURLConnection connection) {
- BufferedReader bufferedReader;
- String result;
- try {
- bufferedReader = new BufferedReader(new InputStreamReader(
- connection.getInputStream()));
- result = bufferedReader.readLine();
- } catch (IOException e) {
- throw new RuntimeException("読み込み時の例外", e);
- }
- Map<string, string=""> responseParameters = new HashMap<string, string="">();
- for (String param : result.split("&")) {
- int equalsAt = param.indexOf('=');
- if (equalsAt > 0) {
- String name = param.substring(0, equalsAt);
- String value;
- try {
- value = URLDecoder.decode(param.substring(equalsAt + 1),
- CHARSET);
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("エンコード時の例外", e);
- }
- responseParameters.put(name, value);
- }
- }
- return responseParameters;
- }
- }
- </string,></string,></string,></string,></string,></string,></string,>
・・・本当に汚い、、、
で、これを利用してindex時に
- EvernoteRequest oauthRequestor = new EvernoteRequest();
- String thisUrl = request.getRequestURL().toString();
- String cbUrl = thisUrl.substring(0, thisUrl.lastIndexOf('/') + 1);
- cbUrl = cbUrl + "callback";
- oauthRequestor.setParameter("oauth_callback", cbUrl);
- Map<string, string=""> reply = oauthRequestor.sendRequest(null);
- String requestToken = reply.get("oauth_token");
- String tokenSecret = reply.get("oauth_token_secret");
- String authorizationUrl = authorizationUrlBase + "?oauth_token=" + requestToken;
- sessionScope("tokenSecret",tokenSecret);
- </string,>
という風にします。
すべての引数を指定した後にoauth_signatureを生成するので
sendRequest()にtokenSecretを持ってきています。(コールバック時に利用)
リクエストトークンとともにtokenSecretは取得できます。
アクセストークンを取得する際に使用するtokenSecretをセッションに残しています。
で以下がコールバックの処理。
- EvernoteRequest oauthRequestor = new EvernoteRequest();
- String requestToken = requestScope("oauth_token");
- String verifier = requestScope("oauth_verifier");
- String tokenSecret = sessionScope("tokenSecret");
- oauthRequestor.setParameter( "oauth_token", requestToken);
- oauthRequestor.setParameter( "oauth_verifier", verifier);
- //取得する
- Map<string, string=""> reply = oauthRequestor.sendRequest(tokenSecret);
- </string,>
こちらはセッションからtokenSecretを取得して指定しているだけですね。
んーAuthrorization Headerでアクセスしたいですよねー。
アクセスもPOSTでもないですし。。。本物はそうしてみようっ。と。
次回、OAuthを読んでいくか、APIアクセスをもう少し行ってみるか悩んでます。
それを記述するのはOAuthの仕様なだけなのでそっち読めば良いかなぁ、、、と。
0 件のコメント:
コメントを投稿