一.概念介绍:windows域,域控
二.环境及说明
三.总体过程
四.AD证书安装过程
五.AD证书的导出与导入
六.AD证书导入java密钥库中
七.java编码实现
八.问题说明
本文摘要:AD证书安装过程,AD证书的导出与导入,AD证书导入java密钥库中,java实现ldap改密,环境及说明
windows域:域常跟工作组做对比,这俩个概念有相似的地方,不理解域的可以参照工作组理解。但是,域一般是用在比较大的网络里,工作组则较小;域是有安全边界的,一个域内计算机建立信任关系。那么在域内访问其他机器,不再需要被访问机器的许可,需要一台计算机作为域控服务器。
域控:能安全集中管理域中账户密码、管理策略等构成数据库,统一安全策略。包含这个域的账号,密码属于这个域的计算机等信息构成的数据库。
1.安装Active Directory 的服务器(我使用的域名为hgcs.local)
2.安装证书服务(需安装企业根证书)的服务器,此服务器加入hdcs域中(也可以用域控作为证书服务器,我的就是)
3.安装JAVA应用的计算机,此服务器不需要加入hgcs域中(我是用的是mac电脑,win电脑参照进行修改)
说明: LDAP 无法直接获取windows Active Directory 用户密码,需要通过一个安全的通道(我这里用的是ssl)
1 安装Active Directory 域控制器
2 安装证书服务
3 以域用户登录到安装了证书服务的服务器中,导出域根证书和计算机证书
4 将证书倒入java密钥库中
5 编码实现
说明:这里我用的服务器是 Windows server 2008
*如果是第一次安装,为了避免出错,下列步骤中能勾选的复选框都选上。
*因服务器而异,在安装过程中,仔细阅读windows的说明信息,根据自己的需求作响应调整。
1.Windows server,进入服务器管理器,如图4.1所示。
图4.1 服务器管理器
2.服务器管理器,选择角色,右击,添加角色,如图4.2所示
图4.2 添加角色
3.添加角色第一步,选择下一步,如图4.3所示
图4.3 添加角色-第一步
4.添加角色第二步,选择Active Directory,下一步,如图4.4所示
图4.4 添加角色-第二步
5.添加角色第三步,选择证书颁发机构web注册,会弹出添加角色向导,点击添加必须的角色服务,(这里注意能选的都选上,或者仔细读win说明)如图4.5所示
图4.5 添加角色-第三步
6.添加角色第四步,选择安装类型-企业,如图4.6所示
图4.6 添加角色-第四步
7.添加角色第五步,选择CA类型-根CA,如图4.7所示
图4.7 添加角色-第五步
8.添加角色第六步,选择新建私钥,如图4.8所示
图4.8 添加角色-第六步
9.添加角色第七步,这里我用的是默认,密钥字体长度2048,哈希算法啥sha1,如图4.9所示
图4.9 添加角色-第七步
10.添加角色第八步,输入CA及dc,如图4.10所示
图4.10 添加角色-第八步
11.添加角色第九步,这里怕错的话能选的都选上,如图4.11所示
图4.11添加角色-第九步
11.添加角色第十步,至此安装成功,如图4.12所示
图4.12添加角色-第九步
说明:这里将导出的AD证书导入到java密钥库中,根据实际情况灵活使用。
*如果是第一次安装,为了避免出错,把能勾选的复选框都选上。
*这里要导出俩个证书,域根证书和计算机证书
1.使用快捷键win+R进入‘运行’,输入mmc进入控制台,如图5.1。
图5.1进入控制台
2.进入控制台,如果还没节点,如图5.2。可以添加,这里需要证书的节点。
图5.2控制台-空
3.添加管理单元,右击文件,选择添加/删除管理单元(本地计算机),如图5.3所示。
图5.3添加管理单元
4.管理单元,选择‘证书’节点,点击添加,确定,如图5.4所示。
图5.4添加证书节点
5.添加完‘证书’节点后,打开‘个人’,‘证书’,选择要导出的证书,如图5.5所示。
图5.5导出证书,第一步
6.右击需要的证书,选择‘所有任务’,‘导出’,导出证书,如图5.6所示。
图5.6导出证书,第二步
7.进入证书导出时,基本都是选择‘默认’直接下一步,下一步就可以,如图5.7所示。
图5.7导出证书,第三步
8.如果证书列表里只有一个证书,可能缺少计算机证书,可以根据步骤8,9申请新证书,再参照1-7导出证书,如图5.8所示。
图5.8申请新证书
9.申请新证书要选择证书类型为‘计算机’,其他选择默认,如图5.9所示。
图5.9申请新证书-要点
说明: 将从证书中导出的两个证书文件,*.cer 使用java的keytool工具创建或导入证书库文件中
这里我导出时,根证书命名为‘ADroot.cer ’ ,计算机证书命名为‘AD.cer’
/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home是我java根目录
/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin 下有keytool工具
/Users/handongchen/Desktop/ADroot.cer 是我证书的位置
/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/keytool -import -keystore security.keystore -file /Users/handongchen/Desktop/ADroot.cer
/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/keytool -import -keystore security.keystore -alias comkey -file /Users/handongchen/Desktop/AD.cer
终端提示证书导入到密钥库,且没报错,说明证书导入完成,这时一定要看下security.keystore在那,我的是在/Users/xxxx/security.keystore
也有可能在/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/security目录下。我的证书密码是“123456”
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class LdapTest {
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) {
// ladp的一些配置
Hashtable env = new Hashtable();
//String adminName = "Administrator@hgcs.local"; //管理员账号
String adminName = "cn=Administrator,cn=users,dc=hgcs,dc=local"; //管理员账号
String adminPassword = "root.1234"; //管理员密码
String userName = ("cn=wph1,cn=users,dc=hgcs,dc=local"); //用户
//String userName = ("wph@hgcs.local"); //用户
String newPassword = "root.1234"; //用户新密码
String keystore = "/Users/xxxx/security.keystore";
System.setProperty("javax.net.ssl.trustStore", keystore);
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, adminName);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
env.put(Context.SECURITY_PROTOCOL, "ssl");
String ldapURL = "ldaps://192.168.23.156:636";
env.put(Context.PROVIDER_URL, ldapURL);
try {
// 初始化ldapcontext
LdapContext ctx = new InitialLdapContext(env, null);
ModificationItem[] mods = new ModificationItem[1];
String newQuotedPassword = "\"" + newPassword + "\"";
byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
new BasicAttribute("unicodePwd", newUnicodePassword));
// 修改密码
ctx.modifyAttributes(userName, mods);
System.out.println("Reset Password for: " + userName);
ctx.close();
} catch (Exception e) {
System.out.println("Problem resetting password: " + e);
e.printStackTrace();
}
}
}
说明:下面是我写的catch里对错误的判断,可以参照
catch (Exception e) {
/*
* 根据ldap返回码判断错误原因并返回
*/
if (e.toString().indexOf("LDAP: error code") > 0) {
// 得到ldap返回的错误吗
String errorMsg = e.toString();
int startNum = errorMsg.toString().indexOf("LDAP: error code") + 17;
errorMsg = errorMsg.substring(startNum, startNum + 19);
int endNum = errorMsg.toString().indexOf(" - ");
errorMsg = errorMsg.substring(0, endNum);
if ("49".equals(errorMsg)) {
errorMsg = "域控管理员账户/密码错误";
} else if ("32".equals(errorMsg) || "34".equals(errorMsg)) {
errorMsg = "域内账户错误";
} else if ("10".equals(errorMsg)) {
errorMsg = "dc错误";
} else {
errorMsg = "修改失败,错误吗:" + errorMsg;
e.printStackTrace();
}
System.out.println("Problem resetting password(ldap):" + errorMsg);
return errorMsg;
} else {
if (e.toString().indexOf(
"algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext") > 0) {
System.out.println("Problem resetting password(ldap):" + "证书无效/证书密码错误");
return "修改失败,证书无效/证书密码错误";
}
if (e.toString().indexOf(
"the trustAnchors parameter must be non-empty") > 0) {
System.out.println("Problem resetting password(ldap):" + "证书不存在");
return "修改失败,证书不存在";
}
e.printStackTrace();
return "修改失败!";
}
}