I am going mad over a LDAP attribute modification.
Be aware, I am very beginner so my code might contain mistakes and loads of issues but here is what I am trying to do.
I need to change the following attribute of a AD user givenName, samAccountName, displayName to the one of my choice.
I have 2 classes, one that searches for AD user (and works perfectly), and one that should modify the above attribute. However I keep getting error InvocationTargetException
This is Class 2, the one that does not work:
public void modify() {
try {
//connecting to the domain
Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.SECURITY_PROTOCOL,"TLSv1.2");
ldapEnv.put(Context.PROVIDER_URL,"ldap://10.61.0.6:389");
ldapEnv.put(Context.SECURITY_PRINCIPAL,"CN=ldapadmin,OU=Users,OU=Dublin,OU=Europe,OU=Offices,DC=vmtech,DC=com");
ldapEnv.put(Context.SECURITY_CREDENTIALS,"Password1");
InitialDirContext ldapContext = new InitialDirContext(ldapEnv);
DirContext ctx = new InitialDirContext(ldapEnv);
System.out.println(NameObject);
ModificationItem[] mods = new ModificationItem[3];
//replace the GivenName
Attribute A0 = new BasicAttribute("givenName", modgivenName);
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A0);
// replace the sAMAccountName
Attribute A1 = new BasicAttribute("samAccountName", ModsAMAccountName);
mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A1);
// Replace the displayname
Attribute A2 = new BasicAttribute("displayName",ModdisplayName);
mods[2] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A2);
for(int i =0; i <= mods.length; i++){
System.out.println(mods[i]);
}
// apply the modification to the object
ctx.modifyAttributes(NameObject, mods);
}
catch (NamingException ex) {
Logger.getLogger(LdapSearch.class.getName()).log(Level.SEVERE, null, ex);
}
}
Related
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();
}
}
I am transforming a shapefile by adding a new column attributes. Since this task is performed using Java, the only option I know for now is using Geotools. I have 2 main concerns:
1. I am not able to figure out how do I actually add a new column variable. Is the feature.setAttribute("col","value") the answer?
I see from this post just the example:https://gis.stackexchange.com/questions/215660/modifying-feature-attributes-of-a-shapefile-in-geotools but I dont get the solution.
//Upload the ShapeFile
File file = JFileDataStoreChooser.showOpenFile("shp", null);
Map<String, Object> params = new HashMap<>();
params.put("url", file.toURI().toURL());
DataStore store = DataStoreFinder.getDataStore(params);
SimpleFeatureSource featureSource = store.getFeatureSource(store.getTypeNames()[0]);
String typeName = store.getTypeNames()[0];
FeatureSource<SimpleFeatureType, SimpleFeature> source =
store.getFeatureSource(typeName);
Filter filter = Filter.INCLUDE;
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(filter);
try (FeatureIterator<SimpleFeature> features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
//adding new columns
feature.setAttribute("ShapeID", "SHP1213");
feature.setAttribute("UserName", "John");
System.out.print(feature.getID());
System.out.print(":");
System.out.println(feature.getDefaultGeometryProperty().getValue());
}
}
/*
* Write the features to the shapefile
*/
Transaction transaction = new DefaultTransaction("create");
// featureSource.addFeatureListener(fl);
if (featureSource instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(collection);
transaction.commit();
} catch (Exception problem) {
problem.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
}
System.exit(0); // success!
} else {
System.out.println(typeName + " does not support read/write access");
System.exit(1);
}
Assuming that setattribute is the one which adds, I get the following error for the above code.
Exception in thread "main" org.geotools.feature.IllegalAttributeException:Unknown attribute ShapeID:null value:null
at org.geotools.feature.simple.SimpleFeatureImpl.setAttribute(SimpleFeatureImpl.java:238)
at org.geotools.Testing.WritetoDatabase.main(WritetoDatabase.java:73)
2. After modifying these changes I want to store it in the database(PostGIS). I figured out the below snippet does the task, but doesn't seems to work for me with just shape file insertion
Properties params = new Properties();
params.put("user", "postgres");
params.put("passwd", "postgres");
params.put("port", "5432");
params.put("host", "127.0.0.1");
params.put("database", "test");
params.put("dbtype", "postgis");
dataStore = DataStoreFinder.getDataStore(params);
The error is a NullPointerException in the above case.
In GeoTools a (Simple)FeatureType is immutable (unchangeable) so you can't just add a new attribute to a shapefile. So first you must make a new FeatureType with your new attribute included.
FileDataStore ds = FileDataStoreFinder.getDataStore(new File("/home/ian/Data/states/states.shp"));
SimpleFeatureType schema = ds.getSchema();
// create new schema
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName(schema.getName());
builder.setSuperType((SimpleFeatureType) schema.getSuper());
builder.addAll(schema.getAttributeDescriptors());
// add new attribute(s)
builder.add("shapeID", String.class);
// build new schema
SimpleFeatureType nSchema = builder.buildFeatureType();
Then you need to convert all your existing features to the new schema and add the new attribute.
// loop through features adding new attribute
List<SimpleFeature> features = new ArrayList<>();
try (SimpleFeatureIterator itr = ds.getFeatureSource().getFeatures().features()) {
while (itr.hasNext()) {
SimpleFeature f = itr.next();
SimpleFeature f2 = DataUtilities.reType(nSchema, f);
f2.setAttribute("shapeID", "newAttrValue");
//System.out.println(f2);
features.add(f2);
}
}
Finally, open the Postgis datastore and write the new features to it.
Properties params = new Properties();
params.put("user", "postgres");
params.put("passwd", "postgres");
params.put("port", "5432");
params.put("host", "127.0.0.1");
params.put("database", "test");
params.put("dbtype", "postgis");
DataStore dataStore = DataStoreFinder.getDataStore(params);
SimpleFeatureSource source = dataStore.getFeatureSource("tablename");
if (source instanceof SimpleFeatureStore) {
SimpleFeatureStore store = (SimpleFeatureStore) source;
store.addFeatures(DataUtilities.collection(features));
} else {
System.err.println("Unable to write to database");
}
I try to get the ID of email that I just send it through Java EWS API.
My goal is when I got that ID I would store it to Database.
This what I'm trying:
try {
String isiEmail = generateIsiEmail(nmBank, jenis, tglAw, tglAk, produk);
EmailMessage mail = new EmailMessage(service);
mail.setSubject(jdlEmail);
mail.setBody(new MessageBody(isiEmail));
//set to cc
mail.getToRecipients().add(new EmailAddress(from.replaceAll("\\s", "")));
String[] too = to.split("\\;");
for (int i = 0; i <too.length; i++) {
mail.getToRecipients().add(new EmailAddress(too[i].replaceAll("\\s", "")));
}
String[] ccc = cc.split("\\;");
for (int i = 0; i <ccc.length; i++) {
mail.getCcRecipients().add(new EmailAddress(ccc[i].replaceAll("\\s", "")));
}
mail.sendAndSaveCopy();
} catch (ServiceLocalException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Thanks for help.
I solved by my self.
this step what I'm done with.
I use ExtendedPropertyDefinition refer from this tutorial https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633654(v%3dexchg.80) , but I modified from C# into java programing language,
set ExtendedPropertyDefinition then save the uuidToStr to database
UUID uuid = UUID.randomUUID();
ExtendedPropertyDefinition epd = new ExtendedPropertyDefinition(uuid, "NamaId", MapiPropertyType.String);
String uuidToStr = uuid.toString();
String isiEmail = generateIsiEmail(nmBank, jenis, tglAw, tglAk, produk);
EmailMessage mail = new EmailMessage(service);
mail.setSubject(jdlEmail);
mail.setBody(new MessageBody(isiEmail));
//set to cc
mail.getToRecipients().add(new EmailAddress(from.replaceAll("\\s", "")));
String[] too = to.split("\\;");
for (int i = 0; i <too.length; i++){
mail.getToRecipients().add(new EmailAddress(too[i].replaceAll("\\s", "")));
}
String[] ccc = cc.split("\\;");
for (int i = 0; i <ccc.length; i++){
mail.getCcRecipients().add(new EmailAddress(ccc[i].replaceAll("\\s", "")));
}
mail.setExtendedProperty(epd, "isiId");
mail.sendAndSaveCopy();
get the email based on ExtendedPropertyDefinition uuidToStr from database
UUID uuid = UUID.fromString("cc59cdbf-aad4-4cd1-a4f0-e7819c56b884");
ExtendedPropertyDefinition epd = new ExtendedPropertyDefinition(uuid, "NamaId", MapiPropertyType.String);
ItemView view2 = new ItemView(3);
SearchFilter sf = new SearchFilter.IsEqualTo(epd,"isiId");
FindItemsResults<Item> fir = service.findItems(WellKnownFolderName.SentItems, sf, view2);
for (Item itm : fir.getItems()){
System.out.println(itm.getId());
System.out.println(itm.getSubject());
}
DONE;
You should make use of the InternetMessageId property.
Call the FindItems method to search for messages in the sent items folder. Then instantiate an EmailMessage object so you can access the InternetMessageId property:
ItemView view = new ItemView(100); // You can change this to your needs.
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.InternetMessageId);
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.SentItems, view);
foreach (Item item in results)
{
if (item is EmailMessage)
{
EmailMessage emailMsg = item as EmailMessage;
Console.WriteLine(emailMsg.InternetMessageId);
}
}
I am using C# EWS Api, But this logic will work for you.
First you have to Save the email in Draft and then after you can get Email id.
EmailMessage emailMessage = new EmailMessage(service);
emailMessage.From = email.From;
emailMessage.Subject = email.Subject;
emailMessage.Body = new MessageBody(BodyType.HTML, email.Body);
foreach (var toAddress in email.To)
{
emailMessage.ToRecipients.Add(toAddress);
}
// Send message and save copy by default to sentItems folder
emailMessage.Save();
emailMessage.Load();
// Get Email Conversation Id.
string ConversationId = emailMessage.ConversationId.UniqueId;
string EmailMessageId;
emailMessage.SendAndSaveCopy();
// Get Email Message Id by InternetMessageId.
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.ContainsSubstring(EmailMessageSchema.InternetMessageId, InternetMessageId));
// Create the search filter.
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());
ItemView view = new ItemView(50);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.InternetMessageId);
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.SentItems, searchFilter, view);
if (results.Items.Count > 0)
{
Item item = results.Items[0];
EmailMessage message = EmailMessage.Bind(service, item.Id);
EmailMessageId = message.Id.UniqueId;
}
I believe the solution is this:
EmailMessage em = EmailMessage.bind( service, item.getId(),
new PropertySet( EmailMessageSchema.InternetMessageId) );
Explanation :
We have to bind the item to an email message, but instead of grabbing all the info, we only ask for the ID and any additional properties we want through the PropertySet parameter.
found -> Exchange Web Services get Message Message-ID
I am trying to get all users from my active directory however my code is returning just one row. I have tried the below which is currently only outputting one user.
private void getUserBasicAttributes(String username, LdapContext ctx) {
try {
List<String> usersList = new ArrayList<String>();
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
//First input parameter is search bas, it can be "CN=Users,DC=YourDomain,DC=com"
//Second Attribute can be uid=username
NamingEnumeration<SearchResult> answer = ctx.search("DC=domain,DC=com", "(&(objectCategory=user))"
, constraints);
if (answer.hasMoreElements()) {
Person person = new Person();
SearchResult attrs = ((SearchResult) answer.next());
String names[] = attrs.getName().split(",");
String name[] = names[0].split("=");
usersList.add(name[1]);
}else{
throw new Exception("Invalid User");
}
System.out.println(usersList.size());
} catch (Exception ex) {
ex.printStackTrace();
}
}
You are not looping over all the results, add a while loop inside the if
if (answer.hasMoreElements()) {
while(answer.hasMoreElements()) {
Person person = new Person();
SearchResult attrs = ((SearchResult) answer.next());
String names[] = attrs.getName().split(",");
String name[] = names[0].split("=");
usersList.add(name[1]);
}
}else{
throw new Exception("Invalid User");
}
You need while instead of if:
while (answer.hasMoreElements()) {
Person person = new Person();
SearchResult attrs = ((SearchResult) answer.next());
String names[] = attrs.getName().split(",");
String name[] = names[0].split("=");
usersList.add(name[1]);
}
if (usersList.size() == 0) {
throw new Exception("Invalid User");
}
You can simplify the name-element handling as well. No need to parse the DN. Just specify the attribute(s) you want returned up front and retrieve them directly.
You are making this too hard. No reason to perform any "splitting" pf values.
// Specify the ids of the attributes to return
String[] attrIDs = { "uid" };
// Get ONLY the attributes desired
Attributes answer = ctx.getAttributes("CN=Users,DC=YourDomain,DC=com", attrIDs);
for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
Attribute attr = (Attribute)ae.next();
System.out.println("attribute: " + attr.getID());
/* Print each value */
for (NamingEnumeration e = attr.getAll(); e.hasMore();
System.out.println(e.next()))
;
}
Let me know how I can help.
I have written an application that retrieves Active Directory groups and flattens them, i.e. includes recursively members of subgroup to the top parent group.
It works fine for small groups, but with larger groups I am facing a problem.
If number of members does not exceed 1500, they are listed in the member attribute. If there are more - then this attribute is empty and attribute with name member;range:0-1499 appears, containing first 1500 members.
My problem that I don't know how to get the rest of member set over 1500.
We have groups with 8-12 thousand members. Do I need to run another query?
On the Microsoft site I have seen C# code snippet on the similar matter, but couldn't make much sense of it, as they were showing how to specify a range, but not how to plug it into query. If someone knows how to do it in Java, I'd appreciate a tip.
This will obviously give you the next ones:
String[] returnedAtts = { "member;range=1500-2999" };
You need to fetch the users chunk by chunk (1500 chunks) Just make a counter and update you search and retrieve the next ones until you have all of them.
With your help I have a full working code
// Initialize
LdapContext ldapContext = null;
NamingEnumeration<SearchResult> results = null;
NamingEnumeration<?> members = null;
try {
// Initialize properties
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
properties.put(Context.PROVIDER_URL, "ldap://" + ldapUrl);
properties.put(Context.SECURITY_PRINCIPAL, adminLoginADOnPremise);
properties.put(Context.SECURITY_CREDENTIALS, adminPasswordADOnPremise);
// Initialize ldap context
ldapContext = new InitialLdapContext(properties, null);
int range = 0;
boolean finish = false;
while (finish != true) {
// Set search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchCtls.setReturningAttributes(generateRangeArray(range));
// Get results
results = ldapContext.search(ldapBaseDn, String.format("(samAccountName=%s)", groupName), searchCtls);
if (results.hasMoreElements() == true) {
SearchResult result = results.next();
try {
members = result.getAttributes().get(generateRangeString(range)).getAll();
while (members.hasMore()) {
String distinguishedName = (String) members.next();
logger.debug(distinguishedName);
}
range++;
} catch (Exception e) {
// Fails means there is no more result
finish = true;
}
}
}
} catch (NamingException e) {
logger.error(e.getMessage());
throw new Exception(e.getMessage());
} finally {
if (ldapContext != null) {
ldapContext.close();
}
if (results != null) {
results.close();
}
}
Two functions missing from the working code example by #Nicolas, I guess they would be something like:
public static String[] generateRangeArray(int i) {
String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);
String[] returnedAtts = { range };
return returnedAtts;
}
public static String generateRangeString(int i) {
String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);
return range;
}
The code does not handle the case if the AD group is not so large that the member attribute actually needs to be "chunked", that is if the "member" attribute exists instead.