《Spring Security3》第八章第三部分翻译(属性交换)
属性交换(Attribute Exchange)
OpenID另外一个有趣的功能就是如果使用OpenID的站点需要,OpenID provider提供(基于用户的许可)典型的用户注册数据,如名字、e-mail、生日。这个功能叫做属性交换(Attribute Exchange,AX)。下图展现了在OpenID请求中要求属性交换是如何添加进去的:
AX属性值(如果provider提供的话)将会与其它的OpenID响应一起返回,并作为一个o.s.s.openid.OpenIDAttribute列表(list)插入到OpenIDAuthenticationToken中。
AX属性能够被OpenID提供者随意定义,但是均为唯一定义的URI。有人在努力标准化可用的和常见的属性模式。以下的属性是可用的(完整的列表在http://www.axschema.org/types/):
属性名 |
描述 |
http://axschema.org/contact/email |
用户的e-mail地址 |
http://axschema.org/namePerson |
用户的全名 |
axschema.org站点列出了超过30个不同的属性,带有唯一的URI和描述。在一些特定情况下,你可能需要引用schema.openid.net而不是axschema.org(稍后我们将会解释为什么)。
让我们看一下在Spring Security中如何配置属性交换。
在Spring Security OpenID中启用AX
一旦你知道了要请求的属性,在Spring Security OpenID中启用AX实际上很容易。我们可以配置AX以请求e-mail:
<openid-login authentication-failure-handler-ref="openIdAuthFailureHandler"> <attribute-exchange> <openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true"/> </attribute-exchange> </openid-login>
对这个例子,我们建议你使用myOpenID标识登录。你将会看到,当你重定向到提供者时,提供者会通知你JBCP Pets站点请求额外的信息。在以下的截屏中,我们在请求中实际上包含了更多的AX属性:
请求的属性一旦被提供者返回,那在OpenIDAuthenticationToken就可用了(在成功认证的请求中),是以键值对的方式存在而名字(即键)就是在<openid-attribute>中声明的。这就取决于我们的站点来检查这些数据并对其进行处理。一般来说这些数据能够要在填充用户简介或用户注册表单上。
为了进行探索研究,可以增强我们写的OpenIDAuthenticationFailureHandler来打印检索出的属性到控制台上:
request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL", ((UsernameNotFoundException)exception).getExtraInformation()); OpenIDAuthenticationToken openIdAuth = (OpenIDAuthenticationToken)exception.getAuthentication(); for(OpenIDAttribute attr : openIdAuth.getAttributes()) { System.out.printf("AX Attribute: %s, Type: %s, Count: %d\n", attr.getName(), attr.getType(), attr.getCount()); for(String value : attr.getValues()) { System.out.printf(" Value: %s\n", value); } } redirectStrategy.sendRedirect(request, response, "/registrationOpenid. do");
在我们的例子中将会得到如下的输出:
AX Attribute: email, Type: http://schema.openid.net/contact/email, Count: 1 Value: peter@mularien.com AX Attribute: birthDate, Type: http://schema.openid.net/birthDate, Count: 1 Value: 1968-04-13 AX Attribute: namePerson, Type: http://schema.openid.net/namePerson, Count: 1 Value: Peter Mularien AX Attribute: nickname, Type: http://schema.openid.net/namePerson/ friendly, Count: 1 Value: pmularien AX Attribute: country, Type: http://schema.openid.net/contact/country/ home, Count: 1 Value: US
我们可以看到AX数据能够很容易从OpenID提供者那里得到,并且支持通过简单API调用访问。在典型的应用场景下,如前面所讨论,AX信息会用在注册时填入用户基本信息或偏好信息,节省了用户重复键入OpenID简介中已包含的信息。
现实世界的AX的支持和限制
但是,在现实中AX的承诺实现的很不足。市面上的OpenID提供者对AX支持的都很差,只有少数支持(myOpenID和Google是最好的)。另外,即使支持标准的提供者在有什么属性对应数据方面也有混乱。比如,要查询用户的e-mail,即使两个支持AX的提供者所请求的属性名都不一样!
提供者 |
支持的AX属性 |
myOpenID |
http://schema.openid.net/contact/email |
|
http://axschema.org/contact/email |
在写作本书的时候,在OpenID相关的邮件列表中还在讨论怎样更好的标准属性并允许OpenID提供者公开他们所支持的属性。
AX的替代方式,叫做简单注册(Simple Registration ,SReg)被openid4java所支持,但是并没有暴露到Spring Security OpenID(由开发人员选择)。这很遗憾,因为SReg实际上很多的提供者支持,超过AX。AX曾经想作为更开放和灵活的替代SReg的方案,但是缺乏支持和标准化使得妨碍了它被提供者所采用。
支持Google OpenID
Google选择一种稍微不同的方式实现OpenID,并没有给用户分配用户友好的OpenID标识符。相反,Google期望提供OpenID的站点使用Google式的提供者URL,并且用户直接向Google提供凭证。为了是这个处理对用户来说更简单,通用的做法是站点提供了“Sign in with Google”按钮,这会触发Google OpenID提供者。我们可以添加这个到登录页:
<form action="j_spring_openid_security_check" method="post"> <input name="openid_identifier" size="50" maxlength="100" type="hidden" value="https://www.google.com/accounts/o8/id"/> <input type="submit" value="Sign in with Google"/> </form>
我们可以看到Google URL不需要暴露给用户。用户会看到这个经典的登录页:
在Google登录过程完成后,用户的OP-Local Identifier会被返回,并且注册/登录能像其它OpenID提供者一样处理。
OpenID安全吗?
OpenID依赖于OpenID提供者的可靠性以及提供者响应的可验证性,为了应用能够信任基于OpenID的用户登录,安全和可靠性至关重要。
幸运的是,OpenID规范的设计者注意到了这些关切并实现了一系列的校验步骤来防止响应伪造、重放攻击以及其它类型的篡改,描述如下:
l 响应伪造(Response forgery)通过联合使用公用的密钥(使用OpenID的站点在初始请求之前创建)和对响应信息本身进行单向hash信息加密来阻止。恶意的用户不能访问共享的密钥和加密算法,伪装响应的任何域数据都会生成不合法的响应。
l 重放攻击(Replay attacks)通过包含当前时间(nonce)或一次使用的随机key来阻止,这应该保存在使用OpenID的站点上所以不能重复使用。这样,即使用户试图重新发送响应URL也会失败,因为接受的站点会确定当前时间(nonce)以前已经被使用过了,这个请求就失效了。
最可能的一种攻击方式可能会导致一个用户交互可能是中间攻击(man-in-the-middle attack)——在这里恶意用户拦截了用户电脑和OpenID提供者的交互。假设的攻击者在一个地方记录用户浏览器和OpenID的会话,并记录下请求初始化的密钥。在这种情况下,需要攻击者有很高的水平和相当完整的OpenID签名规则实现——简言之,在正常情况下这不会发生。
注意的是,尽管openid4java库支持使用JDBC持久化当前时间(nonce)跟踪,但是Spring Security OpenID当前没有作为一个配置属性暴露——所以当前时间只能在内存中跟踪。这意味着一个重复攻击可能在服务器重启后或集群环境下发生,在这里内存存储没有在不同服务器的JVM间复制。
小结
在本章中,我们了解了OpenID——一个相对很新的技术用来进行用户认证的凭证管理。OpenID在web中应用广泛,在最近一两年中在可用性和接受程度上发展迅速。现代web中大多数面向公众的站点都应该规划一些OpenID支持功能,JBCP Pets也不例外。
在本章中,我们:
l 学习了OpenID认证机制并探究了它的整体结构和术语;
l 利用JBCP Pets站点,实现了OpenID的登录和自动用户注册功能;
l 通过使用属性交换(Attribute Exchange ,AX),了解了OpenID未来的基本信息管理;
l 检查了OpenID登录响应的安全性。
在本章中,我们涉及到大多数常用基于web的外部认证方法。在下一章中,我们将会介绍一种最常用的基于目录的企业认证方式:LDAP。在我们要转到下一章的时候,请观察外部和内部认证机制的区别以及相似之处。
推荐阅读
-
《Spring Security3》第四章第三部分翻译上(配置安全的密码)
-
《Spring Security3》第四章第三部分翻译下(密码加salt)
-
《Spring Security3》第三章第四部分翻译(修改密码)
-
《Spring Security3》第三章第三部分翻译下(Remember me安全吗?)
-
《Spring Security3》第三章第二部分翻译(退出功能的实现)
-
《Spring Security3》第三章第三部分翻译上(Remember me功能实现)
-
《Spring Security3》第六章第三部分翻译(Session的管理和并发)
-
《Spring Security3》第五章第三部分翻译(保护业务层)
-
《Spring Security3》第三章第一部分翻译
-
《Spring Security3》第二章第三部分翻译(下)附前两章doc文档