用LDAP牵涉到的几个概念,Context,entry/object,filter.Attribute
Context:上下文,我的理解是相当与文件系统的中的目录(JNDI的Naming Service是可以用操作系统的文件系统的).
entry/object:一个节点,相当与文件系统中的目录或文件.
filter:查询/过滤条件是一个字符串表达式如:(&(objectClass=top)(cn=*))查询出objectClass属性为top,cn属性为所有情况的entry.
Attribute:entry/object的属性可以理解成JAVA对象的属性,不同的是这个属性可以多次赋值.
测试方法:
search()方法的第一个参数是一个上下文执行时在这个上下文下进行查找,第二个参数是一个Filter字串意思是符合objectClass=top并且cn属性为任意值的entry,第三个属性是一个SearchControls对象在这个对象中设置一些参数用于控制查找,如controls.setSearchScope(SearchControls.SUBTREE_SCOPE); 这个方法中有三个值,SUBTREE_SCOPE为查找给定上下文(第一个参数)下以及所有下级上下文下的所有entry,而 ONELEVEL_SCOPE只查找给定上下文下的entry,OBJECT_SCOPE只查找一个entry。 controls.setCountLimit(100); 是设置查找返回的最大结果,如果查询的结果超过了这个值那么就会抛出一个异常。还有一个设置超时时间的方法setTimeout()。
[img]http://dl.iteye.com/upload/attachment/524853/dae31924-4ace-3371-a0a1-c80407c2494a.jpg[/img]
Context:上下文,我的理解是相当与文件系统的中的目录(JNDI的Naming Service是可以用操作系统的文件系统的).
entry/object:一个节点,相当与文件系统中的目录或文件.
filter:查询/过滤条件是一个字符串表达式如:(&(objectClass=top)(cn=*))查询出objectClass属性为top,cn属性为所有情况的entry.
Attribute:entry/object的属性可以理解成JAVA对象的属性,不同的是这个属性可以多次赋值.
import java.util.HashMap;
import java.util.Properties;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.AttributeInUseException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.NoSuchAttributeException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LDAPManager {
/** The OU (organizational unit) to add users to */
private static final String USERS_OU =
"ou=People,dc=ibm,dc=com";
/** The OU (organizational unit) to add groups to */
private static final String GROUPS_OU =
"ou=Group,dc=ibm,dc=com";
/** The OU (organizational unit) to add permissions to */
private static final String PERMISSIONS_OU =
"ou=Permission,dc=ibm,dc=com";
/** The default LDAP port */
private static final int DEFAULT_PORT = 389;
/** The LDAPManager instance object */
private static Map instances = new HashMap();
/** The connection, through a <code>DirContext</code>, to LDAP */
private DirContext context;
/** The hostname connected to */
private String hostname;
/** The port connected to */
private int port;
protected LDAPManager(String hostname, int port,
String username, String password)
throws NamingException {
context = getInitialContext(hostname, port, username, password);
// Only save data if we got connected
this.hostname = hostname;
this.port = port;
}
public static LDAPManager getInstance(String hostname,
int port,
String username,
String password)
throws NamingException {
// Construct the key for the supplied information
String key = new StringBuffer()
.append(hostname)
.append(":")
.append(port)
.append("|")
.append((username == null ? "" : username))
.append("|")
.append((password == null ? "" : password))
.toString();
if (!instances.containsKey(key)) {
synchronized (LDAPManager.class) {
if (!instances.containsKey(key)) {
LDAPManager instance =
new LDAPManager(hostname, port,
username, password);
instances.put(key, instance);
return instance;
}
}
}
return (LDAPManager)instances.get(key);
}
public static LDAPManager getInstance(String hostname, int port)
throws NamingException {
return getInstance(hostname, port, null, null);
}
public static LDAPManager getInstance(String hostname)
throws NamingException {
return getInstance(hostname, DEFAULT_PORT, null, null);
}
public void addUser(String username, String firstName,
String lastName, String password)
throws NamingException {
// Create a container set of attributes
Attributes container = new BasicAttributes();
// Create the objectclass to add
Attribute objClasses = new BasicAttribute("objectClass");
objClasses.add("top");
objClasses.add("person");
objClasses.add("organizationalPerson");
objClasses.add("inetOrgPerson");
// Assign the username, first name, and last name
String cnValue = new StringBuffer(firstName)
.append(" ")
.append(lastName)
.toString();
Attribute cn = new BasicAttribute("cn", cnValue);
Attribute givenName = new BasicAttribute("givenName", firstName);
Attribute sn = new BasicAttribute("sn", lastName);
Attribute uid = new BasicAttribute("uid", username);
//
// Attribute att = new BasicAttribute("memberof");
// if(username.startsWith("dev")){
// String memberOf = new StringBuilder("cn=dev,").append(GROUPS_OU).toString();
// att.add(memberOf);
// }else if(username.startsWith("qa")){
// String memberOf = new StringBuilder("cn=qa,").append(GROUPS_OU).toString();
// att.add(memberOf);
// }else{
// String memberOf = new StringBuilder("cn=dev,").append(GROUPS_OU).toString();
// att.add(memberOf);
//
// memberOf = new StringBuilder("cn=qa,").append(GROUPS_OU).toString();
// att.add(memberOf);
// }
// container.put(att);
// Add password
Attribute userPassword =
new BasicAttribute("userpassword", password);
// Add these to the container
container.put(objClasses);
container.put(cn);
container.put(sn);
container.put(givenName);
container.put(uid);
container.put(userPassword);
// Create the entry
context.createSubcontext(getUserDN(username), container);
}
public void deleteUser(String username) throws NamingException {
try {
context.destroySubcontext(getUserDN(username));
} catch (NameNotFoundException e) {
// If the user is not found, ignore the error
}
}
public boolean isValidUser(String username, String password)
throws UserNotFoundException {
try {
DirContext context =
getInitialContext(hostname, port, getUserDN(username),
password);
return true;
} catch (javax.naming.NameNotFoundException e) {
throw new UserNotFoundException(username);
} catch (NamingException e) {
// Any other error indicates couldn't log user in
return false;
}
}
public void addGroup(String name, String description, String[] memberOfGroup)
throws NamingException, Throwable {
if(memberOfGroup != null && memberOfGroup.length > 0){
// Create a container set of attributes
Attributes container = new BasicAttributes();
// Create the objectclass to add
Attribute objClasses = new BasicAttribute("objectClass");
objClasses.add("top");
objClasses.add("groupOfUniqueNames");
// objClasses.add("groupOfNames");
// Assign the name and description to the group
Attribute cn = new BasicAttribute("cn", name);
Attribute desc = new BasicAttribute("description", description);
// StringBuilder sb = new StringBuilder();
// int count = 0;
// for(String member : memberOfGroup){
// if(count > 0){
// sb.append(",");
// }
// sb.append("uid=").append(member);
// count ++;
// }
// String memberAttribute = sb.append(",").append(USERS_OU).toString();
// Attribute groupmember = new BasicAttribute("member", memberAttribute);
// container.put(groupmember);
Attribute memberAttributes = new BasicAttribute("uniquemember");
for(String member : memberOfGroup){
String memberAttribute = new StringBuilder("uid=").append(member).append(",").append(USERS_OU).toString();
// Attribute groupmember = new BasicAttribute("member", memberAttribute);
memberAttributes.add(memberAttribute);
}
container.put(memberAttributes);
// Add these to the container
container.put(objClasses);
container.put(cn);
container.put(desc);
// Create the entry
context.createSubcontext(getGroupDN(name), container);
}else{
throw new Throwable("Error occurs, not assign members into this group.");
}
}
public void deleteGroup(String name) throws NamingException {
try {
context.destroySubcontext(getGroupDN(name));
} catch (NameNotFoundException e) {
// If the group is not found, ignore the error
}
}
public void addPermission(String name, String description)
throws NamingException {
// Create a container set of attributes
Attributes container = new BasicAttributes();
// Create the objectclass to add
Attribute objClasses = new BasicAttribute("objectClass");
objClasses.add("top");
objClasses.add("ibmPermission");
// Assign the name and description to the group
Attribute cn = new BasicAttribute("cn", name);
Attribute desc = new BasicAttribute("description", description);
// Add these to the container
container.put(objClasses);
container.put(cn);
container.put(desc);
// Create the entry
context.createSubcontext(getPermissionDN(name), container);
}
public void deletePermission(String name) throws NamingException {
try {
context.destroySubcontext(getPermissionDN(name));
} catch (NameNotFoundException e) {
// If the permission is not found, ignore the error
}
}
public void assignUser(String username, String groupName)
throws NamingException {
try {
ModificationItem[] mods = new ModificationItem[1];
Attribute mod =
new BasicAttribute("uniqueMember",
getUserDN(username));
mods[0] =
new ModificationItem(DirContext.ADD_ATTRIBUTE, mod);
context.modifyAttributes(getGroupDN(groupName), mods);
} catch (AttributeInUseException e) {
// If user is already added, ignore exception
}
}
public void removeUser(String username, String groupName)
throws NamingException {
try {
ModificationItem[] mods = new ModificationItem[1];
Attribute mod =
new BasicAttribute("uniqueMember",
getUserDN(username));
mods[0] =
new ModificationItem(DirContext.REMOVE_ATTRIBUTE, mod);
context.modifyAttributes(getGroupDN(groupName), mods);
} catch (NoSuchAttributeException e) {
// If user is not assigned, ignore the error
}
}
public boolean userInGroup(String username, String groupName)
throws NamingException {
// Set up attributes to search for
String[] searchAttributes = new String[1];
searchAttributes[0] = "uniqueMember";
Attributes attributes =
context.getAttributes(getGroupDN(groupName),
searchAttributes);
if (attributes != null) {
Attribute memberAtts = attributes.get("uniqueMember");
if (memberAtts != null) {
for (NamingEnumeration vals = memberAtts.getAll();
vals.hasMoreElements();
) {
if (username.equalsIgnoreCase(
getUserUID((String)vals.nextElement()))) {
return true;
}
}
}
}
return false;
}
public List getMembers(String groupName) throws NamingException {
List members = new LinkedList();
// Set up attributes to search for
String[] searchAttributes = new String[1];
searchAttributes[0] = "uniqueMember";
Attributes attributes =
context.getAttributes(getGroupDN(groupName),
searchAttributes);
if (attributes != null) {
Attribute memberAtts = attributes.get("uniqueMember");
if (memberAtts != null) {
for (NamingEnumeration vals = memberAtts.getAll();
vals.hasMoreElements();
members.add(
getUserUID((String)vals.nextElement()))) ;
}
}
return members;
}
public List getGroups(String username) throws NamingException {
List groups = new LinkedList();
// Set up criteria to search on
String filter = new StringBuffer()
.append("(&")
.append("(objectClass=groupOfIBMNames)")
.append("(uniqueMember=")
.append(getUserDN(username))
.append(")")
.append(")")
.toString();
// Set up search constraints
SearchControls cons = new SearchControls();
cons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
// cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
// cons.setCountLimit(10000);
NamingEnumeration results =
context.search(GROUPS_OU, filter, cons);
while (results.hasMore()) {
SearchResult result = (SearchResult)results.next();
groups.add(getGroupCN(result.getName()));
}
return groups;
}
public void assignPermission(String groupName, String permissionName)
throws NamingException {
try {
ModificationItem[] mods = new ModificationItem[1];
Attribute mod =
new BasicAttribute("uniquePermission",
getPermissionDN(permissionName));
mods[0] =
new ModificationItem(DirContext.ADD_ATTRIBUTE, mod);
context.modifyAttributes(getGroupDN(groupName), mods);
} catch (AttributeInUseException e) {
// Ignore the attribute if it is already assigned
}
}
public void revokePermission(String groupName, String permissionName)
throws NamingException {
try {
ModificationItem[] mods = new ModificationItem[1];
Attribute mod =
new BasicAttribute("uniquePermission",
getPermissionDN(permissionName));
mods[0] =
new ModificationItem(DirContext.REMOVE_ATTRIBUTE, mod);
context.modifyAttributes(getGroupDN(groupName), mods);
} catch (NoSuchAttributeException e) {
// Ignore errors if the attribute doesn't exist
}
}
public boolean hasPermission(String groupName, String permissionName)
throws NamingException {
// Set up attributes to search for
String[] searchAttributes = new String[1];
searchAttributes[0] = "uniquePermission";
Attributes attributes =
context.getAttributes(getGroupDN(groupName),
searchAttributes);
if (attributes != null) {
Attribute permAtts = attributes.get("uniquePermission");
if (permAtts != null) {
for (NamingEnumeration vals = permAtts.getAll();
vals.hasMoreElements();
) {
if (permissionName.equalsIgnoreCase(
getPermissionCN((String)vals.nextElement()))) {
return true;
}
}
}
}
return false;
}
public List getPermissions(String groupName) throws NamingException {
List permissions = new LinkedList();
// Set up attributes to search for
String[] searchAttributes = new String[1];
searchAttributes[0] = "uniquePermission";
Attributes attributes =
context.getAttributes(getGroupDN(groupName),
searchAttributes);
if (attributes != null) {
Attribute permAtts = attributes.get("uniquePermission");
if (permAtts != null) {
for (NamingEnumeration vals = permAtts.getAll();
vals.hasMoreElements();
permissions.add(
getPermissionCN((String)vals.nextElement()))) ;
}
}
return permissions;
}
private String getUserDN(String username) {
return new StringBuffer()
.append("uid=")
.append(username)
.append(",")
.append(USERS_OU)
.toString();
}
private String getUserUID(String userDN) {
int start = userDN.indexOf("=");
int end = userDN.indexOf(",");
if (end == -1) {
end = userDN.length();
}
return userDN.substring(start+1, end);
}
private String getGroupDN(String name) {
return new StringBuffer()
.append("cn=")
.append(name)
.append(",")
.append(GROUPS_OU)
.toString();
}
private String getGroupCN(String groupDN) {
int start = groupDN.indexOf("=");
int end = groupDN.indexOf(",");
if (end == -1) {
end = groupDN.length();
}
return groupDN.substring(start+1, end);
}
private String getPermissionDN(String name) {
return new StringBuffer()
.append("cn=")
.append(name)
.append(",")
.append(PERMISSIONS_OU)
.toString();
}
private String getPermissionCN(String permissionDN) {
int start = permissionDN.indexOf("=");
int end = permissionDN.indexOf(",");
if (end == -1) {
end = permissionDN.length();
}
return permissionDN.substring(start+1, end);
}
private DirContext getInitialContext(String hostname, int port,
String username, String password)
throws NamingException {
String providerURL =
new StringBuffer("ldap://")
.append(hostname)
.append(":")
.append(port)
.toString();
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, providerURL);
if ((username != null) && (!username.equals(""))) {
props.put(Context.SECURITY_AUTHENTICATION, "simple");
props.put(Context.SECURITY_PRINCIPAL, username);
props.put(Context.SECURITY_CREDENTIALS,
((password == null) ? "" : password));
}
return new InitialDirContext(props);
}
}
public class UserNotFoundException extends RuntimeException{
private static final long serialVersionUID = 1L;
public UserNotFoundException(String message) {
super(message);
}
public UserNotFoundException(Throwable cause) {
super(cause);
}
public UserNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
测试方法:
import org.junit.BeforeClass;
import org.junit.Test;
public class LDAPManagerTest {
private static LDAPManager ldapManager;
@BeforeClass
public static void initEnv() throws Exception{
ldapManager = LDAPManager.getInstance("10.2.9.110", 389, "cn=manager,dc=ibm,dc=com", "secret");
}
@Test
public void addGroup() throws Throwable{
try{
String[] str1 = {"test1", "test2", "test3", "test4", "test5"};
String[] str2 = {"test1", "test7", "test9"};
ldapManager.addGroup("dev", "All people in dev team", str1);
ldapManager.addGroup("qa", "All people in dev team", str2);
ldapManager.assignUser("test5", "qa");
}catch(Exception e){
e.printStackTrace();
}
}
@Test
public void addUser() throws Exception{
for(int i=1; i<234000; i++){
ldapManager.addUser("test"+i, "first"+i, "last"+i, "123");
}
}
}
search()方法的第一个参数是一个上下文执行时在这个上下文下进行查找,第二个参数是一个Filter字串意思是符合objectClass=top并且cn属性为任意值的entry,第三个属性是一个SearchControls对象在这个对象中设置一些参数用于控制查找,如controls.setSearchScope(SearchControls.SUBTREE_SCOPE); 这个方法中有三个值,SUBTREE_SCOPE为查找给定上下文(第一个参数)下以及所有下级上下文下的所有entry,而 ONELEVEL_SCOPE只查找给定上下文下的entry,OBJECT_SCOPE只查找一个entry。 controls.setCountLimit(100); 是设置查找返回的最大结果,如果查询的结果超过了这个值那么就会抛出一个异常。还有一个设置超时时间的方法setTimeout()。
[img]http://dl.iteye.com/upload/attachment/524853/dae31924-4ace-3371-a0a1-c80407c2494a.jpg[/img]
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.SizeLimitExceededException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
/**
* Demonstrates how to perform a search and limit the number of results
* returned.
*
* usage: java SearchCountLimit
*/
class SearchCountLimit {
static int expected = 1;
public static void printSearchEnumeration(NamingEnumeration srhEnum) {
int count = 0;
try {
while (srhEnum.hasMore()) {
SearchResult sr = (SearchResult) srhEnum.next();
System.out.println(">>>" + sr.getName());
++count;
}
System.out.println("number of answers: " + count);
} catch (SizeLimitExceededException e) {
if (count == expected)
System.out.println("number of answers: " + count);
else
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
try {
// Create initial context
DirContext ctx = new InitialDirContext(env);
// Set search controls to limit count to 'expected'
SearchControls ctls = new SearchControls();
ctls.setCountLimit(expected);
// Search for objects with those matching attributes
NamingEnumeration answer = ctx.search("ou=People", "(sn=M*)", ctls);
// Print the answer
printSearchEnumeration(answer);
// Close the context when we're done
ctx.close();
} catch (Exception e) {
System.err.println(e);
}
}
}