啊。。。。。。沙滩,阳光,笔记本往膝上一搁,开始写博客。第一次没在国内过年,避开了吃吃吃,感觉真好,人也觉得轻松多了。
上次说到了CAS SSO最基本的使用方法,并且我们结合了一个数据库表来实现了我们自定义用户名和密码的单点登录功能。今天我们将要开始把我们的CAS SSO一步步往更深更专业的层次推进下去,我们先来看一下CAS SSO在结合WINDOWS AD域(此处我们使用open-ldap)来实现这个WINDOWS AD域的单点登录。即如何把我们的单点登录和巳有域帐号进行一下结合。
安装openldap
我们首先需要安装一个openldap,考虑到大部分读者还是以Windows操作系统为主,因此我们还是安装一个openldap for windows吧,网上很多openldap写着for windows但其实都不是真正的for windows,而是一些个自解压包或者是linux下的openldap的src文件在windows下用c++编译器重新编译了一下,这样的openldap会存在的诸多的不稳定性如:
- 服务莫明奇妙的当机
- openldap损坏,数据发生了无可逆转的破坏
我们还是去官方下载一个专门为windows定制的openldap吧,这个版本目前为止也是我使用下来觉得最稳定的版本,从没死过机,当然我回头也会把相关的安装文件传在我的资源中为大家提供便利。
大家以后装软件尽量不要把东西都装在C盘或者是什么program files这种形式的目录内,因为java的一些软件对于空格、特殊字符很敏感,曾经碰到过一些生产环境上出问题,结果查了半天是因为JAVA不认一些特殊字符导致的无法预料的错误,一旦你碰到了这种错误,嘿嘿,那就不只是找1-2小时的问题了,所以大家请养成一个好的习惯。
安装软件时请一定clear and sharp, clear and sharp。
可以从上图中看出openldap有2个端口:
- 389即通用端口
- 636即加密通讯端口,也就是openldaps(openldap里的ssl传输)
下一步。
在这儿我们选择BDB,即openldap自带的berkeley db,它是一个嵌入式的数据库,openldap的一些存储依赖于这个选项。
这儿设置的你们可以认为就是openldap里的“数据库超级用户密码”,我们就简单点,保持其default值叫"secret"即可。
全都设置完后openldap for windows就开始安装了。它装完后会自动在windows的服务器安装一个openldap的service,以便于开机自启动。
我们先不要去启动它,因为openldap刚装完后只是一个光版,我们还需要给它一些最基本的设置。
设置openldap
找到我们的openldap安装位置,用纯文本编辑器打开D:\utility\OpenLDAP目录下的slapd.conf文件。
include ./schema/core.schema include ./schema/cosine.schema include ./schema/nis.schema include ./schema/inetorgperson.schema include ./schema/openldap.schema include ./schema/dyngroup.schema
确保这几行include都不会注释即放开状态,所谓注释状态即如下形式:
#include ./schema/core.schema
因为这些是openldap的”依赖库“文件。
接着我们继续往下找,找到下面这行:
suffix "dc=maxcrc,dc=com" rootdn "cn=Manager,dc=maxcrc,dc=com"
这是什么意思?
openldap用的是和windows ad域一样的协议,它就是一个万维网的地址格式,如http://www.abc.com/video/animate,这一个个的”/”就是ldap即目录域形式,它是按照目录格式一级级向下寻找的,因此它相对于关系性数据库来说显得更轻量更快。
在这儿:
- suffix即代表“数据库地址”大家也可以把它想成url
- rootdn即用户名
- 密码?那就是刚才我们设的secret
这个是openldap安装完后默认的一个连接地址和用户名,当然我们不希望延用它的默认值,我们一般都会做一些自己个性化的设置,来,我们下面来改变一下这两行内容的值。
suffix "dc=sky,dc=org" rootdn "cn=Manager,dc=sky,dc=org"
我们把我们的域的根地址改成sky.org,那么在openldap中的表现就是dc=sky,dc=org,如果说对于这个根有一个用户,那么这个用户就一定是对于sky.org/xxx/xxx/xxx下所有目录具有访问权限的一个用户了,对不对,所以说这个dc=sky,dc=org的用户就是一个超级用户。
在openldap中用户名的格式是要写全的,因此我们把rootdn也改成了“cn=Manager,dc=sky,dc=org”,这么一长串就是它的用户名了。
再比如说:我们有一个用户,只限定该用户可以访问sky.org/company/companya下面的任何东西,那么这时这个用户名的dn该怎么写呢:
cn=sampleuser1,ou=companya,o=company,dc=sky,dc=org
看到了吗?
大家根据上面这个形式去找找感觉看,至于o代表什么意思? ou? dc? 这些都是ldap协议中的专有“属性”,好比是数据库内的字段类型,这个不属于本教程讨论范围,网上这方面资料太多,以后我会在讲ldap或者是ad域时专门讲述这些内容的。
上面我们设好了suffix,设好了rootdn,保存该文件后我们就可以启动openldap的服务了。
服务启动了,怎么连接openldap?怎么管理?
很可惜,openldap默认不提供图形化客户端 ,都是以黑屏命令形式连上openldap然后以命令形式来进行相关的用户和组织的增删改查的,当然我们有第三方开源工具可以对openldap进行管理。
openldap的管理
我们使用LdapAdmin工具,它是一个for windows的图形化管理openldap的客户工具,不需要安装,直接下载后双击即可使用,相当的灵活,它轻便、灵活而且是一个开源免费的软件。
双击它即可启动。
启动后选择菜单里的start->connect...即会弹出上面这个界面
我们选择New connection这个选项,双击New connection即得到下面这个界面。
大家可以把这个界面就认为是数据库超级用户的管理界面啦。
现在,我们开始填入相应的参数进去:
大家看这边的Base,就是suffix,如果你不想输这个Base或者是忘记了我们在slapd.conf文件中设置的suffix,你也可以点一下这个【Fetch DNs】按钮,它会根据主机地址和端口号自动探测到该服务器上的openldap服务及所有的suffix,并为你自动填上。
当然,我们不希望匿名登录,这样太不安全了,因此我们不是才设了rootdn和password吗?
于是我们把【Anonymous connection】前的勾取消掉,然后在Username中填入我们的rootdn,Password中填入“secret”。
按【Test connection】,我们得到“Connection successful”提示,即代表我们已经可以连上openldap服务了,此时请点【OK】按钮。
look,我们有了一个自己的“连接”叫localhost,双击它试试呢?
可以看到,此时,它还是一个空的“数据库”即没有建任何的“database instance(数据库实例)”,我们需要建一个database后才可以进行使用。
openldap的database的建立也有着它自己的create database命令,只不过它是一种叫ldif的批指令格式,我们只需要建立一个database,因此我们尽量简化我们的ldif命令,我们把它称为:root.ldif吧,该文件内容如下:
dn: o=company,dc=sky,dc=org objectClass: organization o: company dn: ou=members,o=company,dc=sky,dc=org objectClass: organizationalUnit ou: members
我们把它存为root.ldif文件,然后在我们的LdapAdmin界面中如下操作:
选择我们刚才建立的root.ldif文件,并且点【OK】按钮
看,我们已经有了自己的openldap“数据库”了。
建立openldap中的用户
我们有了数据库就可以往数据库中插数据了,我们来建一个用户名叫user1,密码为6个a吧。
右键单击ou=member这个树叶,按照如下界面来操作吧。
注意上面有几个地方要选择的:
- Rdn即rootdn,我们填入cn=user1
- 在Objectclass即字段类型中我们通过下拉框选择organizationPerson
- 这个organizationPerson有3个属性是必须要填的:
- cn即用户名
- sn即缩写
- 还有就是userPassword(按右边的滚动条往下拉可以看到这个属性
右边凡是黑色加粗的为“必填”项。
全部填完后即可按下【Save】按钮。
看,我们在我们的openldap中增加了一项,此时我们对于:
ou=members,o=company,dc=sky,dc=org这条url的访问用的用户名那因该怎么写呢:
dn: cn=users1,ou=members,o=company,dc=sky,dc=org
password: aaaaaa
对吧?很简单的哦,多练练就熟悉了。
好了,我们在openldap中建立了用户名和密码,现在就是要把我们的CAS SSO和我们的OpenLdap结合起来,即CAS SSO单点登录中的用户名从原来的数据库改变为ldap里的用户名和密码了。
在此之前,我们先普及一下相关的LDAP的理论知识。
OpenLdap VS 数据库
LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务。目录服务是一种特殊的数据库系统,其专门针对读取,浏览和搜索操作进行了特定的优化。目录一般用来包含描述性的,基于属性的信息并支持精细复杂的过滤能力。目录一般不支持通用数据库针对大量更新操作操作需要的复杂的事务管理或回卷策略。而目录服务的更新则一般都非常简单。这种目录可以存储包括个人信息、web链结、jpeg图像等各种信息。为了访问存储在目录中的信息,就需要使用运行在TCP/IP 之上的访问协议—LDAP。因此LDAP协议存储和访问数据比数据库的效率要高的多的多。
LDAP目录中的信息是是按照树型结构组织,具体信息存储在条目(entry)的数据结构中。常见的例子是通讯簿,由以字母顺序排列的名字、地址和电话号码组成。
目录服务与关系数据库之间的主要区别在于:二者都允许对存储数据进行访问,只是目录主要用于读取,其查询的效率很高,而关系数据库则是为读写而设计的。也就是目录服务不适于进行频繁的更新,属于典型的分布式结构。
总结:对于查询操作多于更新操作的(认证)系统来说,使用OpenLDAP是一个比关系数据库如MySq、PostgreSQL等更好的选择。
配置CAS SSO结合LDAP
拷入相应的jar类。
我们需要用到以下这些类库,把它们加载到D:\tomcat\webapps\cas-server\WEB-INF\lib目录下。
- cas-server-support-ldap-3.5.2.jar(在cas-server3.5.2的modules目录下去找到该包)
- spring-context-3.1.0.RELEASE.jar
- spring-context-support-3.1.0.RELEASE.jar
- spring-ldap-core-1.3.0.RELEASE.jar
- spring-ldap-core-tiger-1.3.0.RELEASE.jar
- spring-context-3.1.0.RELEASE.jar
- spring-context-support-3.1.0.RELEASE.jar
- spring-binding-2.3.0.RELEASE.jar
当然,我会把我集成好的cas-server-ldap一起上传在我的资源中,以便于大家的学习和使用。
把类库准备好后,我们开始来编辑我们的配置文件了。
配置ldap数据源
打开D:\tomcat\webapps\cas-server\WEB-INF目录下的deployerConfigContext.xml文件
找到我们原来的数据库数据源即dataSource
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" /> <property name="username" value="ymk" /> <property name="password" value="password_1" /> </bean>
我们把它注释掉。
<!--jdbc datasource--> <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" /> <property name="username" value="ymk" /> <property name="password" value="password_1" /> </bean> -->
然后加入一段:
<!-- ldap datasource--> <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="password" value="secret" /> <property name="pooled" value="true" /> <property name="url" value="ldap://localhost:389"/> <!--管理员 --> <property name="userDn" value="cn=Manager,dc=sky,dc=org" /> <property name="baseEnvironmentProperties"> <map> <!-- Three seconds is an eternity to users. --> <entry key="com.sun.jndi.ldap.connect.timeout" value="60" /> <entry key="com.sun.jndi.ldap.read.timeout" value="60" /> <entry key="java.naming.security.authentication" value="simple" /> </map> </property> </bean>
这就是我们的LDAP连接数据源了。
这边需要注意的是以下几个地方:
- property name="password"
- property name="url"
- property name="userDn"
然后我们找到我们在第一天教程中配置jdbc handler的地方:
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource" ></property> <property name="sql" value="select password from sys_user where user_id=?" ></property> </bean>
把这段注释掉
<!-- jdbc handler--> <!-- <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource" ></property> <property name="sql" value="select password from sys_user where user_id=?" ></property> </bean> -->
加入一段:
<!--ldap handler--> <bean class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler"> <property name="filter" value="cn=%u" /> <!-- 基节点 --> <property name="searchBase" value="ou=members,o=company,dc=sky,dc=org" /> <property name="contextSource" ref="contextSource" /> </bean>
保存并存盘。
需要注意的是下面这两行:
- <property name="filter" value="cn=%u" />
- <property name="searchBase" value="ou=members,o=company,dc=sky,dc=org" />
还记得之前我们说过的,LDAP里是怎么寻找cn=user1的连接地址的吗?
cn=user1,ou=members,o=company,dc=sky,dc=org
所以,在这儿,我们以ou=members,o=company,dc=sky,dc=org为基本地址(searchbase),寻找下面一切cn=为开头的用户名是否匹配(filter),如果用户名匹配了,那么cas会自动从LDAP里把该用户的userDn取出来,同时问你索取该用户所绑定的相关密码。
cas sso就是这么和ldap结合起来的。
好了,我们的LDAP和我们的CAS SSO已经结合好了,来做实验吧。
打开一个IE,输入:http://localhost:9090/cas-server/login
得到上面这个界面,然后我们在用户名和密码中输入相应的用户名和密码:
点击【登录】按钮,得到登录成功画面
这说明我们的CAS + LDAP是结合成功了,为了进一步实验我使用LdapAdmin工具再加入一个用户名:
username="cn=user2"
password="abcdefg"
然后我们拿cn=user2来做一下实验吧。
点击【登录】按钮,得到登录成功画面
这是我们需要的效果。
现在我们来拿我们在第一天中的cas-sample-site1和cas-sample-site2这两个Web App来做实验吧。
把这2个实验工程启动起来,然后我们打开一个IE,输入:http://localhost:8080/cas-sample-site1,IE跳转到了我们的cas-server的单点登录画面:
输入user1/aaaaaa或者是user2/abcdefg后,我们得到如下画面
点击“注销”连接,关闭IE,然后我们打开一个IE,输入:http://localhost:8080/cas-sample-site2,随后我们在登录界面输入user1/aaaaaa或者是user2/abcdefg后,我们得到如下画面
以上就是我们要的结果。
- cas-server和ldap的集成完后的case-server-ldap我已经上传在了我的资源中了,下载网址在:cas-server-ldap。
- LdapAdmin客户端的下载网址在此:LdapAdmin。
- Openldap for Windows稳定版下载在此:openldap for windows稳定版
OK,结束我们第二天的教程,下次开始我们要深入了解在使用cas sso登录后我们的Web应用是如何去取到用户的登录信息。
比如说我们的用户的信息像email, 手机, 姓名, 公司, 部门都是保存在ldap协议中的(如下截图)
我们在单点登录成功后,Web App是怎么把这些信息通过cas sso传播到我们的cas-sample-site1和cas-sample-site2中去呢?大家敬请期待后面一天的cas sso教程吧。