l'essentiel est invisible pour les yeux

Saturday, March 22, 2008

[ruby] myOpenID and OpenID Attributes Exchange, myOpenID isn't supported Type URI described in http://axschema.org/

JanRain's myOpenID is popular OpenID provider, supports SSL, SREG, some persona, authentication with Information Card, OpenID Attributes Exchange (but only some attributes), Pavatar and so on. JanRain also offers ruby-openid that implements OpenID 2.0 with Ruby.

myOpenID supports only some attributes that can be exchange with OpenID Attribute Exchange, but you should care about Type URI, because myOpenID doesn't support Type URI described on "http://www.axschema.org/types/". You should specify Type URI with "http://schema.openid.net/" instead.

Sample code that fetch some attributes from myOpenID is as follows. At first, you need to initialize your persona. My persona for work is "Rakuto Furutani".

ConsumerController#start in /path/to/rails_openid/app/controller/consumer_controller.rb


# AX
if params[:use_ax]
# Builds Fetch Request of Attributes Exchange
ax_req = OpenID::AX::FetchRequest.new
requested_attrs = [ ['http://schema.openid.net/namePerson', 'name', true],
['http://schema.openid.net/namePerson/friendly', 'nickname'],
['http://schema.openid.net/contact/email', 'email', true],
['http://schema.openid.net/contact/web/default', 'web_default'],
['http://schema.openid.net/contact/postalCode/home', 'postal_code'],
['http://schema.openid.net/person/gender', 'gender'],
['http://schema.openid.net/birthDate', 'birthDate'],
['http://schema.openid.net/contact/country/home', 'country'],
['http://schema.openid.net/pref/language', 'language']]

requested_attrs.each {|a| ax_req.add(OpenID::AX::AttrInfo.new(a[0], a[1], a[2] || false))}
oidreq.add_extension(ax_req)
oidreq.return_to_args['did_ax'] = 'y'
pp oidreq
end


Customize a view
/path/to/rails_openid/app/views/consumer/index.rhtml

<% if flash[:ax_results]%>
<div class='alert'>
<%= flash[:ax_results] %>
</div>
<% end %>
<div id="verify-form">
<form method="get" accept-charset="UTF-8"
action='<%= url_for :action => 'start' %>'>
Identifier:
<input type="text" class="openid" name="openid_identifier" />
<input type="submit" value="Verify" /><br />
<input type="checkbox" name="immediate" id="immediate" /><label for="immediate">Use immediate mode</label><br/>
<input type="checkbox" name="use_sreg" id="use_sreg" /><label for="use_sreg">Request registration data</label><br/>
<input type="checkbox" name="use_pape" id="use_pape" /><label for="use_pape">Request phishing-resistent auth policy (PAPE)</label><br/>
<input type="checkbox" name="force_post" id="force_post" /><label for="force_post">Force the transaction to use POST by adding 2K of extra data</label><br/>
<input type="checkbox" name="use_ax" id="use_ax" /><label for="use_ax">Request registration data with AX (Attribute Exchange)</label>
</form>
</div>


ConsumerController#complete in /path/to/rails_openid/app/controllers/consumer_controller.rb

if params[:did_ax]
ax_resp = OpenID::AX::FetchResponse.from_success_response(oidresp)
pp ax_resp
end


Screenshot


We can fetch some attribtues from myOpenID, above code's output is as follows:

OpenID::Consumer::CheckIDRequest instance

