日向夏特殊応援部隊

俺様向けメモ

Net::OpenID::Consumerでsregを試す

ふと思い立ってOpenIDが使えるちょっとしたサービスを作ってみようかなと思っています。
で、その中でsreg*1を使いたかったのでNet::OpenID::Consumerのopenid2 branchで出来るかどうか調べてみました。

その前にsregについて具体的に説明

The request parameters detailed here SHOULD be sent with OpenID Authentication checkid_immediate or checkid_setup requests. This extension works with both versions 1.1 (Recordon, D. and B. Fitzpatrick, “OpenID Authentication 1.1,” .) [OpenIDAuthentication1.1] and 2.0 (Recordon, D., Hoyt, J., Hardt, D., and B. Fitzpatrick, “OpenID Authentication 2.0 - Draft 10,” 2006.) [OpenIDAuthentication2.0] of the OpenID Authentication protocol.

まぁ簡単に要約するとですね。

  • checkid_immediateまたはcheckid_setupのリクエストと一緒に送ります
  • OpenID Authentication 1.1, 2.0のどちらでも動きますよ

って事ですね。

で、送るパラメータは、

name detail
openid.ns.sreg http://openid.net/extensions/sreg/1.1
openid.sreg.required カンマ区切りで欲しいプロフィールの名前

とかですね。openid.sreg.optional, openid.sreg.policy_urlもありますが、今回は簡単の為考慮しません。カンマ区切りの値は4. Response Formatに列挙してある値でopenid.sreg.をprefixにしてある値で、このprefixの値は省略することになります。つまり、

openid.sreg.required=nickname,email

とかとか、そういう事になりますね。
そうするとOpenID Providerがsregに対応してて、ユーザーがそのprofileを公開する事に同意した場合は、これらの値がレスポンスと一緒に返って来ます。

つまるところ会員登録とかでの入力補助、補完と言う場面で使うような機能ですね。
説明おしまい。

Net::OpenID::Consumerで試す

まずはコードから。

#!/usr/bin/perl

use strict;
use warnings;

use Cache::File;
use LWP::UserAgent;
use Net::OpenID::Consumer;

### ここは固定になってるけど実際はユーザーのclaimed_id
my $claimed_id = "zigorou.myopenid.com";
my $csr = Net::OpenID::Consumer->new(
    ua => LWP::UserAgent->new,
    cache => Cache::File->new(
        cache_root => '/tmp/openid',
        default_expires => '6000 sec'
    ),
    consumer_secret => 'zigorou',
    args => {},
    required_root => 'http://localhost:3000/',
    debug => 1,
);

if (my $cident = $csr->claimed_identity($claimed_id)) {
    ### ここがポイント
    $cident->set_extension_args("http://openid.net/extensions/sreg/1.1", {
        required => join(",", qw/email nickname/)
    });

    my $check_url = $cident->check_url(
        return_to => "http://localhost:3000/login/handler",
        trust_root => "http://localhost:3000/",
        delayed_return => "checkid_setup",
    );

    ### 実際にはUserAgentに対してこのcheck_urlにリダイレクトさせる
    print "[check_url]\n";
    print $check_url;
}

適宜コメント振りました。

ポイントはNet::OpenID::ClaimedIdentifierオブジェクトのset_extension_argsに対して、ソースのような値を入れて行くのがポイントです。

こうする事によってcheck_url、即ちcheckid_setupの時のリクエストURLのパラメータに先ほど説明したようなopenid.ns.sregとか、openid.sreg.requiredがセットされます。実行結果を見てみると、

http://www.myopenid.com/server?
openid.ns=http://specs.openid.net/auth/2.0&
openid.return_to=http://localhost:3000/login/handler%3Foic.time%3D1206197561-a06a907ab7899fbd2e83&openid.claimed_id=http://zigorou.myopenid.com/&
openid.identity=http://zigorou.myopenid.com/&
openid.mode=checkid_setup&
openid.realm=http://localhost:3000/&
openid.assoc_handle=%7BHMAC-SHA1%7D%7B47e51527%7D%7BwyS0XA%3D%3D%7D&
openid.ns.e1=http://openid.net/extensions/sreg/1.1&
openid.e1.required=email,nickname

となりsregではなくs1みたいになってますね。
ちなみに実行結果は見易さの為に適宜改行しています。

これはNet::OpenID::Consumer側でのcheck_urlメソッドの実装にて、168行目付近から、

# Finally we add in the extension arguments, if any
my %ext_url_args = ();
my $ext_idx = 1;
foreach my $ext_uri (keys %{$self->{extension_args}}) {
    my $ext_alias;

    if ($self->protocol_version >= 2) {
        $ext_alias = 'e'.($ext_idx++);
        $ext_url_args{'openid.ns.'.$ext_alias} = $ext_uri;
    }
    else {
        # For OpenID 1.1 only the "SREG" extension is allowed,
        # and it must use the "openid.sreg." prefix.
        next unless $ext_uri eq "http://openid.net/extensions/sreg/1.1";
        $ext_alias = "sreg";
    }

    foreach my $k (keys %{$self->{extension_args}{$ext_uri}}) {
        $ext_url_args{'openid.'.$ext_alias.'.'.$k} = $self->{extension_args}{$ext_uri}{$k};
    }
}

となってますが、OpenID Authentication 2.0プロトコルの場合は、aliasを使ってprefixを指定出来るんですね。ちょうどxmlnsみたいですね。

もちろんきちんと何の拡張なのかnamespaceを表すURIをaliasに対して明記する必要がありますが。

まとめ

  • check_url()の前にset_extension_argsでsregに必要な値を突っ込んでおく

でした。

*1:OpenID Simple Registration Extension 1.1のこと