メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2009年8月3日月曜日

[Apache Shindig][お勉強][OpenSocial] メモ120 shindigで3legged OAuthなるものをしてみる

OAuthには、2legged OAuthなるものと、3legged OAuthなるものがあるらしい。
で、署名付きリクエストは、2legged OAuthというらしい。

2legged OAuthはHMACもRSAもやってみたので、次は3legged OAuthなるものをやってみる。
サービスプロバイダはGoogle。
サンプルとしてGoogle Contact(だっけ?)にアクセスして
自分で構築したShindig環境でアドレス張のデータを表示してみる。

おおきな作業の流れは以下な感じ。
1) ガジェットを用意
2) とりあえずShindigを動かして、該当するガジェット別のdomainを取得
3) google アカウントのManageDomainsページにアクセスし、2)で取得したドメインを登録
4) 3)で登録するとconsumer keyとconsumer secretが発行されるので、それをconfig/oauth.jsonへ記述。
5) ガジェットXMLの一部修正
6) shindigコンパイル&起動
でできるはず。


1) まずガジェットXMLを用意。

http://code.google.com/intl/ja/apis/gadgets/docs/oauth.html
のページを見ると、gadgetのサンプルXMLがあるので、それをコピペ。

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <Module>  
  3.   <ModulePrefs title="OAuth Contacts" scrolling="true">  
  4.     <Require feature="opensocial-0.8" />  
  5.     <Require feature="locked-domain"/>  
  6.     <OAuth>  
  7.       <Service name="google">  
  8.         <Access url="https://www.google.com/accounts/OAuthGetAccessToken" method="GET" />  
  9.         <Request url="https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.google.com/m8/feeds/" method="GET" />  
  10.         <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken?oauth_callback=http://oauth.gmodules.com/gadgets/oauthcallback" />  
  11.       </Service>  
  12.     </OAuth>  
  13.   </ModulePrefs>  
  14.   <Content type="html">  
  15.   <![CDATA[ 
  16.  
  17.   <!-- shindig oauth popup handling code --> 
  18.   <script src="http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/popup.js"></script> 
  19.  
  20.   <style> 
  21.   #main { 
  22.     margin: 0px; 
  23.     padding: 0px; 
  24.     font-size: small; 
  25.   } 
  26.   </style> 
  27.  
  28.   <div id="main" style="display: none"> 
  29.   </div> 
  30.  
  31.   <div id="approval" style="display: none"> 
  32.     <img src="http://gadget-doc-examples.googlecode.com/svn/trunk/images/new.gif"> 
  33.     <a href="#" id="personalize">Personalize this gadget</a> 
  34.   </div> 
  35.  
  36.   <div id="waiting" style="display: none"> 
  37.     Please click 
  38.     <a href="#" id="approvaldone">I've approved access</a> 
  39.     once you've approved access to your data. 
  40.   </div> 
  41.  
  42.   <script type="text/javascript"> 
  43.     // Display UI depending on OAuth access state of the gadget (see <divs> above). 
  44.     // If user hasn't approved access to data, provide a "Personalize this gadget" link 
  45.     // that contains the oauthApprovalUrl returned from makeRequest. 
  46.     // 
  47.     // If the user has opened the popup window but hasn't yet approved access, display 
  48.     // text prompting the user to confirm that s/he approved access to data.  The user 
  49.     // may not ever need to click this link, if the gadget is able to automatically 
  50.     // detect when the user has approved access, but showing the link gives users 
  51.     // an option to fetch their data even if the automatic detection fails. 
  52.     // 
  53.     // When the user confirms access, the fetchData() function is invoked again to 
  54.     // obtain and display the user's data. 
  55.     function showOneSection(toshow) { 
  56.       var sections = [ 'main', 'approval', 'waiting' ]; 
  57.       for (var i=0; i < sections.length; ++i) { 
  58.         var s = sections[i]; 
  59.         var el = document.getElementById(s); 
  60.         if (s === toshow) { 
  61.           el.style.display = "block"; 
  62.         } else { 
  63.           el.style.display = "none"; 
  64.         } 
  65.       } 
  66.     } 
  67.  
  68.     // Process returned JSON feed to display data. 
  69.     function showResults(result) { 
  70.       showOneSection('main'); 
  71.  
  72.       var titleElement = document.createElement('div'); 
  73.       var nameNode = document.createTextNode(result.feed.title.$t); 
  74.       titleElement.appendChild(nameNode); 
  75.       document.getElementById("main").appendChild(titleElement); 
  76.       document.getElementById("main").appendChild(document.createElement("br")); 
  77.  
  78.       list = result.feed.entry; 
  79.  
  80.       for(var i = 0; i < list.length; i++) { 
  81.         entry = list[i]; 
  82.         var divElement = document.createElement('div'); 
  83.         divElement.setAttribute('class', 'name'); 
  84.         var valueNode = document.createTextNode(entry.gd$email[0].address); 
  85.         divElement.appendChild(nameNode); 
  86.         divElement.appendChild(valueNode); 
  87.         document.getElementById("main").appendChild(divElement); 
  88.       } 
  89.     } 
  90.  
  91.     // Invoke makeRequest() to fetch data from the service provider endpoint. 
  92.     // Depending on the results of makeRequest, decide which version of the UI 
  93.     // to ask showOneSection() to display. If user has approved access to his 
  94.     // or her data, display data. 
  95.     // If the user hasn't approved access yet, response.oauthApprovalUrl contains a 
  96.     // URL that includes a Google-supplied request token. This is presented in the 
  97.     // gadget as a link that the user clicks to begin the approval process. 
  98.     function fetchData() { 
  99.       var params = {}; 
  100.       url = "http://www.google.com/m8/feeds/contacts/default/base?alt=json"; 
  101.       params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON; 
  102.       params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.OAUTH; 
  103.       params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "google"; 
  104.       params[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always"; 
  105.       params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET; 
  106.  
  107.       gadgets.io.makeRequest(url, function (response) { 
  108.         if (response.oauthApprovalUrl) { 
  109.           // Create the popup handler. The onOpen function is called when the user 
  110.           // opens the popup window. The onClose function is called when the popup 
  111.           // window is closed. 
  112.           var popup = shindig.oauth.popup({ 
  113.             destination: response.oauthApprovalUrl, 
  114.             windowOptions: null, 
  115.             onOpen: function() { showOneSection('waiting'); }, 
  116.             onClose: function() { fetchData(); } 
  117.           }); 
  118.           // Use the popup handler to attach onclick handlers to UI elements.  The 
  119.           // createOpenerOnClick() function returns an onclick handler to open the 
  120.           // popup window.  The createApprovedOnClick function returns an onclick 
  121.           // handler that will close the popup window and attempt to fetch the user's 
  122.           // data again. 
  123.           var personalize = document.getElementById('personalize'); 
  124.           personalize.onclick = popup.createOpenerOnClick(); 
  125.           var approvaldone = document.getElementById('approvaldone'); 
  126.           approvaldone.onclick = popup.createApprovedOnClick(); 
  127.           showOneSection('approval'); 
  128.         } else if (response.data) { 
  129.           showOneSection('main'); 
  130.           showResults(response.data); 
  131.         } else { 
  132.           // The response.oauthError and response.oauthErrorText values may help debug 
  133.           // problems with your gadget. 
  134.           var main = document.getElementById('main'); 
  135.           var err = document.createTextNode('OAuth error: ' + 
  136.             response.oauthError + ': ' + response.oauthErrorText); 
  137.           main.appendChild(err); 
  138.           showOneSection('main'); 
  139.         } 
  140.       }, params); 
  141.     } 
  142.     // Call fetchData() when gadget loads. 
  143.     gadgets.util.registerOnLoadHandler(fetchData); 
  144.   </script> 
  145.   ]]>  
  146.   </Content>  
  147. </Module>  