#<OpenID::Consumer::CheckIDRequest:0x33543fc
@anonymous=false,
@assoc=
#<OpenID::Association:0x3354500
@assoc_type="HMAC-SHA1",
@handle="{HMAC-SHA1}{47dd30ef}{WTRsAg==}",
@issued=Sun Mar 16 14:38:35 +0000 2008,
@lifetime=1209600,
@secret="\005F6\246W\032\220\233]\002V$j\034��j�!1">,
@endpoint=
#<OpenID::OpenIDServiceEndpoint:0x33602b0
@canonical_id=nil,
@claimed_id="http://rakuto.myopenid.com/",
@display_identifier=nil,
@local_id="http://rakuto.myopenid.com/",
@server_url="http://www.myopenid.com/server",
@type_uris=
["http://specs.openid.net/auth/2.0/signon",
"http://openid.net/sreg/1.0",
"http://openid.net/extensions/sreg/1.1",
"http://schemas.openid.net/pape/policies/2007/06/phishing-resistant",
"http://openid.net/srv/ax/1.0"],
@used_yadis=true>,
@message=
#<OpenID::Message:0x3354334
@args=
{["http://openid.net/srv/ax/1.0", "type.gender"]=>
"http://schema.openid.net/person/gender",
["http://openid.net/srv/ax/1.0", "if_available"]=>
"country,web_default,language,birthDate,postal_code,nickname,gender",
["http://openid.net/srv/ax/1.0", "type.language"]=>
"http://schema.openid.net/pref/language",
["http://openid.net/srv/ax/1.0", "type.postal_code"]=>
"http://schema.openid.net/contact/postalCode/home",
["http://openid.net/srv/ax/1.0", "mode"]=>"fetch_request",
["http://openid.net/srv/ax/1.0", "type.birthDate"]=>
"http://schema.openid.net/birthDate",
["http://openid.net/srv/ax/1.0", "type.country"]=>
"http://schema.openid.net/contact/country/home",
["http://openid.net/srv/ax/1.0", "type.nickname"]=>
"http://schema.openid.net/namePerson/friendly",
["http://openid.net/srv/ax/1.0", "type.name"]=>
"http://schema.openid.net/namePerson",
["http://openid.net/srv/ax/1.0", "required"]=>"name,email",
["http://openid.net/srv/ax/1.0", "type.web_default"]=>
"http://schema.openid.net/contact/web/default",
["http://openid.net/srv/ax/1.0", "type.email"]=>
"http://schema.openid.net/contact/email"},
@namespaces=
#<OpenID::NamespaceMap:0x33542d0
@alias_to_namespace=
{"ax"=>"http://openid.net/srv/ax/1.0",
:null_namespace=>"http://specs.openid.net/auth/2.0"},
@namespace_to_alias=
{"http://specs.openid.net/auth/2.0"=>:null_namespace,
"http://openid.net/srv/ax/1.0"=>"ax"}>,
@openid_ns_uri="http://specs.openid.net/auth/2.0">,
@return_to_args={"did_ax"=>"y"}>


OpenID::Consumer::SuccessResponse instance

