Add Phone to user account in AD using Java - java

Using Java, I need to add a Phone Number to an user in AD.
String enderecoLdap = paramLDAP.get("SERVER_URLS");
LOGGER.info(enderecoLdap);
if( ! enderecoLdap.toLowerCase().startsWith("ldap") ) enderecoLdap = "ldap://" + enderecoLdap;
String sNomAdmin = "user";
String sSenhaAdmin = "senha";
String sDesChaveNome = "name";
String sDesChaveEmail = "mail";
enderecoLdap = "ldap://oinco.secreto.br:389";
Hashtable<String, Object> ldapEnv = new Hashtable<String, Object>(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
/* Specify host and port to use for directory service */
ldapEnv.put(Context.PROVIDER_URL, enderecoLdap);
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, sNomAdmin);
ldapEnv.put(Context.SECURITY_CREDENTIALS, sSenhaAdmin);
ldapEnv.put(Context.SECURITY_PROTOCOL, "simple");
// Connect AD
ctx = new InitialLdapContext(ldapEnv, null);
What should I do now to add a Phone number to an user?

Related

Query to retrieve all groups a user belongs to in LDAP

At the same time of providing authentication to the user in LDAP within Microsoft Active Directory, I'm trying to get all groups that specific user belongs to. The following code is in Java.
What I'm doing at the moment is the following:
public static List authenticate(String username, String password) throws Exception {
String LDAPURL = MY_LDAP_URL;
String userBase = MY_USERBASE; //format "dc=***,dc=com"
ArrayList<String> groups = new ArrayList<String>();
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, LDAPURL);
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, username);
environment.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx =
new InitialDirContext(environment);
SearchControls ctls = new SearchControls();
String[] attributes = {"cn", "memberOf"};
ctls.setReturningAttributes(attributes);
ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
String searchFilters = "{sAMAccountName="+username+"}";
NamingEnumeration<?> answer = ctx.search(userBase, searchFilters, ctls);
if(answer == null || !answer.hasMore()) {
logger.info("No result found");
}
else {
SearchResult result = (SearchResult) answer.next();
Attributes attrs = result.getAttributes();
Attribute memberAttr = attrs.get("memberOf");
NamingEnumeration e = memberAttr.getAll();
while(e.hasMore()) {
String group = (String) e.next();
groups.add(group);
logger.info(group);
}
}
return groups;
}
I have tried several ways of doing my query, for example:
String searchFilters = "(&(uid="+username+"),(ou=users),(memberOf=*))"
Or
String searchFilters = "(&(objectClass=groupOfNames)(member=cn=" + username + ")(memberOf=*))"
Or
String searchFilters = "(&(userPrincipalName=" + username + ")(memberOf=*))"
In none of the cases any groups were retrieved. In some of the cases the login itself failed as well (in some cases it worked but still no groups returned).
What is the correct way to retrieve the groups?
Although you can bind with "username" and some other attributes, using ANR, ONLY when using Microsoft Active Directory, you will need to obtain the Fully Distinguished Name for the user to perform many LDAP Searches.
Assuming username is the samAccountName, which is always Unique within a AD Forrest, your Authentication should work.
After Authentication you can obtain the DN of the entry and then perform a search for Groups the user is a member.
For all groups the user is a member, including nested groups this will usually work.
(member:1.2.840.113556.1.4.1941:=(CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET))
We have several JNDI Examples in a code repository.

Not able to retrieve users from LDAP AD server

