NC6和NCC版本与微软AD域认证集成
1.使用场景:
企业内部因为系统繁多,为了统一帐号,有可能使用AD域认证,通俗说也就是所有系统使用微软AD域的帐号密码认证,AD域认证通过后系统才可以正常访问。
2.开发思路:
结合到NCC产品上,首先要保证用户的帐号数据和AD域系统编码一致,密码设置需要在用户节点的认证类型字段设置为AD域认证,这样使得后台可以根据认证类型为AD域认证处理
3.编码实现
3.1前端增加认证类型
达到的效果是要在用户节点增加个AD域认证,这块代码是在配置文件里面处理的。路径在 home\ierp\sf\authenConfig.xml下
增加以下代码
<authenMode code="ldapauthen" name="AD域认证" enable="true">
<verifyClsName>nc.identityverify.pub.BQLDAPAuthenVerifier</verifyClsName><!--这个不可修改请确保是BQ模块下的-->
<clientHandlerClsName></clientHandlerClsName>
<resultMsgHandlerClsName></resultMsgHandlerClsName><!--这个不可修改请确保是BQ模块下的-->
<clientRunnableClsName></clientRunnableClsName>
<param key="ldapurl" value="172.20.99.1:389"/><!--这个参数根据现场环境配置 同NC系统即可-->
<afterVerifySuccessServerClsName>nc.identityverify.pub.StaticPWDVerifySuccessServer</afterVerifySuccessServerClsName>
<afterVerifySuccessClientClsName>nc.login.identify.ui.StaticPWDVerifySuccessClient</afterVerifySuccessClientClsName>
</authenMode>
nc.identityverify.pub.BQLDAPAuthenVerifier
这里的类是我们后面要用的认证的类,其他的和静态密码认证是一致的。
3.2重量端后端AD域认证
用户设置的AD域认证的话,会进入verify方法进行认证,认证成功则返回成功编码
package nc.identityverify.pub;
import java.security.Security;
import java.util.Hashtable;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.NCLocator;
import nc.bs.framework.common.RuntimeEnv;
import nc.bs.logging.Logger;
import nc.identityverify.itf.AbstractIdentityVerifier;
import nc.identityverify.vo.AuthenSubject;
import nc.itf.uap.IUAPQueryBS;
import nc.jdbc.framework.processor.BeanProcessor;
import nc.login.vo.ILoginConstants;
import nc.vo.jcom.lang.StringUtil;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.sm.UserVO;
/**
- 进行LDAP用户名身份验证的核心类
*/
public class BQLDAPAuthenVerifier extends AbstractIdentityVerifier {
protected BQLdapCfgBean ldapCfg = null;
protected InitialDirContext dirContext;
public BQLdapCfgBean getLdapcfg(){
if(ldapCfg == null){
BQLdapCfgBean ldapcfg1 =new BQLdapCfgBean();
ldapcfg1.setUsessl(UFBoolean.FALSE);
ldapcfg1.setLdap_server(" ");//ad域ip
ldapcfg1.setLdap_admin_user(" ");//ad域帐号
ldapcfg1.setLdap_admin_pwd("");//ad域密码
ldapcfg1.setContext_factory("com.sun.jndi.ldap.LdapCtxFactory");
ldapcfg1.setTop_dn(" ");//ad域搜索基准
ldapCfg =ldapcfg1;
}
return ldapCfg;
}
public int verify(AuthenSubject subject, UserVO userVO) {
//
if (userVO != null) {
getLdapcfg();
String pwd = subject.getUserPWD();
//默认为空密码
if (StringUtil.isEmpty(pwd)) {
ExceptionUtils.wrappBusinessException("密码不允许为空!");
}
String usercode = null;
try {
usercode = getUserDnByUserCodeInLdap(subject.getUserCode());
} catch (Exception e2) {
ExceptionUtils.wrappBusinessException("帐号信息不正确!");
}
String userAccountControl = null;
try {
userAccountControl = this.getUserCtrlByUserCodeInLdap(subject.getUserCode());
} catch (Exception e2) {
ExceptionUtils.wrappException(e2);
}
if("546".equals(userAccountControl)){
ExceptionUtils.wrappBusinessException("AD中用户已被禁止,请联系系统管理员!");
}
try {
DirContext dirContext ;
if (!this.ldapCfg.getUsessl().booleanValue())
{
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", this.ldapCfg.getContext_factory());
env.put("java.naming.provider.url", this.ldapCfg.getLdap_server());
env.put("java.naming.security.authentication", this.ldapCfg.getAuthentication());
env.put("java.naming.security.principal", usercode);
env.put("java.naming.security.credentials", pwd);
dirContext = new InitialDirContext(env);
}
else {
Hashtable env = new Hashtable();
System.setProperty("javax.net.ssl.trustStore", this.ldapCfg.getKeystorefile());
if (RuntimeEnv.isRunningInWebSphere())
{
Security.setProperty("ssl.SocketFactory.provider", "com.ibm.jsse2.SSLSocketFactoryImpl");
}
else {
try {
Class.forName("com.ibm.jsse2.SSLSocketFactoryImpl");
Security.setProperty("ssl.SocketFactory.provider", "com.ibm.jsse2.SSLSocketFactoryImpl");
}
catch (ClassNotFoundException localClassNotFoundException)
{
Security.setProperty("ssl.SocketFactory.provider", "com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl");
// ExceptionUtils.wrappException(localClassNotFoundException);
}
}
env.put(“java.naming.factory.initial”, this.ldapCfg.getContext_factory());
env.put(“java.naming.provider.url”, this.ldapCfg.getLdap_server());
env.put(“java.naming.security.authentication”, this.ldapCfg.getAuthentication());
env.put(“java.naming.security.principal”, usercode);
env.put(“java.naming.security.credentials”, pwd);
env.put(“java.naming.security.protocol”, “ssl”);
dirContext = new InitialLdapContext(env, null);
}
// DirContext dirc = new InitialDirContext(env);
dirContext.close();
// 验证成功
return ILoginConstants.USER_IDENTITY_LEGAL;
} catch (NamingException e) {
ExceptionUtils.wrappBusinessException("用户密码验证失败[用户名:" + subject.getUserCode() + "]: "
+ e.getMessage());
// 验证失败
return ILoginConstants.USER_NAME_RIGHT_PWD_WRONG;
}
} else { // 说明用户名称错误
return ILoginConstants.USER_NAME_WRONG;
}
}
public String getUserDN(String username,String rootContext){
String tmp = "uid=" + username + "," + rootContext;
return tmp;
}
public InitialDirContext getDirContext() throws NamingException
{
if (this.dirContext == null)
{
if (!this.ldapCfg.getUsessl().booleanValue())
{
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", this.getLdapcfg().getContext_factory());
env.put("java.naming.provider.url", this.getLdapcfg().getLdap_server());
env.put("java.naming.security.authentication", this.getLdapcfg().getAuthentication());
env.put("java.naming.security.principal", this.getLdapcfg().getLdap_admin_user());
env.put("java.naming.security.credentials", this.getLdapcfg().getLdap_admin_pwd());
this.dirContext = new InitialDirContext(env);
}
else
{
Hashtable env = new Hashtable();
System.setProperty("javax.net.ssl.trustStore", this.getLdapcfg().getKeystorefile());
if (RuntimeEnv.isRunningInWebSphere())
{
Security.setProperty("ssl.SocketFactory.provider", "com.ibm.jsse2.SSLSocketFactoryImpl");
}
else {
try {
Class.forName("com.ibm.jsse2.SSLSocketFactoryImpl");
Security.setProperty("ssl.SocketFactory.provider", "com.ibm.jsse2.SSLSocketFactoryImpl");
}
catch (ClassNotFoundException localClassNotFoundException)
{
Security.setProperty("ssl.SocketFactory.provider", "com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl");
}
}
env.put("java.naming.factory.initial", this.getLdapcfg().getContext_factory());
env.put("java.naming.provider.url", this.getLdapcfg().getLdap_server());
env.put("java.naming.security.authentication", this.getLdapcfg().getAuthentication());
env.put("java.naming.security.principal", this.getLdapcfg().getLdap_admin_user());
env.put("java.naming.security.credentials", this.getLdapcfg().getLdap_admin_pwd());
env.put("java.naming.security.protocol", "ssl");
this.dirContext = new InitialLdapContext(env, null);
}
}
return this.dirContext;
}
public String getUserDnByUserCodeInLdap(String usercode) throws Exception {
InitialDirContext ldapContext = getDirContext();
String filter = "(sAMAccountName=" + usercode + ")";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(2);
NamingEnumeration results = ldapContext.search(
getLdapcfg().getTop_dn(), filter, constraints);//
Object dnObj;
String dn;
if ((results != null) && (results.hasMore())) {
SearchResult result = (SearchResult) results.next();
Attributes attrs = result.getAttributes();
Attribute dnAttr = attrs.get("distinguishedName");
if (dnAttr != null) {
dnObj = dnAttr.get();
if (dnObj != null) {
dn = dnObj.toString();
return dn;
}
}
}
String sarchScope = this.ldapCfg.getUsersearchscope();
if ((sarchScope != null) && (sarchScope.trim().length() > 0)) {
String[] sarchScopes = sarchScope.split(";");
String[] arrayOfString1 = sarchScopes.clone();
for (int i = 0; i < arrayOfString1.length; i++) {
String scope = arrayOfString1[i];
if (scope.length() <= 0)
continue;
NamingEnumeration _results = ldapContext.search(scope, filter,
constraints);
if ((_results == null) || (!_results.hasMore()))
continue;
SearchResult result = (SearchResult) _results.next();
Attributes attrs = result.getAttributes();
Attribute dnAttr = attrs.get("distinguishedName");
if (dnAttr == null)
continue;
dnObj = dnAttr.get();
if (dnObj == null)
continue;
dn = dnObj.toString();
return dn;
}
}
return null;
}
public String getUserCtrlByUserCodeInLdap(String usercode) throws Exception {
InitialDirContext ldapContext = getDirContext();
String filter = "(sAMAccountName=" + usercode + ")";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(2);
NamingEnumeration results = ldapContext.search(
getLdapcfg().getTop_dn(), filter, constraints);
Object dnObj;
String dn;
if ((results != null) && (results.hasMore())) {
SearchResult result = (SearchResult) results.next();
Attributes attrs = result.getAttributes();
Attribute dnAttr = attrs.get("userAccountControl");
if (dnAttr != null) {
dnObj = dnAttr.get();
if (dnObj != null) {
dn = dnObj.toString();
return dn;
}
}
}
String sarchScope = this.ldapCfg.getUsersearchscope();
if ((sarchScope != null) && (sarchScope.trim().length() > 0)) {
String[] sarchScopes = sarchScope.split(";");
String[] arrayOfString1 = sarchScopes.clone();
for (int i = 0; i < arrayOfString1.length; i++) {
String scope = arrayOfString1[i];
if (scope.length() <= 0)
continue;
NamingEnumeration _results = ldapContext.search(scope, filter,
constraints);
if ((_results == null) || (!_results.hasMore()))
continue;
SearchResult result = (SearchResult) _results.next();
Attributes attrs = result.getAttributes();
Attribute dnAttr = attrs.get("userAccountControl");
if (dnAttr == null)
continue;
dnObj = dnAttr.get();
if (dnObj == null)
continue;
dn = dnObj.toString();
return dn;
}
}
return null;
}
}
3.3轻量端后端认证
轻量端的入口类在VerfiyBusiAndUser,在这里的可以根据认证类型介入,让其去调用上面AD域认证代码,根据返回信息进行判断。