#<OpenID::Consumer::SuccessResponse:0x32800c0
@endpoint=
#<OpenID::OpenIDServiceEndpoint:0x32bea28
@canonical_id=nil,
@claimed_id="http://rakuto.myopenid.com/",
@display_identifier=nil,
@local_id="http://rakuto.myopenid.com/",
@server_url="http://www.myopenid.com/server",
@type_uris=
["http://specs.openid.net/auth/2.0/signon",
"http://openid.net/sreg/1.0",
"http://openid.net/extensions/sreg/1.1",
"http://schemas.openid.net/pape/policies/2007/06/phishing-resistant",
"http://openid.net/srv/ax/1.0"],
@used_yadis=true>,
@identity_url="http://rakuto.myopenid.com/",
@message=
#<OpenID::Message:0x3296f78
@args=
{["http://openid.net/srv/ax/1.0", "type.gender"]=>
"http://schema.openid.net/person/gender",
["http://specs.openid.net/auth/2.0", "sig"]=>
"5aziAIn3yMlbxq8XFaF8hKG4GCk=",
[:bare_namespace, "did_ax"]=>"y",
["http://openid.net/srv/ax/1.0", "type.language"]=>
"http://schema.openid.net/pref/language",
["http://openid.net/srv/ax/1.0", "count.gender"]=>"1",
["http://specs.openid.net/auth/2.0", "mode"]=>"id_res",
["http://openid.net/srv/ax/1.0", "mode"]=>"fetch_response",
["http://openid.net/srv/ax/1.0", "type.postal_code"]=>
"http://schema.openid.net/contact/postalCode/home",
["http://openid.net/srv/ax/1.0", "value.gender.1"]=>"M",
["http://specs.openid.net/auth/2.0", "op_endpoint"]=>
"http://www.myopenid.com/server",
["http://specs.openid.net/auth/2.0", "response_nonce"]=>
"2008-03-22T04:51:54ZT0280h",
["http://openid.net/srv/ax/1.0", "type.birthDate"]=>
"http://schema.openid.net/birthDate",
["http://openid.net/srv/ax/1.0", "value.name.1"]=>"Rakuto Furutani",
["http://openid.net/srv/ax/1.0", "count.postal_code"]=>"0",
["http://openid.net/srv/ax/1.0", "value.nickname.1"]=>"rakuto",
["http://openid.net/srv/ax/1.0", "type.country"]=>
"http://schema.openid.net/contact/country/home",
["http://openid.net/srv/ax/1.0", "count.name"]=>"1",
["http://openid.net/srv/ax/1.0", "count.web_default"]=>"1",
["http://openid.net/srv/ax/1.0", "type.nickname"]=>
"http://schema.openid.net/namePerson/friendly",
["http://specs.openid.net/auth/2.0", "return_to"]=>
"http://localhost:3001/consumer/complete?did_ax=y",
["http://specs.openid.net/auth/2.0", "assoc_handle"]=>
"{HMAC-SHA1}{47dd30ef}{WTRsAg==}",
["http://openid.net/srv/ax/1.0", "count.email"]=>"0",
["http://openid.net/srv/ax/1.0", "type.name"]=>
"http://schema.openid.net/namePerson",
["http://openid.net/srv/ax/1.0", "count.nickname"]=>"1",
["http://openid.net/srv/ax/1.0", "count.country"]=>"1",
["http://specs.openid.net/auth/2.0", "identity"]=>
"http://rakuto.myopenid.com/",
["http://specs.openid.net/auth/2.0", "signed"]=>
"assoc_handle,ax.count.birthDate,ax.count.country,ax.count.email,ax.count.gender,ax.count.language,ax.count.name,ax.count.nickname,ax.count.postal_code,ax.count.web_default,ax.mode,ax.type.birthDate,ax.type.country,ax.type.email,ax.type.gender,ax.type.language,ax.type.name,ax.type.nickname,ax.type.postal_code,ax.type.web_default,ax.value.birthDate.1,ax.value.country.1,ax.value.gender.1,ax.value.language.1,ax.value.name.1,ax.value.nickname.1,ax.value.web_default.1,claimed_id,identity,mode,ns,ns.ax,op_endpoint,response_nonce,return_to,signed",
["http://openid.net/srv/ax/1.0", "count.language"]=>"1",
["http://openid.net/srv/ax/1.0", "value.language.1"]=>"JA",
["http://openid.net/srv/ax/1.0", "value.web_default.1"]=>
"http://raku.to/",
["http://openid.net/srv/ax/1.0", "value.birthDate.1"]=>"1985-03-12",
["http://openid.net/srv/ax/1.0", "type.web_default"]=>
"http://schema.openid.net/contact/web/default",
["http://openid.net/srv/ax/1.0", "type.email"]=>
"http://schema.openid.net/contact/email",
["http://openid.net/srv/ax/1.0", "value.country.1"]=>"JP",
["http://specs.openid.net/auth/2.0", "claimed_id"]=>
"http://rakuto.myopenid.com/",
["http://openid.net/srv/ax/1.0", "count.birthDate"]=>"1"},
@namespaces=
#<OpenID::NamespaceMap:0x329680c
@alias_to_namespace=
{"ax"=>"http://openid.net/srv/ax/1.0",
:null_namespace=>"http://specs.openid.net/auth/2.0"},
@namespace_to_alias=
{"http://specs.openid.net/auth/2.0"=>:null_namespace,
"http://openid.net/srv/ax/1.0"=>"ax"}>,
@openid_ns_uri="http://specs.openid.net/auth/2.0">,
@signed_fields=
[
"openid.assoc_handle",
"openid.ax.count.birthDate",
"openid.ax.count.country",
"openid.ax.count.email",
"openid.ax.count.gender",
"openid.ax.count.language",
"openid.ax.count.name",
"openid.ax.count.nickname",
"openid.ax.count.postal_code",
"openid.ax.count.web_default",
"openid.ax.mode",
"openid.ax.type.birthDate",
"openid.ax.type.country",
"openid.ax.type.email",
"openid.ax.type.gender",
"openid.ax.type.language",
"openid.ax.type.name",
"openid.ax.type.nickname",
"openid.ax.type.postal_code",
"openid.ax.type.web_default",
"openid.ax.value.birthDate.1",
"openid.ax.value.country.1",
"openid.ax.value.gender.1",
"openid.ax.value.language.1",
"openid.ax.value.name.1",
"openid.ax.value.nickname.1",
"openid.ax.value.web_default.1",
"openid.claimed_id",
"openid.identity",
"openid.mode",
"openid.ns",
"openid.ns.ax",
"openid.op_endpoint",
"openid.response_nonce",
"openid.return_to",
"openid.signed"]>


Extracted attributes from response - OpenID::AX::FetchResponse instance

#<OpenID::AX::FetchResponse:0x3254a4c
@data=
{"http://schema.openid.net/namePerson"=>["Rakuto Furutani"],
"http://schema.openid.net/contact/country/home"=>["JP"],
"http://schema.openid.net/contact/web/default"=>["http://raku.to/"],
"http://schema.openid.net/pref/language"=>["JA"],
"http://schema.openid.net/contact/email"=>[],
"http://schema.openid.net/birthDate"=>["1985-03-12"],
"http://schema.openid.net/contact/postalCode/home"=>[],
"http://schema.openid.net/namePerson/friendly"=>["rakuto"],
"http://schema.openid.net/person/gender"=>["M"]},
@mode="fetch_response",
@ns_alias="ax",
@ns_uri="http://openid.net/srv/ax/1.0",
@update_url=nil>

Conclusion about myOpenID
  • Supports only some attributes that can be exchanged with AX.
  • Doesn't support openid.ax.update_url yet.
  • Doesn't support Type URI described in axschema, you should specify Type URI with "http://schema.openid.net/" namespace.