如何从头开始实现OpenID客户端?

时间:2010-09-29 13:50:48

标签: openid

我需要为新平台编写一个OpenID客户端(服务器端javascript的一些有趣的味道),我正在尝试理解身份验证序列。我一直在阅读Ruby实现并编写测试生成的请求/响应的类型。

初始请求在表格中:

this.getBeginUrl = function(options){
    if(!options) throw("getBeginUrl requires an options hash of the form: {return_to_path:'/path/to/return?something', base:'http://server.name'}")
    if(!options.return_to_path) throw("must supply return_to_path");
    if(!options.base) throw ("must supply base url"); 
    var params = {
        'assoc_handle':getAssocHandle(),
        'ax.mode':'fetch_request',
        'claimed_id':'http://specs.openid.net/auth/2.0/identifier_select',
        'identity':'http://specs.openid.net/auth/2.0/identifier_select',
        'mode':'checkid_setup',
        'ns':'http://specs.openid.net/auth/2.0',
        'ns.ax':'http://openid.net/srv/ax/1.0',
        'ns.sreg':'http://openid.net/extensions/sreg/1.1',
        'realm':options.base,
        'return_to':options.base + options.return_to_path + '&open_id_complete=1' // Assuming the return-to url has a ? in it
    }
    if(options.required) params['sreg.required'] = options.required;
    var result = [];
    for(var e in params) result.push([escape('openid.'+e)] +"=" +escape(params[e]));
    return openid_url + '?' + result.join('&'); // Assuming the openid url didn't have a ? in it already 
}

所以我的问题是关于如何创建这个assoc_handle字段以及如何验证openid服务器返回的内容。关于nonces的事情。

发送此请求时的响应格式为:

'openid.op_endpoint':'https://login.launchpad.net/+openid',           
    'openid.signed':'assoc_handle,claimed_id,identity,invalidate_handle,mode,ns,ns.sreg,op_endpoint,response_nonce,return_to,signed,sreg.nickname',
   'openid.sig':'HMeqwtQ8vG4aNOvRFVSnuOfWv30=',
   'openid.response_nonce':'2010-09-29T10:50:31Z3nPoQ3',
   'open_id_complete':'1',
   'openid.claimed_id':'https://login.launchpad.net/+id/ref466F',
   'foo':'bar',
   'openid.assoc_handle':'{HMAC-SHA1}{4ca319f7}{+KiTxQ==}',
   'openid.sreg.nickname':'michaelforrest',
   'openid.ns':'http://specs.openid.net/auth/2.0',
   'openid.identity':'https://login.launchpad.net/+id/ref466F',
   'openid.ns.sreg':'http://openid.net/extensions/sreg/1.1',
   'openid.mode':'id_res',
   'openid.invalidate_handle':'foo',
   'openid.return_to':'http://localhost:9000/ep/openid/?foo=bar&open_id_complete=1',

所以我想我需要了解如何验证这个响应来自原始请求,然后保存昵称字段的内容(这是我真正感兴趣的是验证)。

1 个答案:

答案 0 :(得分:5)

首先,阅读specification。其次,阅读specification。再多做一次,这样你就会对它是如何工作有一个模糊的想法,然后尝试实现它,然后再仔细阅读规范,这样你就可以确定你没有忘记任何事情。

我不是这么说的,因为我只是想给你发一本手册,但是如果你错过了一个小细节,你可能会在你的图书馆中引入一个关键漏洞。

无论如何,assoc_handle由提供者设置,而不是由客户端设置。规范的第8节描述了如何获得句柄。或者,你根本不关心assoc句柄,并使用无状态模式(因为它更简单)。

在无状态模式下,为了验证响应,您只需发回请求,其中包含openid.signed字段中包含的参数,加上openid.sig字段,openid.mode设置为{ {1}}。

根据您的要求,这里有一些内容:它们是独一无二的,以utc的完整时间戳开始,采用iso 8601格式。

顺便说一句,您对验证check_authentication字段不感兴趣。您想验证sreg.nickname。即使您提出要求,claimed_id甚至不必出现在回复中。

但是,阅读规范非常重要。仅仅让它发挥作用是不够的。