アプリケーションのLDAP認証を行う必要があります。
私は次のプログラムを試しました:
import Java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class LdapContextCreation {
public static void main(String[] args) {
LdapContextCreation ldapContxCrtn = new LdapContextCreation();
LdapContext ctx = ldapContxCrtn.getLdapContext();
}
public LdapContext getLdapContext(){
LdapContext ctx = null;
try{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
//it can be <domain\\userid> something that you use for windows login
//it can also be
env.put(Context.SECURITY_PRINCIPAL, "[email protected]");
env.put(Context.SECURITY_CREDENTIALS, "password");
//in following property we specify ldap protocol and connection url.
//generally the port is 389
env.put(Context.PROVIDER_URL, "ldap://server.domain.com");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
}catch(NamingException nex){
System.out.println("LDAP Connection: FAILED");
nex.printStackTrace();
}
return ctx;
}
}
次の例外を取得:
LDAP接続:FAILED javax.naming.AuthenticationException:[LDAP:error code 49-Invalid Credentials] at com.Sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx。 Java:3053) at com.Sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.Java:2999) at com.Sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.Java: 2801) at com.Sun.jndi.ldap.LdapCtx.connect(LdapCtx.Java:2715) at com.Sun.jndi.ldap.LdapCtx。(LdapCtx.Java:305) com.Sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.Java:187) at com.Sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.Java:205) at com.Sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.Java:148) at com.Sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.Java:78) javax.naming.spi.NamingManager.getInitialContext(NamingManager.Java:235) at javax.naming.InitialContext.initializeDefaultInitCtx(InitialContext.Java:318) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.Java:348) at javax.naming.InitialContext.internalInit(InitialContext.Java:286) at javax.naming。 InitialContext.init(InitialContext.Java:308) javax.naming.ldap.InitialLdapContext。(InitialLdapContext.Java:99) at LdapContextCreation.getLdapContext(LdapContextCreation.Java:27) LdapContextCreation.main(LdapContextCreation.Java:12)
考慮すべき点はまだありません:
以前はTomcat 5.3.5
を使用していましたが、Tomcat 6のみがサポートしていると誰かに言われたので、Tomcat 6.0.35
をダウンロードし、現在このバージョンのみを使用しています。
server.xml
を構成し、次のコードを追加しました-
<Realm className="org.Apache.catalina.realm.JNDIRealm"
debug="99"
connectionURL="ldap://server.domain.com:389/"
userPattern="{0}" />
server.xml
の次のコードにコメントしました-
<!-- Commenting for LDAP
<Realm className="org.Apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/> -->
記事 のステップ2と3
誰かがldap
認証を実行するためにTomcatにコピーされることになっているいくつかのjarファイルがあることを示唆しましたが、それは私がする必要があることですか?そして、どのjar
ファイル?
また、正しい資格情報を確実に使用していますが、この問題の原因は何ですか?
間違った属性を使用している場合に、LDAPの正しい属性を把握する方法はありますか?
以下のコードは、純粋なJava JNDIを使用してLDAPから認証します。原理は次のとおりです。
コードスニペット
public static boolean authenticateJndi(String username, String password) throws Exception{
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT");
props.put(Context.SECURITY_PRINCIPAL, "uid=adminuser,ou=special users,o=xx.com");//adminuser - User with special priviledge, dn user
props.put(Context.SECURITY_CREDENTIALS, "adminpassword");//dn user password
InitialDirContext context = new InitialDirContext(props);
SearchControls ctrls = new SearchControls();
ctrls.setReturningAttributes(new String[] { "givenName", "sn","memberOf" });
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<javax.naming.directory.SearchResult> answers = context.search("o=xx.com", "(uid=" + username + ")", ctrls);
javax.naming.directory.SearchResult result = answers.nextElement();
String user = result.getNameInNamespace();
try {
props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT");
props.put(Context.SECURITY_PRINCIPAL, user);
props.put(Context.SECURITY_CREDENTIALS, password);
context = new InitialDirContext(props);
} catch (Exception e) {
return false;
}
return true;
}
これは私のLDAP Java LDAP://およびLDAPS://自己署名テスト証明書をサポートするログインテストアプリケーションです。コードはいくつかのSO投稿、実装を簡素化し、従来のSun.Java。*インポートを削除しました。
使用法
Windows7およびLinuxマシンでWinADディレクトリサービスに対してこれを実行しました。アプリケーションは、ユーザー名とメンバーグループを出力します。
$ Java -cp classes test.LoginLDAP url = ldap://1.2.3.4:389 [email protected] password = mypwd
$ Java -cp classes test.LoginLDAP url = ldaps://1.2.3.4:636 [email protected] password = mypwd
テストアプリケーションは、ldaps://プロトコルの一時的な自己署名テスト証明書をサポートします。このDummySSLFactoryは、任意のサーバー証明書を受け入れるため、中間者が可能です。実際のインストールでは、サーバー証明書をローカルのJKSキーストアファイルにインポートし、ダミーファクトリを使用しないでください。
アプリケーションは、初期コンテキストとLDAPクエリにエンドユーザーのユーザー名とパスワードを使用します。WinADには機能しますが、すべてのLDAPサーバー実装に使用できるかどうかはわかりません。内部のユーザー名+ pwdでコンテキストを作成し、クエリを実行して、特定のエンドユーザーが見つかったかどうかを確認できます。
LoginLDAP.Java
package test;
import Java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
public class LoginLDAP {
public static void main(String[] args) throws Exception {
Map<String,String> params = createParams(args);
String url = params.get("url"); // ldap://1.2.3.4:389 or ldaps://1.2.3.4:636
String principalName = params.get("username"); // [email protected]
String domainName = params.get("domain"); // mydomain.com or empty
if (domainName==null || "".equals(domainName)) {
int delim = principalName.indexOf('@');
domainName = principalName.substring(delim+1);
}
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, url);
props.put(Context.SECURITY_PRINCIPAL, principalName);
props.put(Context.SECURITY_CREDENTIALS, params.get("password")); // secretpwd
if (url.toUpperCase().startsWith("LDAPS://")) {
props.put(Context.SECURITY_PROTOCOL, "ssl");
props.put(Context.SECURITY_AUTHENTICATION, "simple");
props.put("Java.naming.ldap.factory.socket", "test.DummySSLSocketFactory");
}
InitialDirContext context = new InitialDirContext(props);
try {
SearchControls ctrls = new SearchControls();
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> results = context.search(toDC(domainName),"(& (userPrincipalName="+principalName+")(objectClass=user))", ctrls);
if(!results.hasMore())
throw new AuthenticationException("Principal name not found");
SearchResult result = results.next();
System.out.println("distinguisedName: " + result.getNameInNamespace() ); // CN=Firstname Lastname,OU=Mycity,DC=mydomain,DC=com
Attribute memberOf = result.getAttributes().get("memberOf");
if(memberOf!=null) {
for(int idx=0; idx<memberOf.size(); idx++) {
System.out.println("memberOf: " + memberOf.get(idx).toString() ); // CN=Mygroup,CN=Users,DC=mydomain,DC=com
//Attribute att = context.getAttributes(memberOf.get(idx).toString(), new String[]{"CN"}).get("CN");
//System.out.println( att.get().toString() ); // CN part of groupname
}
}
} finally {
try { context.close(); } catch(Exception ex) { }
}
}
/**
* Create "DC=sub,DC=mydomain,DC=com" string
* @param domainName sub.mydomain.com
* @return
*/
private static String toDC(String domainName) {
StringBuilder buf = new StringBuilder();
for (String token : domainName.split("\\.")) {
if(token.length()==0) continue;
if(buf.length()>0) buf.append(",");
buf.append("DC=").append(token);
}
return buf.toString();
}
private static Map<String,String> createParams(String[] args) {
Map<String,String> params = new HashMap<String,String>();
for(String str : args) {
int delim = str.indexOf('=');
if (delim>0) params.put(str.substring(0, delim).trim(), str.substring(delim+1).trim());
else if (delim==0) params.put("", str.substring(1).trim());
else params.put(str, null);
}
return params;
}
}
SSLヘルパークラス。
package test;
import Java.io.*;
import Java.net.*;
import Java.security.SecureRandom;
import Java.security.cert.X509Certificate;
import javax.net.*;
import javax.net.ssl.*;
public class DummySSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory socketFactory;
public DummySSLSocketFactory() {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{ new DummyTrustManager()}, new SecureRandom());
socketFactory = ctx.getSocketFactory();
} catch ( Exception ex ){ throw new IllegalArgumentException(ex); }
}
public static SocketFactory getDefault() { return new DummySSLSocketFactory(); }
@Override public String[] getDefaultCipherSuites() { return socketFactory.getDefaultCipherSuites(); }
@Override public String[] getSupportedCipherSuites() { return socketFactory.getSupportedCipherSuites(); }
@Override public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
return socketFactory.createSocket(socket, string, i, bln);
}
@Override public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
return socketFactory.createSocket(string, i);
}
@Override public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
return socketFactory.createSocket(string, i, ia, i1);
}
@Override public Socket createSocket(InetAddress ia, int i) throws IOException {
return socketFactory.createSocket(ia, i);
}
@Override public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
return socketFactory.createSocket(ia, i, ia1, i1);
}
}
class DummyTrustManager implements X509TrustManager {
@Override public void checkClientTrusted(X509Certificate[] xcs, String str) {
// do nothing
}
@Override public void checkServerTrusted(X509Certificate[] xcs, String str) {
/*System.out.println("checkServerTrusted for authType: " + str); // RSA
for(int idx=0; idx<xcs.length; idx++) {
X509Certificate cert = xcs[idx];
System.out.println("X500Principal: " + cert.getSubjectX500Principal().getName());
}*/
}
@Override public X509Certificate[] getAcceptedIssuers() {
return new Java.security.cert.X509Certificate[0];
}
}
SECURITY_PRINCIPAL
のユーザー全体dn
を提供する必要があります
このような
env.put(Context.SECURITY_PRINCIPAL, "cn=username,ou=testOu,o=test");
// this class will authenticate LDAP UserName or Email
// simply call LdapAuth.authenticateUserAndGetInfo (username,password);
//Note: Configure ldapURI ,requiredAttributes ,ADSearchPaths,accountSuffex
import Java.util.*;
import javax.naming.*;
import Java.util.regex.*;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class LdapAuth {
private final static String ldapURI = "ldap://20.200.200.200:389/DC=corp,DC=local";
private final static String contextFactory = "com.Sun.jndi.ldap.LdapCtxFactory";
private static String[] requiredAttributes = {"cn","givenName","sn","displayName","userPrincipalName","sAMAccountName","objectSid","userAccountControl"};
// see you Active Directory user OU's hirarchy
private static String[] ADSearchPaths =
{
"OU=O365 Synced Accounts,OU=ALL USERS",
"OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
"OU=In-House,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
"OU=Torbram Users,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS",
"OU=Migrated Users,OU=TES-Users"
};
private static String accountSuffex = "@corp.local"; // this will be used if user name is just provided
private static void authenticateUserAndGetInfo (String user, String password) throws Exception {
try {
Hashtable<String,String> env = new Hashtable <String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
env.put(Context.PROVIDER_URL, ldapURI);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx = new InitialDirContext(env);
String filter = "(sAMAccountName="+user+")"; // default for search filter username
if(user.contains("@")) // if user name is a email then
{
//String parts[] = user.split("\\@");
//use different filter for email
filter = "(userPrincipalName="+user+")";
}
SearchControls ctrl = new SearchControls();
ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctrl.setReturningAttributes(requiredAttributes);
NamingEnumeration userInfo = null;
Integer i = 0;
do
{
userInfo = ctx.search(ADSearchPaths[i], filter, ctrl);
i++;
} while(!userInfo.hasMore() && i < ADSearchPaths.length );
if (userInfo.hasMore()) {
SearchResult UserDetails = (SearchResult) userInfo.next();
Attributes userAttr = UserDetails.getAttributes();System.out.println("adEmail = "+userAttr.get("userPrincipalName").get(0).toString());
System.out.println("adFirstName = "+userAttr.get("givenName").get(0).toString());
System.out.println("adLastName = "+userAttr.get("sn").get(0).toString());
System.out.println("name = "+userAttr.get("cn").get(0).toString());
System.out.println("AdFullName = "+userAttr.get("cn").get(0).toString());
}
userInfo.close();
}
catch (javax.naming.AuthenticationException e) {
}
}
}