I created LDAP AD server in Windows 2008 server using the steps mentioned in the following link:
https://blogs.msdn.microsoft.com/robert_mcmurray/2011/09/16/ftp-and-ldap-part-2-how-to-set-up-an-active-directory-lightweight-directory-services-ad-lds-server/#01b
The following program has to search for users in LDAP AD. It connects with the LDAP server successfully, but the user search is unsuccessful. I am not sure why.
public class LDAPTest {
String ldapHost = "ldap://hostname:389";
String searchBase = "CN=LDAPServer,DC=SITDomain,DC=local";
public static void main(String[] args) {
LDAPTest ldapConnect = new LDAPTest();
ldapConnect.authenticate("john", "****");
}
public Map authenticate(String user, String pass) {
String returnedAtts[] = { "dintinguishedName" };
String searchFilter = "(& (userPrincipalName="+user+")(objectClass=user))";
// Create the search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setReturningAttributes(returnedAtts);
// Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, this.ldapHost);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"CN=ryan,CN=grp,CN=LDAPServer,DC=SITDomain,DC=local");
env.put(Context.SECURITY_CREDENTIALS, pass);
LdapContext ctxGC = null;
boolean ldapUser = false;
try {
ctxGC = new InitialLdapContext(env, null);
// Search objects in GC using filters
NamingEnumeration<SearchResult> answer = ctxGC.search(this.searchBase, searchFilter, searchCtls);
while (answer.hasMoreElements()) {
SearchResult sr = answer.next();
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
Map amap = null;
if (attrs != null) {
System.out.println(attrs.size());
System.out.println(">>>>>>" + attrs.get("dintinguishedName"));
amap = new HashMap();
NamingEnumeration<Attribute> ne = (NamingEnumeration<Attribute>) attrs.getAll();
while (ne.hasMore()) {
Attribute attr = ne.next();
amap.put(attr.getID(), attr.get());
System.out.println(attr.getID()+">>>>>>" + attr.get());
ldapUser = true;
}
ne.close();
}
}
} catch (NamingException ex) {
ex.printStackTrace();
System.out.println(ex.getMessage());
}
return null;
}
}
LDAP server dir image
Not sure if it is a copy/paste error or a typo in the code, but the user attribute being returned is spelled incorrectly. The attribute name dintinguishedName should be distinguishedName. I would also expect to see an initial bind with a known good user (e.g. an account specifically created for the application), a search for the user, retrieval of the distinguishedName, and a second attempt to bind with the returned distinguishedName and user supplied password. Instead I'm seeing a hard-coded ID (ryan) using the user-supplied password. Which may work if the two accounts happen to have the same password. Below this post, I have included the code I use to authenticate against my LDAP servers, including Active Directory.
I wanted universal code, and most other LDAP servers require you use the distinguishedName in the bind operation. But for Active Directory, specifically, you can bind without knowing the distinguishedName of the user -- LDAP bind to AD can be performed with sAMAccountName (domain\user) and userPrincipalName (user#domain.TLD). If you have a single tree in a single forest (i.e. you know the value to append to the user ID to form sAMAccountName or userPrincipalName), you can perform a bind operation as the user. Should you need additional information about the person beyond their authentication validation, on return code 0 (successful authentication), search for the user & retrieve the information.
// Editable variables -- ensure you change these to your application's details
String strSysUID = "uid=YOURSYSTEMIDGOESHERE,ou=OrgUnitName,dc=Org,dc=Name";
String strSysPassword = "YourSystemPasswordGoesHere";
String strAuthorizationGroup = "LJL_Test";
String strTrustStorePassword = "YourTrustStorePassword"
String trustStoreFile = ".\\ADTrust";
String sLDAPServer = "ldaps://ldap.domain.gTLD:636";
String strUserBaseDN = "ou=UserOU,dc=Org,dc=Name";
String strGroupBaseDN = "ou=GroupOU,dc=Org,dc=Name";
String strUserIDSchemaAttribute = "sAMAccountName="; // attribute that holds user logon name
String strGroupMembershipSchemaAttribute = "member"; // attribute that holds member list in group object
// End of editable variables
System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
System.setProperty("javax.net.ssl.trustStorePassword", strTrustStorePassword);
// Obtain UID and PWD from user
String sUserUID = "";
String sUserPwd = "";
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Please enter your username: ");
try{
sUserUID = in.readLine();
}catch(Exception er) { er.printStackTrace(); }
System.out.print("Please enter your password: ");
try{
sUserPwd = in.readLine();
}catch(Exception er) { er.printStackTrace(); }
// Initial context for system bind
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, sLDAPServer);
env.put(Context.SECURITY_PROTOCOL, "ssl");
// Authenticate as system ID and password
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, strSysUID);
env.put(Context.SECURITY_CREDENTIALS, strSysPassword);
try {
DirContext ctx = new InitialDirContext(env);
// Using the system credentials, search for a user matching the logon ID provided by the user
String sFilter = strUserIDSchemaAttribute + sUserUID;
NamingEnumeration UserDNAnswer = ctx.search(strUserBaseDN, sFilter, null);
String sReturnedFQDN = "";
// If only one record should be returns, validate that exactly one record is located and throw an error otherwise
while (UserDNAnswer.hasMore()) {
SearchResult sr = (SearchResult) UserDNAnswer.next();
// Store the DN of the user re have found
sReturnedFQDN = sr.getNameInNamespace();
}
// Check group membership, can be done after the password is validated if you wish
// Example LDAP filter is "(&(cn=NameOfGroupToCheck)(uniqueMember=FQDNOfUserBeingTested))"
String sGroupFilter = "(&(cn=" + strAuthorizationGroup + ")(" + strGroupMembershipSchemaAttribute + "=" + sReturnedFQDN + "))";
NamingEnumeration GroupMembershipAnswer = ctx.search(strGroupBaseDN, sGroupFilter, null);
String sReturnedGroupDN = "";
while (GroupMembershipAnswer.hasMore()) {
SearchResult srGroup = (SearchResult) GroupMembershipAnswer.next();
sReturnedGroupDN = srGroup.getNameInNamespace();
}
ctx.close();
// If an entry was returned, then the user is a member of the group. We should validate the user's password
if(sReturnedGroupDN.equals("cn=" + strAuthorizationGroup+ "," + strGroupBaseDN)){
System.out.println(sReturnedFQDN + " is a member of " + sReturnedGroupDN + " and now we will validate the password.");
// Now establish a new LDAP connection to validate the credentials supplied
Hashtable envUser = new Hashtable(11);
envUser.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
envUser.put(Context.PROVIDER_URL, sLDAPServer);
// Authenticate using the searched FQDN for the user and the password provided by the user
envUser.put(Context.SECURITY_AUTHENTICATION, "simple");
envUser.put(Context.SECURITY_PRINCIPAL, sReturnedFQDN);
envUser.put(Context.SECURITY_CREDENTIALS, sUserPwd);
// Doing this so a login failure throws a code
try{
DirContext ctxUser = new InitialDirContext(envUser);
System.out.println("Successfully authenticated as " + sUserUID);
ctxUser .close;
}
// User credentials failure
catch (NamingException e) {
e.printStackTrace();
}
}
// If no group matched the filter, the user is not a group member and an authorisation failure can be returned
else{
System.out.println(sReturnedFQDN + " is NOT a member of " + sReturnedGroupDN + " and there is no need to verify the password.");
}
}
// System credentials failure
catch (NamingException e) {
e.printStackTrace();
}
}

