在测试环境中,我设置了两个活动目录目录林A和B,每个目录林都有一个域控制器,并且目录林具有两种方式的信任设置。
我有用户-forestA中的userA和forestB中的userB。
我已经使用adfind.exe来测试userA和userB是否可以通过击中forestA端点进行身份验证,例如 。\ AdFind.exe -h -u userA@forestA.com -up 。\ AdFind.exe -h -u userB@forestA.com -up
两个用户都可以按照预期的方式通过forestA进行身份验证,因为他们具有两种方式的信任设置。
但是,userB永远无法使用Java JNDI API进行身份验证。我一直在搜索,发现最多的是他们建议对Context.SECURITY_PRINCIPAL属性使用DN或UPN,但它们都不适合我。
我非常确定原理和凭据正确无误,因为如果将主机更改为存储用户的森林B,则userB可以很好地进行身份验证。
这是我使用的标准JNDI代码-
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://forestA.com");
//env.put(Context.SECURITY_PRINCIPAL, "userB@forestB.com");
//env.put(Context.SECURITY_PRINCIPAL,
CN=userB,OU=marketing,DC=forestB,DC=com");
env.put(Context.SECURITY_PRINCIPAL, "forestB\\userB");
env.put(Context.SECURITY_CREDENTIALS, "mypass");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.REFERRAL, "follow");
DirContext dirContext = new InitialDirContext(env);
我已经坚持了好几天,感谢您的帮助!
答案 0 :(得分:0)
经过几天的研究和深入研究,我终于找到了解决方案。希望这对那些像我一样挣扎的人是有益的:) ...
首先,让我纠正上面使用的adfind示例,那里有一个错字,应该是以下内容-
.\AdFind.exe -h forestA.com -u userA@forestA.com -up pass
.\AdFind.exe -h forestA.com -u userB@forestB.com -up pass
两个adfind命令都会按预期通过。但是,
.\AdFind.exe -h forestA.com -u userB@forestB.com -up pass -simple
这将失败,因为它被迫使用“简单”身份验证。这让我想到,默认情况下,adfind使用的是其他方式,例如Kerberos身份验证,“简单”不适用于跨林身份验证。
我开始将Java JNDI代码从“简单”更改为Kerberos(GSSAPI),并且有效! 确保您的领域名称使用大写字母,并且ldap URL必须是主机名。我也想让它也能正常工作。
我已经包含了所有示例代码和配置文件,它们是使它正常工作所需要的。
JndiAction.java
public class JndiAction implements java.security.PrivilegedAction {
private String url;
private DirContext ctx;
public Object run() {
performJndiOperation();
return null;
}
private void performJndiOperation(/*String[] args*/) {
// Set up environment for creating initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://server01.forestb.com");
// Request the use of the "GSSAPI" SASL mechanism
// Authenticate by using already established Kerberos credentials
env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
try {
/* Create initial context */
ctx = new InitialDirContext(env);
System.out.println("Authenticated!");
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
}
GssExample.java
public class GssExample {
public static void main(String[] args) {
System.setProperty("sun.security.debug", "true");
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("java.security.krb5.conf", "C:\\dev\\active_directory\\krb5.conf");
System.setProperty("java.security.auth.login.config", "C:\\dev\\active_directory\\jaas.conf");
// 1. Log in (to Kerberos)
LoginContext lc = null;
try {
SampleCallbackHandler cbHandler = new SampleCallbackHandler();
cbHandler.setUsername("userb@FORESTB.COM");
cbHandler.setPassword("mypass");
lc = new LoginContext(GssExample.class.getName(), cbHandler);
// Attempt authentication
lc.login();
} catch (Exception le) {
le.printStackTrace();
System.exit(-1);
}
// 2. Perform JNDI work as logged in subject
Subject.doAs(lc.getSubject(), new JndiAction());
}
}
SampleCallbackHandler.java
public class SampleCallbackHandler implements CallbackHandler {
private String username = "";
private String password = "";
public void handle(Callback[] callbacks)
throws java.io.IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback cb = (NameCallback)callbacks[i];
cb.setName(this.username);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback cb = (PasswordCallback)callbacks[i];
String pw = this.password;
char[] passwd = new char[pw.length()];
pw.getChars(0, passwd.length, passwd, 0);
cb.setPassword(passwd);
} else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
krb5.conf
[libdefaults]
default_realm = FORESTB.COM
[realms]
FORESTA.COM = {
kdc = foresta.com
}
FORESTB.COM = {
kdc = forestb.com
}
jaas.conf
GssExample {
com.sun.security.auth.module.Krb5LoginModule required
client=TRUE
debug=true
useTicketCache=true
principal=david;
};