コピペしただけ。
hogehoge.xmlとして保存する。
外部からhttp://www.example.com/opensocial/hogehoge.xmlとして見える場所に設置。


2) とりあえずShindigを動かして、該当するガジェット別のdomainを取得
lockedDomain機能を有効にしているので、gadgetXML毎のiframeのdomainが分からない。
SHA1の結果をBase32してみても良いんだけど、Shindig動かした方が楽しかったので、
そうした。

表示された結果のソースファイルを見てみると、、

http://59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com/gadgets/ifr?url=http://www.example.com/opensocial/hogehoge.xml

などとiframeのsrc属性だったので、ホスト名を抜き出す。
すると、

59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com

なんてなものが抜き出せる。


3) google アカウントのManageDomainsページにアクセスし、2)で取得したドメインを登録

2)で抜き出したgadgets毎のiframeのドメインをgoogleアカウントのmanageDomainsから登録する。
URLはhttps://www.google.com/accounts/ManageDomains
で、「Add a New Domain」ってところから2)で取得した

59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com

を登録。
Googleからverifyなリクエストが飛んでくるので、とある決まったファイルを置いておく。
(登録時にGoogleの画面に従えばOK)



4) 3)で登録するとconsumer keyとconsumer secretが発行されるので、それをconfig/oauth.jsonへ記述。
3)で登録完了すると、

