Java 在LDAP服务器中对用户进行身份验证
我使用以下配置配置了OpenLDAP服务器:Java 在LDAP服务器中对用户进行身份验证,java,ldap,openldap,Java,Ldap,Openldap,我使用以下配置配置了OpenLDAP服务器: version: 1 # Entry 1: dc=unixmen,dc=com dn: dc=unixmen,dc=com dc: unixmen o: unixmen objectclass: top objectclass: dcObject objectclass: organization # Entry 2: cn=ServerAdmins,dc=unixmen,dc=com dn: cn=ServerAdmins,dc=unixmen
version: 1
# Entry 1: dc=unixmen,dc=com
dn: dc=unixmen,dc=com
dc: unixmen
o: unixmen
objectclass: top
objectclass: dcObject
objectclass: organization
# Entry 2: cn=ServerAdmins,dc=unixmen,dc=com
dn: cn=ServerAdmins,dc=unixmen,dc=com
cn: ServerAdmins
gidnumber: 501
objectclass: posixGroup
objectclass: top
# Entry 3: cn=rcbandit,cn=ServerAdmins,dc=unixmen,dc=com
dn: cn=rcbandit,cn=ServerAdmins,dc=unixmen,dc=com
cn: rcbandit
gidnumber: 501
givenname: rcbandit
homedirectory: /home/users/rcbandit
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: rcbandit
uid: rcbandit
uidnumber: 1000
userpassword: {MD5}2FeO34RYzgb7xbt2pYxcpA==
我创建了一个Java代码来搜索凭证:
public class SAuth
{
public static void main(String[] args)
{
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://192.168.1.177:389");
//env.put(Context.SECURITY_AUTHENTICATION, "simple");
//env.put(Context.SECURITY_PRINCIPAL, "cn=rcbandit,cn=ServerAdmins,dc=unixmen,dc=com");
//env.put(Context.SECURITY_CREDENTIALS, "qwerty");
// Enable connection pooling
env.put("com.sun.jndi.ldap.connect.pool", "true");
try
{
LdapContext ctx = new InitialLdapContext(env, null);
ctx.setRequestControls(null);
NamingEnumeration<?> namingEnum = ctx.search("cn=rcbandit,cn=ServerAdmins,dc=unixmen,dc=com", "(objectclass=*)", getSimpleSearchControls());
while (namingEnum.hasMore())
{
SearchResult result = (SearchResult) namingEnum.next();
Attributes attrs = result.getAttributes();
System.out.println(attrs.get("cn"));
System.out.println(attrs.get("gidnumber"));
System.out.println(attrs.get("givenname"));
System.out.println(attrs.get("homedirectory"));
System.out.println(attrs.get("objectclass"));
System.out.println(attrs.get("objectclass"));
System.out.println(attrs.get("objectclass"));
System.out.println(attrs.get("sn"));
System.out.println(attrs.get("uid"));
System.out.println(attrs.get("uidnumber"));
System.out.println(attrs.get("userpassword"));
}
namingEnum.close();
ctx.close();
}
catch (NamingException e)
{
e.printStackTrace();
}
}
private static SearchControls getSimpleSearchControls()
{
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setTimeLimit(30000);
//String[] attrIDs = {"objectGUID"};
//searchControls.setReturningAttributes(attrIDs);
return searchControls;
}
}
验证用户名和密码的正确方法是什么?看起来您可以通过未经验证的连接获取信息。但是,您需要在LDAP中执行
bind()
操作来执行身份验证
绑定操作的功能是允许在客户端和服务器之间交换身份验证信息。绑定操作应被视为“身份验证”操作
更多信息
创建InitialLdapContext
时,将执行代码中的绑定操作。但是,您需要具有要进行身份验证(已注释掉)的凭据和安全主体。目前,您正在通过未经验证的渠道阅读允许的信息
正确的方法是使用实例化InitialLdapContext
与要验证的主体和凭据绑定,并捕获失败的主体和凭据的javax.naming.AuthenticationException
env.put(Context.PROVIDER_URL, "ldap://XXX.XXX.XXX.XXX:XXX");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=rcbandit,cn=ServerAdmins,dc=unixmen,dc=com");
env.put(Context.SECURITY_CREDENTIALS, "xxxx");
..
LdapContext ctx = new InitialLdapContext(env, null);
}
catch(AuthenticationException ex) {
...
}
如果您不使用JNDI,这将很容易做到。所有JavaLDAP SDK都允许在同一个LDAP连接上绑定一个方法。我强烈建议您使用现代、最新的LDAP SDK,而不要使用JNDI。现在我们喜欢 为什么只有一个连接不需要在LDAP服务器上进行配置 下面是一个示例,它使用管理员进行搜索,然后将其绑定为返回的条目:
package com.willeke.samples.ldap.jndi;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
/**
*
* <p>
* Title: BasicJNDISearch
* </p>
*
* <p>
* Description: Provides a sample for performing JNDI Searches
* </p>
*
* @author Jim Willeke
* @version 1.0
*/
public class BasicAdminSearchBind
{
public BasicAdminSearchBind(String[] args)
{
super();
try
{
BasicAdminSearchBind.doBasicSearch(args);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
/**
*
* @param stid
* String - Standard ID (uid)
* @throws Exception
* -
*/
public static void doBasicSearch(String[] args) throws Exception
{
System.out.println("Performing LDAP Search with:");
System.out.println(" ldapHostName = " + args[0]);
System.out.println(" ldapPort = " + args[1]);
System.out.println(" bindDn = " + args[2]);
System.out.println(" bindDnPwd = " + args[3]);
System.out.println(" searchBase = " + args[4]);
System.out.println(" filter = (" + args[5] + "=" + args[6] + ")");
System.out.println(" Scope: = SUBTREE_SCOPE");
// Get the context for the admin account
DirContext adminCtx = getDirContext(args[0], args[1], args[2], args[3]);
SearchControls constraints = new SearchControls();
// Set the Scope of the search
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Create the filter from args
String filter = "(" + args[5] + "=" + args[6] + ")";
// Search for objects with those matching attributes
NamingEnumeration<?> answer = adminCtx.search(args[4], filter, constraints);
//formatResults(answer);
SearchResult sr = (SearchResult) answer.next();
String userDN = sr.getNameInNamespace();
//bind as returned entry
try
{
DirContext userCtx = bindAsEntry(args[0], args[1], userDN, "Secret Password");
System.out.println("We are now bound as the User: "+ userDN);
// we could do something with the userCtx here.
userCtx.close();
}
catch (Exception e)
{
System.err.println("We failed to make a bind as " + userDN + "\n" + e.getMessage());
}
adminCtx.close();
}
/**
*
* @param ldapHostName
* @param ldapPost
* @param bindDn
* @param bindDnPwd
* @return
* @throws NamingException
* @throws Exception
*/
private static DirContext bindAsEntry(String ldapHostName, String ldapPost, String bindDn, String bindDnPwd) throws NamingException
{
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://" + ldapHostName + ":" + ldapPost);
env.put(Context.SECURITY_PRINCIPAL, bindDn);
env.put(Context.SECURITY_CREDENTIALS, bindDnPwd);
// Create the initial context
DirContext ctx = new InitialDirContext(env);
return ctx;
}
/**
* Generic method to obtain a reference to a DirContext
*
* @param ldapHostName
* @param ldapPost
* @param bindDn
* @param bindDnPwd
*/
public static DirContext getDirContext(String ldapHostName, String ldapPost, String bindDn, String bindDnPwd) throws Exception
{
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://" + ldapHostName + ":" + ldapPost);
env.put(Context.SECURITY_PRINCIPAL, bindDn);
env.put(Context.SECURITY_CREDENTIALS, bindDnPwd);
// Create the initial context
DirContext ctx = new InitialDirContext(env);
return ctx;
}
/*
* Generic method to format the NamingEnumeration returned from a search.
*/
public static void formatResults(NamingEnumeration<?> enumer) throws Exception
{
int count = 0;
try
{
while (enumer.hasMore())
{
SearchResult sr = (SearchResult) enumer.next();
System.out.println("SEARCH RESULT:" + sr.getName());
formatAttributes(sr.getAttributes());
System.out.println("====================================================");
count++;
}
System.out.println("Search returned " + count + " results");
}
catch (NamingException e)
{
e.printStackTrace();
}
}
/*
* Generic method to format the Attributes .Displays all the multiple values of each Attribute in the Attributes
*/
public static void formatAttributes(Attributes attrs) throws Exception
{
if (attrs == null)
{
System.out.println("This result has no attributes");
}
else
{
try
{
for (NamingEnumeration<?> enumer = attrs.getAll(); enumer.hasMore();)
{
Attribute attrib = (Attribute) enumer.next();
System.out.println("ATTRIBUTE :" + attrib.getID());
for (NamingEnumeration<?> e = attrib.getAll(); e.hasMore();)
{
Object value = e.next();
boolean canPrint = isAsciiPrintable(value);
if (canPrint)
{
System.out.println("\t\t = " + value);
}
else
{
System.out.println("\t\t = <-value is not printable->");
}
}
}
}
catch (NamingException e)
{
e.printStackTrace();
}
}
}
/**
* Check to see if this Object can be printed.
*
* @param obj
* @return
*/
public static boolean isAsciiPrintable(Object obj)
{
String str = null;
try
{
str = (String) obj;
}
catch (Exception e)
{
return false;
// TODO Auto-generated catch block e.printStackTrace();
}
if (str == null)
{
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++)
{
if (isAsciiPrintable(str.charAt(i)) == false)
{
return false;
}
}
return true;
}
/**
* Used by isAsciiPrintable(Object obj)
*
* @param ch
* @return
*/
public static boolean isAsciiPrintable(char ch)
{
return ch >= 32 && ch < 127;
}
/**
* Does a simple search on the LDAP Directory
*
* String ldapHostName = args[0]; String ldapPort = args[1]; String bindDn = args[2]; String bindDnPwd = args[3]; String searchBase = args[4]; // String searchScope=args[4]; String searchAttribute = args[5];
* String searchAttributeValue = args[6];
*
* @param args
*
*/
public static void main(String[] args)
{
if (args.length == 7)
{
BasicAdminSearchBind basicjndisearch = new BasicAdminSearchBind(args);
}
else
{
System.out.println("\nYou must provide ldapHostName, ldapPort, bindDn, bindDnPwd, searchBase, searchAttribute and searchAttributeValue on the command line!\n");
}
}
}
package com.willeke.samples.ldap.jndi;
导入java.util.*;
导入javax.naming.*;
导入javax.naming.directory.*;
/**
*
*
*标题:基本搜索
*
*
*
*描述:提供用于执行JNDI搜索的示例
*
*
*@作者吉姆·威勒克
*@version 1.0
*/
公共类BasicAdminSearchBind
{
公共BasicAdminSearchBind(字符串[]args)
{
超级();
尝试
{
BasicAdminSearchBind.doBasicSearch(args);
}
捕获(例外情况除外)
{
例如printStackTrace();
}
}
/**
*
*@param stid
*字符串-标准ID(uid)
*@抛出异常
* -
*/
公共静态void doBasicSearch(字符串[]args)引发异常
{
System.out.println(“使用:”)执行LDAP搜索;
System.out.println(“ldapHostName=“+args[0]);
System.out.println(“ldapPort=“+args[1]);
System.out.println(“bindDn=“+args[2]);
System.out.println(“bindDnPwd=“+args[3]);
System.out.println(“searchBase=“+args[4]);
System.out.println(“过滤器=(“+args[5]+”=“+args[6]+”));
System.out.println(“范围:=子树范围”);
//获取管理员帐户的上下文
DirContext adminCtx=getDirContext(args[0],args[1],args[2],args[3]);
SearchControls约束=新的SearchControls();
//设置搜索范围
约束.setSearchScope(SearchControls.SUBTREE_范围);
//从args创建筛选器
字符串筛选器=“(“+args[5]+”=“+args[6]+””);
//搜索具有这些匹配属性的对象
NamingEnumeration answer=adminCtx.search(参数[4],过滤器,约束);
//结果(答案);
SearchResult sr=(SearchResult)answer.next();
字符串userDN=sr.getNameInNamespace();
//绑定为返回条目
尝试
{
DirContext userCtx=bindAsEntry(args[0],args[1],userDN,“秘密密码”);
System.out.println(“我们现在被绑定为用户:“+userDN”);
//我们可以在这里用userCtx做点什么。
userCtx.close();
}
捕获(例外e)
{
System.err.println(“绑定为“+userDN+”\n“+e.getMessage()”失败);
}
adminCtx.close();
}
/**
*
*@param ldapHostName
*@param ldapPost
*@param bindDn
*@param bindDnPwd
*@返回
*@NamingException
*@抛出异常
*/
私有静态DirContext bindAsEntry(字符串ldapHostName、字符串ldapPost、字符串bindDn、字符串bindDnPwd)引发NamingException
{
Hashtable env=新的Hashtable(11);
put(Context.INITIAL\u Context\u工厂,“com.sun.jndi.ldap.LdapCtxFactory”);
env.put(Context.PROVIDER_URL,“ldap://”+ldapHostName+“:”+ldapPost);
环境put(Context.SECURITY_PRINCIPAL,bindDn);
环境put(Context.SECURITY_凭证,bindDnPwd);
//创建初始上下文
DirContext ctx=新的初始DirContext(env);
返回ctx;
}
/**
*获取对DirContext的引用的泛型方法
*
*@param ldapHostName
*@param ldapPost
*@param bindDn
*@param bindDnPwd
*/
公共静态DirContext getDirContext(字符串ldapHostName、字符串ldapPost、字符串bindDn、字符串bindDnPwd)引发异常
{
Hashtable env=新的Hashtable(11);
put(Context.INITIAL\u Context\u工厂,“com.sun.jndi.ldap.LdapCtxFactory”);
env.put(Context.PROVIDER_URL,“ldap://”+ldapHostName+“:”+ldapPost);
环境put(Context.SECURITY_PRINCIPAL,bindDn);
环境put(Context.SECURITY_凭证,bindDnPwd);
//创建初始上下文
DirContext ctx=新的初始DirContext(env);
返回ctx;
}
/*
*设置搜索返回的NamingEnumeration格式的通用方法。
*/
公共静态void formatResults(NamingEnumeration枚举器)引发异常
{
整数计数=0;
尝试
{
while(enumer.hasMore())
{
SearchResult sr=(SearchResult)枚举器。下一步();
System.out.println(“搜索结果:+sr.getName());
formatAttributes(sr.getAttributes());
System.out.println(“===============================================================================”);
计数++;
}
System.out.println(“搜索返回”+计数+结果”);
}
捕获(NamingE例外)
package com.willeke.samples.ldap.jndi;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
/**
*
* <p>
* Title: BasicJNDISearch
* </p>
*
* <p>
* Description: Provides a sample for performing JNDI Searches
* </p>
*
* @author Jim Willeke
* @version 1.0
*/
public class BasicAdminSearchBind
{
public BasicAdminSearchBind(String[] args)
{
super();
try
{
BasicAdminSearchBind.doBasicSearch(args);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
/**
*
* @param stid
* String - Standard ID (uid)
* @throws Exception
* -
*/
public static void doBasicSearch(String[] args) throws Exception
{
System.out.println("Performing LDAP Search with:");
System.out.println(" ldapHostName = " + args[0]);
System.out.println(" ldapPort = " + args[1]);
System.out.println(" bindDn = " + args[2]);
System.out.println(" bindDnPwd = " + args[3]);
System.out.println(" searchBase = " + args[4]);
System.out.println(" filter = (" + args[5] + "=" + args[6] + ")");
System.out.println(" Scope: = SUBTREE_SCOPE");
// Get the context for the admin account
DirContext adminCtx = getDirContext(args[0], args[1], args[2], args[3]);
SearchControls constraints = new SearchControls();
// Set the Scope of the search
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Create the filter from args
String filter = "(" + args[5] + "=" + args[6] + ")";
// Search for objects with those matching attributes
NamingEnumeration<?> answer = adminCtx.search(args[4], filter, constraints);
//formatResults(answer);
SearchResult sr = (SearchResult) answer.next();
String userDN = sr.getNameInNamespace();
//bind as returned entry
try
{
DirContext userCtx = bindAsEntry(args[0], args[1], userDN, "Secret Password");
System.out.println("We are now bound as the User: "+ userDN);
// we could do something with the userCtx here.
userCtx.close();
}
catch (Exception e)
{
System.err.println("We failed to make a bind as " + userDN + "\n" + e.getMessage());
}
adminCtx.close();
}
/**
*
* @param ldapHostName
* @param ldapPost
* @param bindDn
* @param bindDnPwd
* @return
* @throws NamingException
* @throws Exception
*/
private static DirContext bindAsEntry(String ldapHostName, String ldapPost, String bindDn, String bindDnPwd) throws NamingException
{
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://" + ldapHostName + ":" + ldapPost);
env.put(Context.SECURITY_PRINCIPAL, bindDn);
env.put(Context.SECURITY_CREDENTIALS, bindDnPwd);
// Create the initial context
DirContext ctx = new InitialDirContext(env);
return ctx;
}
/**
* Generic method to obtain a reference to a DirContext
*
* @param ldapHostName
* @param ldapPost
* @param bindDn
* @param bindDnPwd
*/
public static DirContext getDirContext(String ldapHostName, String ldapPost, String bindDn, String bindDnPwd) throws Exception
{
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://" + ldapHostName + ":" + ldapPost);
env.put(Context.SECURITY_PRINCIPAL, bindDn);
env.put(Context.SECURITY_CREDENTIALS, bindDnPwd);
// Create the initial context
DirContext ctx = new InitialDirContext(env);
return ctx;
}
/*
* Generic method to format the NamingEnumeration returned from a search.
*/
public static void formatResults(NamingEnumeration<?> enumer) throws Exception
{
int count = 0;
try
{
while (enumer.hasMore())
{
SearchResult sr = (SearchResult) enumer.next();
System.out.println("SEARCH RESULT:" + sr.getName());
formatAttributes(sr.getAttributes());
System.out.println("====================================================");
count++;
}
System.out.println("Search returned " + count + " results");
}
catch (NamingException e)
{
e.printStackTrace();
}
}
/*
* Generic method to format the Attributes .Displays all the multiple values of each Attribute in the Attributes
*/
public static void formatAttributes(Attributes attrs) throws Exception
{
if (attrs == null)
{
System.out.println("This result has no attributes");
}
else
{
try
{
for (NamingEnumeration<?> enumer = attrs.getAll(); enumer.hasMore();)
{
Attribute attrib = (Attribute) enumer.next();
System.out.println("ATTRIBUTE :" + attrib.getID());
for (NamingEnumeration<?> e = attrib.getAll(); e.hasMore();)
{
Object value = e.next();
boolean canPrint = isAsciiPrintable(value);
if (canPrint)
{
System.out.println("\t\t = " + value);
}
else
{
System.out.println("\t\t = <-value is not printable->");
}
}
}
}
catch (NamingException e)
{
e.printStackTrace();
}
}
}
/**
* Check to see if this Object can be printed.
*
* @param obj
* @return
*/
public static boolean isAsciiPrintable(Object obj)
{
String str = null;
try
{
str = (String) obj;
}
catch (Exception e)
{
return false;
// TODO Auto-generated catch block e.printStackTrace();
}
if (str == null)
{
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++)
{
if (isAsciiPrintable(str.charAt(i)) == false)
{
return false;
}
}
return true;
}
/**
* Used by isAsciiPrintable(Object obj)
*
* @param ch
* @return
*/
public static boolean isAsciiPrintable(char ch)
{
return ch >= 32 && ch < 127;
}
/**
* Does a simple search on the LDAP Directory
*
* String ldapHostName = args[0]; String ldapPort = args[1]; String bindDn = args[2]; String bindDnPwd = args[3]; String searchBase = args[4]; // String searchScope=args[4]; String searchAttribute = args[5];
* String searchAttributeValue = args[6];
*
* @param args
*
*/
public static void main(String[] args)
{
if (args.length == 7)
{
BasicAdminSearchBind basicjndisearch = new BasicAdminSearchBind(args);
}
else
{
System.out.println("\nYou must provide ldapHostName, ldapPort, bindDn, bindDnPwd, searchBase, searchAttribute and searchAttributeValue on the command line!\n");
}
}
}