I want to be able to get and update the user list in order to provide the function to maintain AD users. In Java, you can access AD using JNDI.
To search by specifying the user ID for AD authentication, refer to the URL below.
https://www.earthlink.co.jp/engineerblog/intra-mart-engineerblog/3336/
For searches that are expected to have multiple results, such as a list of users belonging to a particular OU, you need to be aware of the LDAP page size. For Windows Active Directory, perhaps 1,000 is the maximum size of the result. If you want to get more than that, repeat the search while paging.
Sample to get user list while paging
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://server"); //AD server address
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "userid@domain"); //User ID to log on to AD server@domain
env.put(Context.SECURITY_CREDENTIALS, "password"); //password
final int PAGE_SIZE = 1000;
InitialLdapContext context = null;
try {
context = new InitialLdapContext(env, null);
//Specifying search conditions
String name = "OU=aaa, DC=bbb, DC=ccc";
String filter = "(objectCategory=user)";
SearchControls control = new SearchControls();
control.setSearchScope(SearchControls.SUBTREE_SCOPE);
byte[] cookie = null;
do {
context.setRequestControls(new Control[] { new PagedResultsControl(PAGE_SIZE, cookie,
Control.CRITICAL) });
//Search execution
NamingEnumeration<SearchResult> results = context.search(name, filter, control);
//Get results
while (results.hasMore()) {
SearchResult result = results.next();
AdUserBean user = new AdUserBean(result);
System.out.println(user);
}
//Check if there is a next page
cookie = null;
if (context.getResponseControls() != null) {
Optional<Control> found = Arrays.stream(context.getResponseControls())
.filter(c -> c instanceof PagedResultsResponseControl).findFirst();
if (found.isPresent()) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) found.get();
cookie = prrc.getCookie();
}
}
} while (cookie != null);
} finally {
try {
if (context != null) {
context.close();
}
} catch (NamingException e) {
}
}
AdUserBean
public class AdUserBean {
private String cn = null;
private String name = null;
/**name*/
private String displayName = null;
/**User ID + domain*/
private String userPrincipalName = null;
/**LDAP Distinguished Name*/
private String distinguishedName = null;
/**mail address*/
private String mail = null;
/**Pager*/
private String pager = null;
/**
*constructor
*/
public AdUserBean() {
}
/**
*constructor
*
*Get content from Active Directory search results
*
* @param result
* @throws NamingException
*/
public AdUserBean(SearchResult result) throws NamingException {
NamingEnumeration<? extends Attribute> attributes = result.getAttributes().getAll();
while (attributes.hasMoreElements()) {
Attribute attribute = attributes.next();
Object value = attribute.get();
if ("name".equals(attribute.getID())) {
if (value instanceof String) {
name = (String) value;
}
} else if ("displayName".equals(attribute.getID())) {
if (value instanceof String) {
displayName = (String) value;
}
} else if ("cn".equals(attribute.getID())) {
if (value instanceof String) {
cn = (String) value;
}
} else if ("userPrincipalName".equals(attribute.getID())) {
if (value instanceof String) {
userPrincipalName = (String) value;
}
} else if ("pager".equals(attribute.getID())) {
if (value instanceof String) {
pager = (String) value;
}
} else if ("mail".equals(attribute.getID())) {
if (value instanceof String) {
mail = (String) value;
}
} else if ("distinguishedName".equals(attribute.getID())) {
if (value instanceof String) {
distinguishedName = (String) value;
}
}
}
}
//The following is omitted
}
hasMore
and hasMoreElements
There are two types of NamingEnumeration
class, which is the return value of thesearch ()
method, the hasMoreElements
method in the ordinary ʻEnumeration class and the original
hasMore` method.
while (results.hasMore()) {
SearchResult result = results.next();
//Abbreviation
}
Using the hasMore
method throws a NamingException
, for example, when trying to get more than the page size.
https://docs.oracle.com/javase/jp/11/docs/api/java.naming/javax/naming/NamingEnumeration.html
However, when searching AD while paging as in the previous sample, no error will occur even if the page size specified on the code side> the page size on the server side, and the search result will be the page size on the server side. returned.
Active Directory attributes include items with a single value and items with multiple values. Please note that the acquisition method is different for each.
Excerpt from the acquisition part of the attribute value
/**Pager*/
private String pager = null;
/**Pager(Other) */
private List<String> otherPager = null;
public AdUserBean(SearchResult result) throws NamingException {
NamingEnumeration<? extends Attribute> attributes = result.getAttributes().getAll();
while (attributes.hasMoreElements()) {
Attribute attribute = attributes.next();
Object value = attribute.get();
if ("pager".equals(attribute.getID())) {
//Pager(Single item)
if (value instanceof String) {
pager = (String) value;
}
} else if ("otherPager".equals(attribute.getID())) {
//Pager(Other) (Multiple items)
NamingEnumeration<?> values = attribute.getAll();
while (values.hasMore()) {
if (value instanceof String) {
if (otherPager == null) {
otherPager = new ArrayList<String>();
}
value = values.next();
otherPager.add((String) value);
}
}
}
}
}
Change user attributes
private static void update() throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://server"); //AD server address
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "user@domain"); //User ID to log on to AD server@domain
env.put(Context.SECURITY_CREDENTIALS, "password"); //password
DirContext context = null;
try {
context = new InitialDirContext(env);
Attributes attrs = new BasicAttributes();
attrs.put(new BasicAttribute("pager", "123456"));
attrs.put(new BasicAttribute("telephoneNumber", "1234567"));
String name = "CN=username, OU=xxx, DC=yyy, DC=zzz";
context.modifyAttributes(name, DirContext.REPLACE_ATTRIBUTE, attrs);
} finally {
try {
if (context != null) {
context.close();
}
} catch (NamingException e) {
}
}
}
The DN specified in the argument of modifyAttributes
must specify the OU to which the user (object) belongs. If you omit the OU hierarchy, an error will occur if "object not found".
The email address is a single item, but multiple phone numbers can be specified.
Descriptions of Active Directory user attributes (there are other explanation pages for each type of attribute) https://docs.microsoft.com/en-us/windows/win32/ad/naming-properties
Active Directory Attribute List https://docs.microsoft.com/en-us/windows/win32/adschema/attributes-all
LDAP search filter syntax http://software.fujitsu.com/jp/manual/manualfiles/M050000/B1WN4911/01/idmgr07/idmgr447.htm https://www.ibm.com/support/knowledgecenter/ja/SSYJ99_8.5.0/admin-system/rbug_ldapfltrxprns.html
Recommended Posts