OAuth Consumer Key: 59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com
OAuth Consumer Secret: hogehogehoge

などと表示されるので、それをshindigのconfig/oauth.jsonへ記述する。
記述したoauth.jsonは以下な感じ。
  1. {  
  2.   "http://www.example.com/opensocial/hello.xml" : {  
  3.     "google" : {  
  4.       "consumer_key" : "59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com",  
  5.       "consumer_secret""hogehogehoge",  
  6.       "key_type" : "HMAC_SYMMETRIC"  
  7.     }  
  8.   }  
  9. }  

3行目の"google"は、ガジェットの<Service name="google">と合わせておくっぽい。


5) ガジェットXMLの一部修正

Googleからコピーしてきたガジェットを修正する。
ガジェットXMLの10行目、
  1. <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken?oauth_callback=http://oauth.gmodules.com/gadgets/oauthcallback" />  

というところを
  1. <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken" />  

とoauth_callback以降を削除。
とりあえず、今はコールバックいらないんで。
また、shindig.propertiesのshindig.signing.global-callback-urlも空にセット。


6) shindigコンパイル&起動
そしたら、shindigをコンパイル&起動する。
で、ガジェットを表示してみる。

すると画面に

Personalize this gadget

というリンクが表示されるんで、クリックする。
すると、別Windowが開いて、Googleにログインしていなければ、Googleのログイン画面が表示される。
ログインすると、

The site 59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com is requesting access to your Google Account for the product(s) listed below.

なんて書かれたページが表示される。そのページの「Grant access」ボタンを押下。
ボタンを押下すると、

You have successfully granted 59vs5qn45f2fqulv6shuu20n9v6ig218.gadget.example.com access to your Google Account. You can revoke access at any time under 'My Account'.

なんて書かれたページが表示される。このWindowはもういらないので、閉じる。

するとあら不思議。
ガジェットにメールアドレス一覧が表示されているではありませんか!


そんだけ。

--
まだいろいろ試したわけじゃないので、なんとも言えないが、
ガジェットを表示する際のOWNERとVIEWERをGoogleのアカウント名と合わせておかないと
駄目かも。
--
OWNERを合わせておかないと、ダメかも。
OWNERが違うときにはGoogle側でエラーになる。
--
ちなみに上記は、Shindig-1.1-SNAPSHOTでやった。
(Java版)

--(2009/08/11)
OwnerIdとViewerIdが違うとShindigでエラーになる。
OAuthRequest.javaの320行目あたり参照。
.

2009年8月2日日曜日

[その他][CentOS] CentOS

http://ssig33.ddo.jp/blog/2009-07-31-1.html

へぇ。
CentOSやばいんだ。。

.

[Apache Shindig][お勉強][OpenSocial] メモ119 gadgets.io.makeRequest 認証認可タイプSIGNEDをやってみる(MHAC-SHA1で署名)

ついでにMHAC-SHA1でのSIGNEDもやってみる。

MHACはパスワードを自分と先方とで共有する方式。