getting user DN with user name LDAP

I want to get user DN with the username provided.
What I think is that I want to retrieve all the user data and compare with the username.
And now, I have added objectclass in my search filter and I have no idea why is the data is not retrieving.
Here are the codes that I currently have.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=admin,ou=sa,o=system");
env.put(Context.SECURITY_CREDENTIALS, "P#ssw0rd");
try{
DirContext context = new InitialDirContext(env);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration result = context.search("", "(objectclass=Person)", constraints);
while(result.hasMore())
{
SearchResult searchResult = (SearchResult) result.next();
Attributes attrs = searchResult.getAttributes();
request.setEmail(attrs.get("mail").toString());
request.setPhoneNumber(attrs.get("personalMobile").toString());
Attribute ldapattr = attrs.get("photo");
if(ldapattr != null){
byte[] photo = (byte[])ldapattr.get();
request.setPhoto(photo);
}
}
}catch(Exception e){
System.out.println("can't initialized");
}
list.add(request);
//Specific URL of LDAP with the host and :port
return list;
}
Provide a base DN to search. e.g. ou=users below and add username to filter for faster search
Don't get all the user data as you are unnecessarily increasing network traffic and doing additional computational work on the client.
LDAP server excels at this kind of searching. CN is indexed by default but givenName may not be indexed; so you might want to add an index for this attribute.
NamingEnumeration result = context.search("ou=users",
"(&(objectClass=person)(sAMAccountName=" + userId + "))", constraints);
If you have givenName
NamingEnumeration result = context.search("ou=users",
"(&(objectClass=person)(givenName=" + givenName + "))", constraints);

Setting LDAP SecurityPrincipal value

