经过几天的琢磨,利用LDAP实现用户共享的任务初步实现。
LDAP相关简介:
1、快速响应和大容量查询并且提供多目录服务器的信息复制功能,它为读密集型的操作进行专门的 优化。因此,当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快一个数量级。
2、实现用户共享。即用某个第三方平台,管理公司内部的多个系统用户,同一个用户登录多个系统。
OpenLDAP服务器搭建: 下载地址: openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe
安装与配置: 推荐参考网址
1)、打开C:\Program Files\OpenLDAP \slapd.conf,找到ucdata-path ./ucdata
include ./schema/core.schema,在它后面添加
include ./schema/cosine.schema
include ./schema/inetorgperson.schema
2)、下面我们做一个示例:需要在 slapd.conf 配置文件中,找到
suffix “dc=my-domain,dc=com”
rootdn “cn=Manager,dc=my-domain,dc=com”
把这两行改为
suffix "dc=mycompany,dc=com"
rootdn "cn=Manager,dc=mycompany,dc=com"
3. 启动 OpenLDAP . CMD 进入到C:\Program Files\OpenLDAP 下,
1)、启动OpenLDAP-slapd服务:作用在于开机自动启动该服务项
slapd install OpenLDAP-slapd “OpenLDAP Directory Service” auto net start OpenLDAP-slapd
NOTE: the “slapd install” is only needed if you didn’t choose the “create NTservice” option during installation.
当你完成这一步后,下次开机的时候就自动启动LDAP的服务了,不必再次手动启动。(此步也可以忽略不做!)
2)、启动OpenLDAP服务器在cmd下运行:slapd -d 1
OpenAdmin客服端: 下载地址: LdapAdmin.exe 。 我下载的版本是LdapAdminExe-w64-1.7.1.zip。功能是没问题,可视化效果不好。
也可用LdapBrowser ,这个没试过,可能管理会方便得多。
打开LdapAdmin.exe文件
那么就你可以按照自己的目录设计修改一下压缩包目录中的init.ldif文件,并通过LDAP Admin->Tool->Import …菜单,导入init.ldif,实现top组织的添加。当然,你也可以通过命令窗口导入ldif文件,如:ldapadd -l init.ldif
dn: dc=mycompany,dc=com
objectClass: top
objectClass: dcObject
objectClass: domain
dc: mycompany
userPassword: {CRYPT}$1$Vd5g.O/y$g34U3EEuhAh.2g2q0E1TN/
dn: ou=roles,dc=mycompany,dc=com
objectClass: top
objectClass: organizationalUnit
ou: roles
dn: ou=people,dc=mycompany,dc=com
objectClass: top
objectClass: organizationalUnit
ou: people
dn: cn=Test Users,ou=roles,dc=mycompany,dc=com
objectClass: groupOfUniqueNames
cn: Test Users
uniqueMember: uid=sspecial,ou=people,dc=mycompany,dc=com
uniqueMember: uid=jbloggs,ou=people,dc=mycompany,dc=com
dn: cn=Special Users,ou=roles,dc=mycompany,dc=com
objectClass: groupOfUniqueNames
cn: Special Users
uniqueMember: uid=sspecial,ou=people,dc=mycompany,dc=com
dn: cn=Admin Users,ou=roles,dc=mycompany,dc=com
objectClass: groupOfUniqueNames
cn: Admin Users
uniqueMember: uid=admin,ou=people,dc=mycompany,dc=com
dn: uid=admin,ou=people,dc=mycompany,dc=com
objectClass: person
objectClass: inetOrgPerson
cn: State App
displayName: App Admin
givenName: App
mail: admin@fake.org
sn: Admin
uid: admin
userPassword: adminpassword
dn: uid=jbloggs,ou=people,dc=mycompany,dc=com
objectClass: person
objectClass: inetOrgPerson
cn: Joe Bloggs
displayName: Joe Bloggs
givenName: Joe
mail: jbloggs@fake.org
sn: Bloggs
uid: jbloggs
userPassword: password
dn: uid=sspecial,ou=people,dc=mycompany,dc=com
objectClass: person
objectClass: inetOrgPerson
cn: Super Special
displayName: Super Special
givenName: Super
mail: sspecial@fake.org
sn: Special
uid: sspecial
userPassword: password
dn: ou=sdmc,dc=mycompany,dc=com
objectClass: organizationalUnit
objectClass: top
ou: sdmc
dn: cn=DEMO,ou=sdmc,dc=mycompany,dc=com
gidNumber: 500
objectClass: posixGroup
objectClass: top
cn: DEMO
dn: cn=cai dimin,ou=sdmc,dc=mycompany,dc=com
givenName: cai
sn: dimin
cn: cai dimin
uid: cdimin
userPassword: {MD5}4QrcOUm6Wau+VuBX8g+IPg==
uidNumber: 1000
gidNumber: 500
homeDirectory: /home/users/cdimin
loginShell: /bin/sh
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
mail: 724801286@qq.com
dn: cn=ldapsdmc,ou=sdmc,dc=mycompany,dc=com
cn: ldapsdmc
telephoneNumber: 18682135083
l: sz
objectClass: organizationalRole
objectClass: top
phpldapadmin客户端(版本1.2.3)
a.官网下载源码放入WEB目录下:http://phpldapadmin.sourceforge.net/wiki/index.php/Download
b.安装依赖的扩展gettext ldap这2个扩展
c.按需配置 源码目录下config/config.php ( 需要取消注释的配置有)
$servers->setValue('server','name','My LDAP Server');
$servers->setValue('server','host','10.10.121.8');
$servers->setValue('server','base',array('dc=mycompany,dc=com'));
$servers->setValue('login','auth_type','session');
$servers->setValue('login','bind_id','cn=Manager,dc=mycompany,dc=com');
$servers->setValue('login','bind_pass','secret');) //空时,每次登录时,要手动输入
注意:在运行时,由于PHP版本是5.6,不兼容正则的'/e',则preg_replace() ->preg_replace_callback() ,
$a[$key] = preg_replace('/\\\([0-9A-Fa-f]{2})/e',"''.chr(hexdec('\\1')).''",$rdn);
$a[$key] = preg_replace_callback('/\\\([0-9A-Fa-f]{2})/',function($r) { return ''.chr(hexdec($r[0])).'' ; },$rdn);
还有 password_hash()->passwordhash()
公司内部系统连接LDAP服务器: 推荐参考网址:http://www.mzone.cc/article/621.html
spring-ldap-xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- ldap -->
<bean id="contextSource"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://10.10.121.8:389" />
<property name="base" value="dc=mycompany,dc=com" />
<property name="userDn" value="cn=Manager,dc=mycompany,dc=com" />
<property name="password" value="secret" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="userLdapDao" class="com.sdmc.basecms.ldap.UserDaoLdapImpl">
<property name="ldapTemplate" ref="ldapTemplate"/>
</bean>
<!-- end ldap -->
</beans>
Ldap.java
public static Object init(){
ApplicationContext cxt = new ClassPathXmlApplicationContext("spring-ldap.xml");
userLdapDao = (UserDaoLdapImpl)cxt.getBean("userLdapDao");
return userLdapDao ;
}
UserDaoLdapImpl.java
@SuppressWarnings("unchecked")
public LdapUser getLdapUserByuid(User user) {
// TODO Auto-generated method stub
byte[] bytes=(byte[])DigestUtils.md5( user.getPassword() );
String passwordValue=new String(bytes);
String filter = "(&(uid=" + user.getUsername()+"))";
List<LdapUser> list = ldapTemplate.search("ou=sdmc", filter, new AttributesMapper() { @Override
public Object mapFromAttributes(Attributes attributes) throws NamingException {
LdapUser ldapuser = new LdapUser();
Attribute attr = attributes.get("gidnumber");
if(attr!=null ){
ldapuser.setRoleId( attr.get()+"" );
}attr = attributes.get("userpassword");
if(attr!=null ){
byte[] bytes=(byte[])attr.get();
String passwordValue=new String(bytes);
ldapuser.setPassword( passwordValue );
}
attr = attributes.get("cn");
if(attr!=null ){
ldapuser.setCn( attr.get()+"" );
}attr = attributes.get("mail");
if(attr!=null ){
ldapuser.setMail( attr.get()+"" );
}
return ldapuser;
}
});
if (list.isEmpty()) return null;
return list.get(0);
}
1-LDAP服务器——已搭建好
2-phpldapadmin系统——已安装上(能操作LDAP的用户)
3-应用系统(CMS)——含有自己的用户及角色权限(也能操作到LDAP的用户)
总结:通过phpldapadmin管理LDAP上的用户实体,在CMS登录时,用该用户实体,实现CMS的登录鉴权验证和权限控制。
我的想法是:由于CMS存在一个用户表,表中有些字段在CMS系统操作时是有用的,CMS登录的时候,通过username,先去查询LDAP是否存在该用户,查密码等。 通过ldap分组名(唯一)获取cms中角色的权限。
1、LDAP存在,且CMS不存在该用户,就在CMS的用户表中插入用户数据,再按照CMS原来流程的登录
2、LDAP不存在,直接按照CMS原来流程的登录
说明:phpldapadmin系统对用户实体加密默认是MD5代码如下: base64_encode(pack('H*',md5( password )));
那么用username查出的密码,与CMS加密的密码需比较来验证 :
String ldapPassword = new String(Base64.decodeBase64( ldapUser.getPassword().substring(5).getBytes()),"UTF-8") ;
String loginPassword = CommonUtil.toStringHexTest( CommonUtil.getMd5( user.getPassword().getBytes()) ) ;
if( !loginPassword.equals(ldapPassword) ){
ResultVO<User> resutlVO = new ResultVO<User>();
resutlVO.setFlag(false);
resutlVO.setMessage("The Username Or Password On The LDAP Is incorrect!");
return resutlVO;
}