まずconfig/oauth.json。

  1. "http://localhost/opensocial/hello.xml" : {  
  2.   "" : {  
  3.     "consumer_key" : "gadgetConsumer",  
  4.     "consumer_secret""testpass",  
  5.     "key_type" : "MHAC_SYMMETRIC"  
  6.   }  
  7. },  

な感じに修正。

key_typeはMHAC_SYMMETRIC。
別にMHAC_SYMMETRIC使いたい場合は、"UNKO"とかでもOK。(BasicOAuthStoreの場合)

そしてそして、
通信相手側(サービス側というのか?)のサーブレットも修正。
  1. OAuthConsumer consumer =  
  2.     new OAuthConsumer(null"gadgetConsumer""testpass", provider);  

OAuthConsumerをnewするときのパラメータにconsumer_secretで指定したパスワードを
渡してあげる。

で、おしまい。

ガジェットは「メモ118」と一緒。

で実行すると、画面に、

*** OAuthMessage Params:
URL: http://localhost/oauth/SignedFetchVerifyServlet
Param Name-->opensocial_viewer_id Value-->root
Param Name-->oauth_signature Value-->hcnKb9xBH6xlXrcFXNtkhNcccKI=
Param Name-->oauth_body_hash Value-->2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Param Name-->oauth_nonce Value-->1249151173936074000
Param Name-->oauth_version Value-->1.0
Param Name-->oauth_signature_method Value-->HMAC-SHA1
Param Name-->oauth_consumer_key Value-->gadgetConsumer
Param Name-->opensocial_owner_id Value-->root
Param Name-->opensocial_app_id Value-->http://localhost/opensocial/hello.xml
Param Name-->opensocial_app_url Value-->http://localhost/opensocial/hello.xml
Param Name-->oauth_timestamp Value-->1249151173
VALIDATING SIGNATURE
REQUEST STATUS::OK


と表示される。oauth_signature_method ValueもHMAC-SHA1になってる。


おしまい。
.

[Apache Shindig][お勉強][OpenSocial] メモ118 gadgets.io.makeRequest 認証認可タイプSIGNEDをやってみる(RSA-SHA1で署名)

makeRequestでsignatureをリクエストにつけて通信することができるとのこと。
これもOAuthの一種っぽい。

ということでMy Shindigでもやってみる。
参考にしたサイトはhttp://wiki.opensocial.org/index.php?title=Validating_Signed_Requests

Shindigでは、RSA-SHA1かHMAC-SHA1が使えるらしい。

まず、shindigでoauthを使えるようにセットアップする。


config/oauth.json

に設定できる。

oauth.jsonの中身は、デフォルトでは
  1. {  
  2.   "http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml" : {  
  3.     "" : {  
  4.       "consumer_key" : "gadgetConsumer",  
  5.       "consumer_secret" : "gadgetSecret",  
  6.       "key_type" : "HMAC_SYMMETRIC"  
  7.     }  
  8.   },  
  9.   "http://localhost:8080/gadgets/files/samplecontainer/examples/shindigoauth.xml" : {  
  10.     "shindig" : {  
  11.       "consumer_key" : "http://localhost:8080/gadgets/files/samplecontainer/examples/shindigoauth.xml",  
  12.       "consumer_secret" : "secret",  
  13.       "key_type" : "HMAC_SYMMETRIC"  
  14.     }  
  15.   }  
  16. }  

なんてなふうになっているんで、自分のガジェット用定義にする。

で、下記自分用。
  1. {  
  2.   "http://localhost/opensocial/oauth.xml" : {  
  3.     "" : {  
  4.       "consumer_key" : "gadgetConsumer",  
  5.       "consumer_secret" : "gadgetSecret",  
  6.       "key_type" : "RSA_PRIVATE"  
  7.     }  
  8.   }  
  9. }  

最初のURLの"http://localhost:8080/opensocial/oauth.xml"は、
ガジェットのURL。shindigはmakeRequestをSIGNEDで受け取ると、
現在実行中のガジェットのURLをキーに、oauth.jsonの中身を探しにいく。

consumer_keyというのは、どこのコンテナから送られてきたリクエストかを指し示す。
consumer_secretというのは、key_typeにHMAC_SYMMETRICを指定した場合の、先方と共有すべき
パスワード、みたいなものらしい。
RSA_PRIVATEの場合、consumer_secretには、BasicOAuthStore.java(デフォルト)を使うのであれば、opensslで作成した証明書の秘密鍵を指定する。


