ぼくがかんがえたおーぷんそーしゃる その3

  • JavaScript を(極力)使わずに OpenSocial アプリケーションを作る講座、第三回です
  • 外部サーバ上で security token がどのアプリに対して発行されたものか検証する方法とは
    • Signed Requests を使います
      • コンテナから外部サーバのエンドポイントに対して、Signed Requests を投げさせ、レスポンスに含まれる opensocial_app_url をチェックすることで、どのアプリの st であるか確認します
  • まず、コンテナから Signed Requests を投げさせる
    • gadgets.io.makeRequest() を実行しているガジェットをモニタすると内部でこんなことになっています

POST /gadgets/makeRequest HTTP/1.1
Host: 7f17fe5993881228b01b387a41e93a45edb7b149.app0.mixi-platform.com
X-Mixi-Platform-IO: 1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8


url=http%3A%2F%2Fmxfarm.rekoo.com%2Fembed_swf%2F&httpMethod=POST&headers=Content-Type%3Dapplication%252Fx-www-form-urlencoded&postData=***&authz=signed&st=***&contentType=JSON&numEntries=3&getSummaries=false&signOwner=true&signViewer=true&gadget=http%3A%2F%2Fmxfarm.rekoo.com%2F%3Fv%3D1258954460&container=default&bypassSpecCache=

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8


throw 1; < don't be evil' >{"http://mxfarm.rekoo.com/embed_swf/":{"body":"{\n \"session_name\": \"sessionid\", \n \"return_code\": 0, \n \"uid\": \"11325239\", \n \"server_now\": 1258974369.6, \n \"session_value\": \"***\"\n}","rc":200}}

  • 試してみると、http://app0.mixi-platform.com/gadgets/makeRequest に少なくとも下記のパラメータを POST で渡せばよいことがわかります
    • X-Mixi-Platform-IO: 1
    • httpMethod
      • 外部サーバをたたくときの method
    • url
      • 外部サーバのエンドポイント
    • authz=signed
      • request に署名する
    • st
      • security token
  • 次に、外部サーバ上に Signed Requests を検証するためのエンドポイントを用意する
    • こいつはサンプルコードまんまでいいです
use CGI;
use OAuth::Lite::SignatureMethod::RSA_SHA1;
use OAuth::Lite::Util qw(create_signature_base_string);
use JSON;

my $public_key = <<__END_OF_PUBLIC__;
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDASPndWVBy/VYe99aVM/5PWVdS
D3Vb5uAlK4cAPz091V/1SOeL3YSRuOposPMDjf5TlQuUr/TmNE6cbAUFV0hLFQuB
69KmJN+Bt8JwptFbuFetNKaMVESntg69+VPeuvuqo2+Ob7dcTXnvNxTfdJcwga9f
W5Af9jh82kQTWmZf5QIDAQAB
-----END PUBLIC KEY-----
__END_OF_PUBLIC__

my $verifier = OAuth::Lite::SignatureMethod::RSA_SHA1->new(
    consumer_secret => $public_key,
);

my $cgi = CGI->new;
my $params = $cgi->Vars;

my $oauth_signature = $params->{oauth_signature};
delete $params->{oauth_signature};

my $base_string = create_signature_base_string(
    $cgi->request_method,
    $cgi->url,
    $params,
);

my $result = $verifier->verify($base_string, $oauth_signature);

print $cgi->header, to_json({
    validated => $result ? 1 : 0,
    query => $params,
});
use CGI;
use LWP::UserAgent;
use JSON;

my $q = CGI->new;

my $ua = LWP::UserAgent->new;
my $res = $ua->post(
    'http://app0.mixi-platform.com/gadgets/makeRequest',
    {
        httpMethod => 'GET',
        url        => 'http://twixi.dyndns.org/fetchme.cgi',
        authz      => 'signed',
        st         => $q->param('st'),
    },
    'X-Mixi-Platform-IO' => '1',
);

my $content = from_json($1) if $res->content =~ /({.+)$/;
my $body = from_json($content->{$url}->{body});

print $q->header(-type => 'text/plain', -charset => 'utf-8');

print 'validated: ' . $body->{validated} . "\n";
print 'opensocial_app_url: ' . $body->{query}->{opensocial_app_url} . "\n";
print 'opensocial_viewer_id: ' . $body->{query}->{opensocial_viewer_id} . "\n";
    • これで opensocial_app_url が取れました
      • gadget.xml を置いた URL と等しいか確認しましょう
    • opensocial_viewer_id なども同時に取れるので、プロフィール情報が必要なければ、RESTful API を叩かなくてすみます

  • ここまでぐだぐだと書いてきましたが、手順が煩雑なのと、コンテナの実装に依存する部分があるので、微妙な気持ちになってきました
    • あくまでも Twixi はこういうふうに作ったよ、ということで
  • ではどうするかというと、以下のような流れのほうがすっきりするかも
    • gadget.xml から gadgets.io.makeRequest() で st を外部サイトに送る
    • 外部サイトは、opensocial_app_url を検証し、opensocial_viewer_id と st をセッションデータとして保存、それに紐付くトークンを生成しレスポンスに含めて返す
    • gadget.xml から、返されたトークンをパラメータに含めて外部サイトに iframe 内のみリダイレクト
    • 外部サイトでセッション用 cookie 発行、st を使って RESTful ウマー
  • 次回、JavaScript API 使えないならマイミクの招待とかできないし OpenSocial の意味ぜんぜんないじゃん、と突っ込まれたときに、そこだけ最低限の JS を使ってなんとかする、という話を書きます
  • つづく