I am able to run following search query successfully on openldap commandline tool:
ldapsearch -h 1.11.1.1 -b "DC=ff2,DC=in" -s subtree -D "CN=Ldap Bind,OU=Service Accounts,OU=BA,DC=ff2,DC=in" -w G00Pass# sBAAccountName=testAccount
Now I have to execute it in java class. I have done the following:
Hashtable env = new Hashtable();
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, "ldap://1.11.1.1:389");
env.put(Context.SECURITY_PRINCIPAL, "CN=Ldap Bind,OU=Service Accounts,OU=TECH,DC=ff2,DC=in");
env.put(Context.SECURITY_CREDENTIALS, "H00Pass#");
LdapContext context = new InitialLdapContext(env, null);
// To get only 1000 results at a time.
context.setRequestControls(
new Control[]{new PagedResultsControl(1000, Control.CRITICAL)});
String[] attrs={"CN=Ldap Bind,OU=Service Accounts,OU=TECH,DC=ff2,DC=in"};
String base = "DC=ff2,DC=in";
String filter = "(&(objectClass=user)(sAMAccountName=testAccount))";
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(attrs);
SearchResult searchResults;
NamingEnumeration<SearchResult> results = context.search(base, filter, controls);
if (results.hasMoreElements()) {
SearchResult searchResult = (SearchResult) results.nextElement();
if(results.hasMoreElements()){
System.err.println("Matched multiple groups for the group with SID: ");
}else{
System.out.println( (String)searchResult.getAttributes().get("sAMAccountName").get());
}
}
This is giving me Null Pointer Exception at searchResult.getAttributes(). Here I am not sure how to include sBAAccountName filter?
You have to search with that criteria as follows:
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, "<LDAP HOST>");
env.put(Context.SECURITY_PRINCIPAL, "<LDAP USER LOGIN>");
env.put(Context.SECURITY_CREDENTIALS, "<LDAP USER PASSWORD>");
LdapContext context = new InitialLdapContext(env);
// To get only 1000 results at a time.
context.setRequestControls(
new Control[]{new PagedResultsControl(1000, Control.CRITICAL))});
String attrs = "<List of attrs to be retrieved for each matching LDAP entry>";
String base = "<Base of the search tree>";
String filter = "<Your filter>";
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(attrs);
SearchResults searchResults;
do {
searchResults = ctx.search(base, filter, controls);
while (searchResults.hasMoreElements()) {
// Process result.
}
// Process response controls to get the cookie
// and keep searching until it is null.
}
while (cookie is not null);
You must have declared searchResult elsewhere as a member variable. Remove that. You will then discover via a compile error that you are using it in a place where it isn't even declared and therefore has no value. Remove that too.

List the root contexts in LDAP

I would like to list or search the root context(s) in a LDAP tree. I use Apache Directory Server and Java:
Hashtable<String, String> contextParams = new Hashtable<String, String>();
contextParams.put("java.naming.provider.url", "ldap://localhost:10389");
contextParams.put("java.naming.security.principal", "uid=admin,ou=system");
contextParams.put("java.naming.security.credentials", "secret");
contextParams.put("java.naming.security.authentication", "simple");
contextParams.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
DirContext dirContext = new InitialDirContext(contextParams);
NamingEnumeration<NameClassPair> resultList;
//Works
resultList = dirContext.list("ou=system");
while (resultList.hasMore()) {
NameClassPair result = resultList.next();
System.out.println(result.getName());
}
//Does not work
resultList = dirContext.list("");
while (resultList.hasMore()) {
NameClassPair result = resultList.next();
System.out.println(result.getName());
}
I can list the sub nodes of ou=system. But I cannot list the sub nodes of the actual root node. I would like to have this list just like Apache Directory Studio can:
alt text http://lesc.se/stackoverflow/ldap_root_contexts.png
The base DNs can be obtained from the namingContexts attribute of the root node (RootDSE). The code should look like this:
Attributes attributes = dirContext.getAttributes( "", new String[]{"namingContexts"} );
Attribute attribute = attributes.get( "namingContexts" );
NamingEnumeration<?> all = attribute.getAll();
while(all.hasMore())
{
String next = (String)all.next();
System.out.println(next);
}

Categories