次は、証明書と秘密鍵の作成。
特に設定しないで起動すると、ログに

Couldn't load OAuth signing key. To create a key, run:
openssl req -newkey rsa:1024 -days 365 -nodes -x509 -keyout testkey.pem \
-out testkey.pem -subj '/CN=mytestkey'
openssl pkcs8 -in testkey.pem -out oauthkey.pem -topk8 -nocrypt -outform PEM

Then edit gadgets.properties and add these lines:
shindig.signing.key-file=
shindig.signing.key-name=mykey


などと出力されているんで、そのとおりにopnessl、設定を実行。

$ openssl req -newkey rsa:1024 -days 365 -nodes -x509 -keyout testkey.pem -out testkey.pem -subj '/CN=mytestkey'
$ openssl pkcs8 -in testkey.pem -out oauthkey.pem -topk8 -nocrypt -outform PEM

で、できあがったファイルをWEB-INFの直下に配置。(getResourceで見える場所ならどこでも良い)

$ cp ./oauthkey.pem /tmp/

で、shindig.propertiesを修正。

shindig.signing.key-file=/tmp/oauthkey.pem
shindig.signing.key-name=mytestkey

と。

さらに、oauthkey.pemをoauth.jsonのconsumer_secretにセットする。
  1. "http://localhost/opensocial/hello.xml" : {  
  2.   "" : {  
  3.     "consumer_key" : "gadgetConsumer",  
  4.     "consumer_secret""-----BEGIN PRIVATE KEY-----\nMIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMMTit67BWHr6lY/\nsIGrNljDff5ZG6M5RCSDvIwHKwmhMFIRE1rhfdzmxst1wpih6X4D/r9W6rMVqMEz\nD8UVz+D7guS6VAJLzOVMi08bo3aOvUuTbnqt6vsVTO41wwPkoHzBWkQsIk5BLBia\neDr/nTR0Hih8cHCDo8KOjyl6lUJBAgMBAAECgYAx/Fr0MaXybnoQeadnwpBddFJf\nj0O2smDUnnD8zIVppUT1cmysN+WBahz8W4NuiuaCpNFtA/+FvgIM52GeFbW7NInS\nkCKQ/d0IxFII9qiE/VHGiSIx2tM978LtEZ90oUDcBSfOfkmuAiZmNNa7MPvxzXBH\n6ykLtK6I0Jdsc7vutQJBAPX6waYp8oyjR/ju6dN/BpYknzeTcH4xV6sX1gtAD1SR\noFpui5VgkPrTAHsHNHNlEakH+olzOyW/kEmteg4WiUMCQQDLBe7CrkZQt1UjhIij\nazE2TzpNHkxocsFa27vp3fnfSo3U+RxsX+Veyz09SoSEVfj40Zbaz9u35BUDV5Hk\nlbwrAkA870iHjD6svko3DaBZJ0+PZDUZBGpKqJiKJtZ8ZPsnPQgXPulPMOPZbung\nkFFbAL+WOwbChAwz9recuN/Sm5yXAkAr4LhdcvTXdQf9iSNOzlfweOcMy8OPv11y\nmZLfVI4waBiHMt+lvIQCHMK7gGNrhnksrX+BAvNlpvGzqzVoxcPJAkA4m5u5skPY\nmbpIPAPda/lr8XN88U5QROr/LdWeu46WO/402U86R+cVRwM/m7WVHAC8MCxzQ+8U\nDOWOrYDKefew\n-----END PRIVATE KEY-----",  
  5.     "key_type" : "RSA_PRIVATE"  
  6.   }  
  7. },  

な感じ。(BasicOAuthStoreを使用の場合。デフォルト)
BasicOAuthStoreは実運用には耐えられるものではないとshindig-devのメーリングリストで
見つけた。実運用する際には別途実装せよ、とのこと。

でコンパイル。で、起動。


