|
2012-03-31 10:00:24
《Spring Security 3》 【第九章】 第九章 LDAP目录服务(1) 浏览(10474)|评论(0) 交流分类:Java|笔记分类: Spring Sec……
|
属性名 |
描述 |
示例 |
dc |
域组件(Domain Component)——一般为LDAP等级结构中的最高一级组织 |
dc=jbcppets,dc=com |
c |
国家(Country)——一些LDAP等级结构中将国家作为很高的等级 |
c=US |
o |
组织名(Organization name)——一个LDAP资源分类上的业务组织 |
o=Sun Microsystems |
ou |
组织单元(Organizational unit)——业务组织部门,一般在组织之内 |
ou=Product Development |
cn |
通用名(Common name)——对象的通用名或唯一名或者为对人可读的名字。对人来说一般为人的全名,对于LDAP中的其它资源(电脑等等)一般为主机名。 |
cn=Super Visor cn=Jim Bob |
uid |
用户ID(User ID)——尽管并不是原生作为组织相关使用,但是Spring一般会查找uid进行用户认证和搜索 |
uid=svisor |
userPassword |
用户密码(User password)——存储人对象相关联的密码。一般会经过SHA或类似的单向哈希算法。 |
userPassword=plaintext userPassword={SHA}cryptval |
要记住的是有上百个标准的LDAP属性——上面只是其中的一小部分,当你与一个完整LDAP集成的话会看到它们。但是表中的这些属性是目录树中组织相关的属性,当你配置Spring Security与LDAP交互的时候可能会用来形成各种查询表达式或匹配符。
运行一个嵌入式的LDAP服务
作为测试,Spring Security允许使用嵌入式的LDAP服务器。就像我们使用嵌入式数据库那样,这使得应用可以启动一个基于内存的LDAP服务器并插入初始化数据。当然,这样的一个配置只能用于测试的目的,但是这能够节省我们很多配置单独LDAP服务器的时间。
嵌入式的LDAP服务器功能是通过使用Apache Directory Server (DS) 1.5来支持的,它是一个基于Java、开源且完全符合规范的LDAP服务器。实际上,你也可以使用Apache DS作为独立的服务器,它很相对很容易配置并易于获取和安装。本章实例代码中的Dependencies目录下包含了嵌入式LDAP服务器所需要的JAR包——如果你要自己使用它的话,你要么使用Maven要么自己到以下地址http://directory.apache.org/ 下载Apache DS。
如同嵌入式的HSQL数据库允许在启动时加载SQL脚本,嵌入式的LDAP服务器提供了启动时从LDAP数据交换格式(LDAP Data Interchange Format ,LDIF)文件中插入目录的方法。LDIF是一种简洁的且对人和机器都很易读的数据定义格式,它提供了LDAP对象和支持数据的灵活定义。在本章的源码中提供了几个实例性的LDIF文件。
配置基本的LDAP集成
现在让我们让JBCP Pets支持基于LDAP的认证。幸运的是,通过使用嵌入式的LDAP服务器和实例LDIF文件,这是一个相对容易的练习。在这个练习中,我们使用为本书创建的LDIF文件,这个文件用来进行表述LDAP和Spring Security的常用配置场景。我们提供了几个其它的LDIF文件,其中一些来自Apache DS 1.5,还有一个来自SpringSecurity的单元测试,你可能会愿意选择它们进行体验。
配置LDAP服务器引用
第一步是在dogstore-security.xml中声明嵌入式LDAP服务器的引用。LDAP服务器的声明在<http>元素之外,与<authentication-manager>相同的等级:
<ldap-server ldif="classpath:JBCPPets.ldif" id="ldapLocal" root="dc=jb cppets,dc=com"/>
我们从classpath中加载JBCPPets.ldif,并用其为LDAP服务器插入数据。这意味着(如同嵌入式HSQL数据库启动那样)我们应该在WEB-INF/classes放置JBCPPets.ldif文件。root属性用特定的DN声明了LDAP目录的根。这应该与我们使用的LDIF文件逻辑根DN相对应。
【注意,对于嵌入式的LDAP服务器,root是必须的,尽管XML模式并没有这样声明。如果它没有指明或指明错误,你会在Apache DS server启动的时候看待几个奇怪的错误。】
当我们在Spring Security配置文件中声明LDAP用户服务和其它配置元素时,会重用这里定义的bean ID。对于嵌入式的LDAP模式来说,<ldap-server>声明的其它属性都是可选的。
启用LDAP AuthenticationProvider
接下来,我们要配置另一个AuthenticationProvider,它用来用LDAP来检查用户凭证。简单得添加另一个AuthenticationProvider即可,如下:
<authentication-manager alias="authenticationManager"> <!-- Other authentication providers are here --> <ldap-authentication-provider server-ref="ldapLocal" user-search-filter="(uid={0})" group-search-base="ou=Groups" /> </authentication-manager>
解决嵌入式LDAP的问题
很可能你在使用嵌入式LDAP时,调试问题很困难。Apache DS的出错信息并不友好,这在SpringSecurity嵌入模式下更严重。如果你不能让这个简单的例子正常运行,请仔细检查以下的地方:
确保Apache DS依赖的所有JAR都在web应用的classpath下。这会有很多——最好的方式就是包含所有的(实例代码就是这样做的);
确保在你的配置文件中<ldap-server>设置了root属性,且它与启动时加载的LDIF文件中root的定义相匹配。如果你遇到了找不到引用的错误,很可能要么缺少root元素,要么与LDIF文件不匹配;
注意的是启动嵌入式LDAP的错误并不会是一个致命错误。为了分析加载LDIF文件的错误,你需要确保适当设置了日志,包括Apache DS的日志启用,至少要在ERROR级别。LDIF的加载器在包下,它应该被用来启用LDIF加载错误的日志;
如果应用没有被正常关闭,为了重新启动服务,你可能会需要删除临时目录下的一些文件(Windows系统下为%TEMP%)。这个的出错信息(幸运的是)很清楚。
遗憾的是,嵌入式LDAP并不像嵌入式HSQL数据库那样简单,但是相对于需要下载和配置的很多外部LDAP服务器来说,已经比较简单了。
一个用于排除问题和访问LDAP的好工具是Apache Directory Studio,它提供了独立的和Eclipse插件的版本。免费下载地址:http://directory.apache.org/studio/ 。
理解Spring LDAP认证如何工作
我们看到可以使用LDIF文件定义的用户(也就会在LDAP目录中出现)进行登录了。一个LDAP用户进行登录时到底发生了什么?在LDAP认证过程中有三个基本的步骤:
将用户提供的凭证与LDAP目录进行认证;
基于LDAP上的信息,确定用户拥有的GrantedAuthority;
为了应用以后用到,从LDAP条目中预先加载用户信息到自定义的UserDetails对象中。
认证用户凭证
第一步,通过织入AuthenticationManager的自定义认证提供者与LDAP目录进行认证。o.s.s.ldap.authentication.LdapAuthenticationProvider将用户提供的凭证与LDAP目录进行校验,如下图所示:
我们可以看到o.s.s.ldap.authentication.LdapAuthenticator接口定义了一个代理从而允许提供者以自定义的方式认证请求。在这里我们明确配置的是o.s.s.ldap.authentication.BindAuthenticator,它会尝试使用用户的凭证绑定(登录)LDAP服务器,就像用户本身尝试建立连接。对嵌入式的服务器来说,这对于我们的认证要求是足够的,但是,外部的LDAP服务器在用户绑定LDAP目录上可能要求更严格。幸运的是,还有一种替代的认证方式,我们将会在本章稍后介绍。
正如图中所标注的那样,记住查找是在<ldap-server>引用的manager-dn属性所创建的LDAP上下文中进行的。对于嵌入式的服务器,我们没有使用这个信息,但是对于外部的服务器引用,除非提供manager-dn,否则的话将会进行匿名绑定。为了保持目录中公开访问信息的限制,通常需要合法的凭证来进行LDAP目录的搜索,这样的话,manager-dn在现实世界场景中基本上就是必需的了。manager-dn代表了用户的全DN,基于合法的访问绑定目录并进行查找。
确定用户的角色
在用户基于LDAP服务器成功认证之后,接下来必须要进行权限信息的确定。授权是通过安全实体的一系列角色定义的,LDAP认证过的用户角色确定如下图所示:
我们可以看到,用户在使用LDAP认证之后,LdapAuthenticationProvider委托给了一个LdapAuthoritiesPopulator。DefaultLdapAuthoritiesPopulator将会尝试在LDAP等级中另一个条目的同级或下级属性中查找认证用户的DN。(译者注:即在LDAP目录角色相关的条目中寻找当前用户,以确定用户的角色)
查找用户角色分配的DN是通过group-search-base属性定义的——在我们的例子中,我们这样设置group-search-base="ou=Groups"。当一个用户的DN在group-search-base DN下面的条目中时,包含用户DN的条目中的一个属性将会作为这些用户的角色。
【你可能注意到我们混合使用了属性的写法——在类流程图中使用了groupSearchBase,在文本中使用的是group-search-base。这是有意的——文本中对应的是XML配置属性而图中指的是相关类的成员(属性)。他们的命名相似,但是在不同的上下文中(XML和Java)要适当调整。】
Spring Security中的角色和LDAP中的用户如何关联还是有点令人迷惑,所以让我们看一下JBCP Pets库以及用户与角色关联是如何进行的。DefaultLdapAuthoritiesPopulator使用了几个<ldap-authentication-provider>声明的属性来管理为用户查找角色。这些属性大致按以下的顺序使用:
group-search-base:它定义了基础的DN,LDAP集成应该基于此往下为用户查找一个或多个的匹配项。默认值会在LDAP根中进行查找,这可能会代价较高;
group-search-filter:它定义了LDAP查找的过滤器,用来匹配用户的DN与group-search-base之下的条目属性。这个过滤器通过两个参数进行参数化设置——第一个({0})作为用户的DN,第二个作为({1})作为用户的名字。默认值为(uniqueMember={0})。
group-role-attribute:它定义了匹配条目中用来组装用户GrantedAuthority的属性,默认值为cn;
role-prefix:要拼到在group-role-attribute中发现值的前缀以产生Spring Security的GrantedAuthority。默认值为ROLE_。
这对于新的开发人员可能会比较抽象和困难,因为这与我们基于JDBC的UserDetailsService实现有很大的区别。让我们以JBCP Pets LDAP目录中的ldapguest用户登录以了解其过程。
用户的DN是uid=ldapguest,ou=Users,dc=jbcppets,dc=com而group-search-base被配置成了ou=Groups。对于这个ou的LDAP树展现如下:
我们可以看到在ou=Groups之下,有两个条目(cn=Admin和cn=User)。每个条目都具有objectClass: groupOfUniqueNames(你可能会记起我们在本章前面讨论过的对象类)。这种类型的LDAP对象允许多个DN值存储在这个条目下并进行逻辑分组。条目cn=User的属性列在下图中:
我们可以看到cn=User的uniqueMember属性用来标识这个组里面的LDAP用户。你也可能会发现uniqueMember的属性值就是对应用户的DN。
现在再看角色搜索的逻辑的就很容易了。从ou=Groups (group-search-base)开始,Spring Security将会查找任何uniqueMember属性值与用户DN(group-search-filter)匹配的条目。当它找到匹配的条目,条目的cn值(group-role-attribute)——在本例中即为User,将会加上ROLE_ (role-prefix)前缀然后转换成大写字母组成用户的GrantedAuthority。一旦我们使用过它,再理解起来就容易一些了,不是吗?
【Spring LDAP很灵活。要记住的是尽管这是一个组织LDAP兼容Spring Security的方式,但是通常的使用场景恰恰相反——LDAP目录已经存在,Spring Security需要织入。在很多场景下,你可以重新配置Spring Security来处理LDAP的等级结构。但是,很关键的一点是你要有效规划并理解Spring在查询时如何与LDAP一起工作。开动你的大脑,勾画出用户查找和组查找以及你能想到的最优方案——让查询范围尽可能小和精确。】
如果你此时还是感到困惑,我们建议你休息一下然后尝试使用Apache Directory Studio来看一下运行系统配置的嵌入式LDAP服务器。如果你按照前面描述的算法,尝试自己查找一下目录将会有助于你了解Spring Security LDAP配置的流程。
匹配UserDetails的其它属性
最后,在通过LDAP查找分配给用户GrantedAuthority后,o.s.s.ldap.userdetails.LdapUserDetailsMapper将会使用o.s.s.ldap.userdetails.UserDetailsContextMapper来获取另外的细节信息来填充UserDetails。
使用我们到现在为止配置的<ldap-authentication-provider>,LdapUserDetailsMapper将会使用用户LDAP条目中的信息填充UserDetails对象。
我们稍后将会看到UserDetailsContextMapper怎样配置才能从标准的LDAP person和inetOrgPerson中获取丰富的信息。使用基本的LdapUserDetailsMapper,仅仅能够存储用户名、密码以及GrantedAuthority。
尽管在LDAP用户认证里面还有很多的结构,但是你会发现整体的流程与我们前面学习的JDBC认证很类似(认证用户、填充GrantedAuthoritys)。如同JDBC认证中那样,在LDAP集成中也有进行高级配置的能力——让我们了解的更深入一些并看看还能做什么。
感谢 iteye lengyun3566 。
他的博客地址:http://lengyun3566.iteye.com
他的新浪微博:http://weibo.com/1920428940
研磨设计模式——跟着cc学设计系列视频教程
本视频课程是北京Java私塾原创精品书籍《研磨设计模式》一书的配套学习视频,由《研磨设计模式》的第一作者CC录制
课程目标:全面、系统的掌握GoF设计模式的知识,达到可以在实际项目开发中运用的能力
技术要点:如何实现可配置、如何实现缓存以及缓存的管理、如何实现用缓存来控制多实例的创建、如何实现参数化工厂、 如何实现可扩展工厂、如何实现原型管理器、如何实现Java的静态代理和动态代理、如何实现多线程处理队列请求、 如何实现命令的参数化配置、可撤销的操作、宏命令、队列请求和日志请求、如何实现翻页迭代、如何检测环状结构、 如何实现通用的增删改查、如何模拟工作流来处理流程、如何实现简单又通用的XML读取、如何实现模拟AOP的功能......
深入浅出学Shrio视频教程
内容概述:Shiro是目前最热门、最易用、功能超强大的Java权限管理框架,强烈推荐,每个项目都必备的权限管理技术!通过本课程,你将从零开始直到彻底掌握Shiro的相关开发知识,达到可以进行实际项目开发的能力。包括:权限管理基础、Shiro入门、配置、身份认证、授权、Realms、Session管理、和Spring的集成、Web、Cache等众多开发细节技术
技术要点:源码级分析Shiro的授权过程、自定义开发Realm、多个Realms的开发配置、自定义开发AuthenticationStrategy、自定义开发自定义SessionDAO、和Struts2+Spring3的集成(包括修正struts2的bug)、Shiro和SpringMVC+Spring3的集成、包装使用其他的Cache框架、缓存数据同步更新的解决方案等等实际开发中常用的内容
ssh+jbpm项目(某集团OA)视频教程
达到能综合使用Struts2+Spring3+Hibernate3+Jbpm4来进行实际项目开发的能力。
包括:ssh和jbpm的整合;数据字典;通用DAO(Spring+Hibernate+泛型+反射+SpEL+模板方法模式);自动生成UUID的加强版;分层开发、SSH联合的基本开发;翻页的taglib;示范真实值和表现值,数据参照的实现;文件上传下载;主子表操;登录验证码;登录控制的拦截器
深入浅出学Spring Web MVC视频教程
系统、完整的学习Spring Web MVC开发的知识。包括:Spring Web MVC入门;理解DispatcherServlet;注解式控制器开发详解;数据类型转换;数据格式化;数据验证; 拦截器;对Ajax的支持;文件上传下载;表单标签等内容;最后以一个综合的CRUD带翻页的应用示例来综合所学的知识
Weblogic实战视频教程
WebLogic基础知识:WebLogic基本概念、正确安装WebLogic、建域、应用部署于JDBC选择、对WebLogic的监控和日志查看、集群的高可用性;课程目标:彻底掌握WebLogic的基本概念,在理解基本概念的基础上做到正确的安装WebLogic,根据不同的需求创建域,合理选择应用部署和JDBC配置。熟练掌握WebLogic的console监控,了解各种性能和运行指标,以及对监控结果的分析,运用集群的高可用性,对集群架设。