今度は通信先のサーブレットを実装。
http://wiki.opensocial.org/index.php?title=Validating_Signed_Requests
にあるものそのままだけど、一応コピペ。
そのままじゃ動かないので、一部現状のOAuthライブラリに合わせて修正。
さらに環境に合わせて修正。
  1. package net.oauth.example.provider.servlets;  
  2.   
  3.  import net.oauth.OAuth;  
  4.  import net.oauth.OAuthAccessor;  
  5.  import net.oauth.OAuthConsumer;  
  6.  import net.oauth.OAuthMessage;  
  7.  /* ここから修正 */  
  8.  import net.oauth.OAuthValidator;  
  9.  import net.oauth.SimpleOAuthValidator;  
  10.  /* ここまで修正 */  
  11.  import net.oauth.OAuthProblemException;  
  12.  import net.oauth.OAuthServiceProvider;  
  13.  import net.oauth.server.OAuthServlet;  
  14.  import net.oauth.signature.RSA_SHA1;  
  15.   
  16.  import java.util.ArrayList;  
  17.  import java.io.IOException;  
  18.  import java.util.Map;  
  19.  import java.io.PrintWriter;  
  20.  import java.util.List;  
  21.   
  22.  import javax.servlet.ServletException;  
  23.  import javax.servlet.http.HttpServlet;  
  24.  import javax.servlet.http.HttpServletRequest;  
  25.  import javax.servlet.http.HttpServletResponse;  
  26.   
  27.  public class SignedFetchVerifyServlet extends HttpServlet {  
  28.   
  29.    private final static String CERTIFICATE =  
  30.        "-----BEGIN CERTIFICATE-----\n"  
  31.            + "MIIDHDCCAoWgAwIBAgIJAMbTCksqLiWeMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\n"  
  32.            + "BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIG\n"  
  33.            + "A1UEChMLR29vZ2xlIEluYy4xDjAMBgNVBAsTBU9ya3V0MQ4wDAYDVQQDEwVscnlh\n"  
  34.            + "bjAeFw0wODAxMDgxOTE1MjdaFw0wOTAxMDcxOTE1MjdaMGgxCzAJBgNVBAYTAlVT\n"  
  35.            + "MQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChML\n"  
  36.            + "R29vZ2xlIEluYy4xDjAMBgNVBAsTBU9ya3V0MQ4wDAYDVQQDEwVscnlhbjCBnzAN\n"  
  37.            + "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAseBXZ4NDhm24nX3sJRiZJhvy9eDZX12G\n"  
  38.            + "j4HWAMmhAcnm2iBgYpAigwhVHtOs+ZIUIdzQHvHeNd0ydc1Jg8e+C+Mlzo38OvaG\n"  
  39.            + "D3qwvzJ0LNn7L80c0XVrvEALdD9zrO+0XSZpTK9PJrl2W59lZlJFUk3pV+jFR8NY\n"  
  40.            + "eB/fto7AVtECAwEAAaOBzTCByjAdBgNVHQ4EFgQUv7TZGZaI+FifzjpTVjtPHSvb\n"  
  41.            + "XqUwgZoGA1UdIwSBkjCBj4AUv7TZGZaI+FifzjpTVjtPHSvbXqWhbKRqMGgxCzAJ\n"  
  42.            + "BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEU\n"  
  43.            + "MBIGA1UEChMLR29vZ2xlIEluYy4xDjAMBgNVBAsTBU9ya3V0MQ4wDAYDVQQDEwVs\n"  
  44.            + "cnlhboIJAMbTCksqLiWeMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA\n"  
  45.            + "CETnhlEnCJVDXoEtSSwUBLP/147sqiu9a4TNqchTHJObwTwDPUMaU6XIs2OTMmFu\n"  
  46.            + "GeIYpkHXzTa9Q6IKlc7Bt2xkSeY3siRWCxvZekMxPvv7YTcnaVlZzHrVfAzqNsTG\n"  
  47.            + "P3J//C0j+8JWg6G+zuo5k7pNRKDY76GxxHPYamdLfwk=\n"  
  48.            + "-----END CERTIFICATE-----";  
  49.   
  50.    @Override  
  51.    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  52.        throws ServletException, IOException {  
  53.      verifyFetch(req, resp);  
  54.    }  
  55.   
  56.   
  57.    @Override  
  58.    protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
  59.        throws ServletException, IOException {  
  60.      verifyFetch(req, resp);  
  61.    }  
  62.   
  63.   
  64.    private void verifyFetch(HttpServletRequest request, HttpServletResponse resp)  
  65.        throws IOException, ServletException {  
  66.      resp.setContentType("text/html; charset=UTF-8");  
  67.      PrintWriter out = resp.getWriter();  
  68.   
  69.      try {  
  70.        OAuthServiceProvider provider =  
  71.            new OAuthServiceProvider(nullnullnull);  
  72.        /* ここから修正(oauth.jsonに書いたconsumerKeyをセット) */  
  73.        OAuthConsumer consumer =   
  74.            new OAuthConsumer(null"gadgetConsumer"null, provider);  
  75.        /* OAuthConsumer consumer =  
  76.            new OAuthConsumer(null, "orkut.com", null, provider); 
  77.        */  
  78.        /* ここまで修正 */  
  79.        consumer.setProperty(RSA_SHA1.X509_CERTIFICATE, CERTIFICATE);  
  80.   
  81.        String method = request.getMethod();  
  82.        String requestUrl = getRequestUrl(request);  
  83.        List<OAuth.Parameter> requestParameters = getRequestParameters(request);  
  84.   
  85.        /* ここから修正 */  
  86.        OAuthMessage message =   
  87.            new OAuthMessage(method, requestUrl + "/SignedFetchVerifyServlet", requestParameters);  
  88.        /* 
  89.        OAuthMessage message = 
  90.            new OAuthMessage(method, requestUrl, requestParameters); 
  91.        */  
  92.        /* ここまで修正 */  
  93.        OAuthAccessor accessor = new OAuthAccessor(consumer);  
  94.        out.print("*** OAuthMessage Params:");  
  95.        out.print("  
  96. URL: " + OAuthServlet.htmlEncode(message.URL));  
  97.        for (java.util.Map.Entry param : message.getParameters()) {  
  98.          String key = param.getKey().toString();  
  99.          String value = param.getValue().toString();  
  100.          out.print("  
  101. ");  
  102.          out.print("Param Name-->" + OAuthServlet.htmlEncode(key));  
  103.          out.print(" ");  
  104.          out.print("Value-->" + OAuthServlet.htmlEncode(value));  
  105.        }  
  106.        out.print("  
  107. ");  
  108.        out.print(" VALIDATING SIGNATURE ");  
  109.        out.print("  
  110. ");  
  111.        /* ここから修正 */  
  112.        OAuthValidator validator = new SimpleOAuthValidator();  
  113.        message.validateMessage(accessor, validator);  
  114.        /* message.validateSignature(accessor); */  
  115.        /* ここまで修正 */  
  116.        out.print("REQUEST STATUS::OK");  
  117.        out.print("  
  118. ");  
  119.      } catch (OAuthProblemException ope) {  
  120.        out.print("  
  121. ");  
  122.        out.print("OAuthProblemException-->"  
  123.            + OAuthServlet.htmlEncode(ope.getProblem()));  
  124.       } catch (Exception e) {  
  125.          out.println(e);  
  126.          System.out.println(e);  
  127.        throw new ServletException(e);  
  128.      } finally {  
  129.        out.flush();  
  130.      }  
  131.    }  
  132.   
  133.    /** 
  134.      * Constructs and returns the full URL associated with the passed request 
  135.      * object. 
  136.      * 
  137.      * @param  request Servlet request object with methods for retrieving the 
  138.      *         various components of the request URL 
  139.      */  
  140.    public static String getRequestUrl(HttpServletRequest request) {  
  141.      StringBuilder requestUrl = new StringBuilder();  
  142.      String scheme = request.getScheme();  
  143.      int port = request.getLocalPort();  
  144.   
  145.      requestUrl.append(scheme);  
  146.      requestUrl.append("://");  
  147.      requestUrl.append(request.getServerName());  
  148.   
  149.      if ((scheme.equals("http") && port != 80)  
  150.              || (scheme.equals("https") && port != 443)) {  
  151.        requestUrl.append(":");  
  152.        requestUrl.append(port);  
  153.      }  
  154.   
  155.      requestUrl.append(request.getContextPath());  
  156.      requestUrl.append(request.getServletPath());  
  157.   
  158.      return requestUrl.toString();  
  159.    }  
  160.   
  161.    /** 
  162.     * Constructs and returns a List of OAuth.Parameter objects, one per 
  163.     * parameter in the passed request. 
  164.     * 
  165.     * @param  request Servlet request object with methods for retrieving the 
  166.     *         full set of parameters passed with the request 
  167.     */  
  168.    public static List<OAuth.Parameter> getRequestParameters(  
  169.        HttpServletRequest request) {  
  170.   
  171.      List<OAuth.Parameter> parameters = new ArrayList<OAuth.Parameter>();  
  172.   
  173.      for (Object e : request.getParameterMap().entrySet()) {  
  174.        Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) e;  
  175.   
  176.        for (String value : entry.getValue()) {  
  177.          parameters.add(new OAuth.Parameter(entry.getKey(), value));  
  178.        }  
  179.      }  
  180.   
  181.      return parameters;  
  182.    }  

で、CERTIFICATEの値をさっきつくったtestkey.pemの
BEGIN CERTIRICATEの方、証明書をコピペ。

で、コンパイル。OAuthライブラリは、
http://code.google.com/p/oauth/
にある。

クラスパス通してコンパイル。


次にSINGEDでリクエストするガジェットを用意。
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.  <Module>  
  3.   <ModulePrefs title="oAuth Java Example">  
  4.     <Require feature="opensocial-0.8"></Require>  
  5.     <Require feature="dynamic-height"></Require>  
  6.   </ModulePrefs>  
  7.   <Content type="html">  
  8.    <![CDATA[ 
  9.     <script type="text/javascript"> 
  10.       var servletUrl="http://localhost/oauth/SignedFetchVerifyServlet"; 
  11.  
  12.       function response(data) { 
  13.         document.getElementById('dom_handle').innerHTML=data.text; 
  14.       }; 
  15.  
  16.       function request() { 
  17.         var params={}; 
  18.         params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT; 
  19.         params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED; 
  20.         gadgets.io.makeRequest(servletUrl,response,params); 
  21.       }; 
  22.  
  23.       gadgets.util.registerOnLoadHandler(request); 
  24.     </script> 
  25.  
  26.     <div id="dom_handle"></div> 
  27.    ]]>  
  28.    </Content>  
  29.  </Module>  

な感じ。

実行させると、、、

*** OAuthMessage Params:
URL: http://localhost/oauth/SignedFetchVerifyServlet
Param Name-->opensocial_viewer_id Value-->root
Param Name-->oauth_signature Value-->uR7NP8VHHIvUTVl6wQI6iDUtp25DSrg1zrdfzLByvLR1/4xE2aT3+J+l9aGDBQGO8jFky9qC6CEQE1UFruif4cSDXY7PhQZZnCcaNxPLvPMmknc2lNafYt1h0xlTCZ1YupgwCXegCYTCrEcONTD2X+xPs9amKFIcRTpsHCojNb4=
Param Name-->oauth_body_hash Value-->2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Param Name-->oauth_nonce Value-->1249149514626651000
Param Name-->oauth_version Value-->1.0
Param Name-->oauth_signature_method Value-->RSA-SHA1
Param Name-->oauth_consumer_key Value-->gadgetConsumer
Param Name-->opensocial_owner_id Value-->root
Param Name-->opensocial_app_id Value-->http://localhost/opensocial/hello.xml
Param Name-->opensocial_app_url Value-->http://localhost/opensocial/hello.xml
Param Name-->oauth_timestamp Value-->1249149514
VALIDATING SIGNATURE
REQUEST STATUS::OK


なんてなふうに表示される。

完璧。これで、
RSA-SHA1での署名付きリクエスト、
さらにはRSA-SHA1の署名VERIFYまでできた。


--
というか、config/oauth.jsonとshindig.propertiesの両方に秘密鍵指定しないと
動かないのは、なんか変。何か間違えたかも。
.