Java: LDAP Search returning 1 row - java

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.

Related

How to access an object attribute from a String in Java?

I have a String that tells me what attribute I should use to make some filtering. How can I use this String to actually access the data in the object ?
I have a method that returns a List of strings telling me how to filter my List of objects. Such as:
String[] { "id=123", "name=foo" }
So my first idea was to split the String into 2 parts with:
filterString.split("=") and use the first part of the String (e.g. "id") to identify the attribute being filtered.
Coming for a JS background, I would do it like this:
const attr = filterString.split('=')[0]; // grabs the "id" part from the string "id=123", for example
const filteredValue = filterString.split('=')[1]; // grabs the "123" part from the string "id=123", for example
items.filter(el => el[`${attr}`] === filteredValue) // returns an array with the items where the id == "123"
How would I be able to do that with Java ?
You can use reflections to get fields of class by dynamic name.
#Test
void test() throws NoSuchFieldException, IllegalAccessException {
String[] filters = {"id=123", "name=foo"};
List<Item> list = newArrayList(new Item(123, "abc"), new Item(2, "foo"), new Item(123, "foo"));
Class<Item> itemClass = Item.class;
for (String filter : filters) {
String key = StringUtils.substringBefore(filter, "=");
String value = StringUtils.substringAfter(filter, "=");
Iterator<Item> iterator = list.iterator();
while (iterator.hasNext()) {
Item item = iterator.next();
Field field = itemClass.getDeclaredField(key);
field.setAccessible(true);
Object itemValue = field.get(item);
if (!value.equals(String.valueOf(itemValue))) {
iterator.remove();
}
}
}
assertEquals(1, list.size());
}
But I agree with comment from sp00m - it's slow and potentially dangerous.
This code should work :
//create the filter map
Map<String, String> expectedFieldValueMap = new HashMap<>();
for (String currentDataValue : input) {
String[] keyValue = currentDataValue.split("=");
String expectedField = keyValue[0];
String expectedValue = keyValue[1];
expectedFieldValueMap.put(expectedField, expectedValue);
}
Then iterate over input object list ( have used Employee class with id and name fields & prepared a test data list with few Employee objects called inputEmployeeList which is being iterated ) and see if all filters passes, using reflection, though slow, is one way:
for (Employee e : inputEmployeeList) {
try {
boolean filterPassed = true;
for (String expectedField : expectedFieldValueMap.keySet()) {
String expectedValue = expectedFieldValueMap.get(expectedField);
Field fieldData = e.getClass().getDeclaredField(expectedField);
fieldData.setAccessible(true);
if (!expectedValue.equals(fieldData.get(e))) {
filterPassed = false;
break;
}
}
if (filterPassed) {
System.out.println(e + " object passed the filter");
}
} catch (Exception any) {
any.printStackTrace();
// handle
}
}

Combine 2 array lists of objects that have null values

I'm trying to concatenate 2 array lists of objects into one but i can't figure out how to do it. I've tried with addAll and add but those methods won't really do what i want.
Basically, i have one array list with values like this:
SearchResult1 [title=null, url=null, price=19 690 EUR]
And another one with values like this:
SearchResult2 [title=Ford Car, url=http://www.something.com, price=null]
How can i combine those 2 arrays into one with values like this:
SearchResult3 [title=Ford Car, url=http://www.something.com, price=19 690 EUR]
This is the code so far:
public List searchMethod() {
try {
final String query = "ford";
final Document page = Jsoup.connect("link" + URLEncoder.encode(query, "UTF-8")).userAgent(USER_AGENT).get();
List<SearchResult> resultList1 = new ArrayList<SearchResult>();
List<SearchResult> resultList2 = new ArrayList<SearchResult>();
List<SearchResult> resultList3 = new ArrayList<SearchResult>();
for(Element searchResult : page.select(".offer-price")) {
String price = searchResult.text();
resultList1.add(new SearchResult(price));
}
for(Element searchResult : page.select(".offer-title__link")) {
String title = searchResult.text();
String url = searchResult.attr("href");
resultList2.add(new SearchResult(title, url));
}
resultList3.addAll(resultList1);
resultList3.addAll(resultList2);
return resultList3;
}catch(Exception e) {
e.printStackTrace();
}
return Collections.emptyList();
}
The values that i put in those arrays are extracted from a web page
Thanks for helping!
From the comment, you have said that you just want to correlate/merge the objects from both lists by each index.
You can simply loop through the list, constructing a new SearchResult (assuming you have getters for the fields)
for(int i = 0; i < resultList1.size(); i++) {
resultList3.add(new SearchResult(resultList1.get(i).getPrice(),
resultList2.get(i).getTitle(),
resultList2.get(i).getUrl()));
}
You may have to change the order of the passed arguments to the SearchResult constructor taking price, title and url as you haven't shown it.
why don't you do it in one shot?
List<SearchResult> resultList1 = new ArrayList<SearchResult>();
for(Element searchResult : page.select(".offer-title__link")) {
String title = searchResult.text();
String url = searchResult.attr("href");
resultList1.add(new SearchResult(title, url));
}
int index = 0;
for(Element searchResult : page.select(".offer-price")) {
String price = searchResult.text();
//since you have already assumed
//that price will come in the same order and title and url.
resultList1.get(index++).setPrice(price);
}
return resultList1;

Make custom code to reduce number of repetitive lines

I have to get 'tags' from the database and store them in an array so I could check if my document contains them. Due to the number of tag categories (customers, system_dependencies, keywords) I have multiple arrays to compare my document with. Is there an easy way to simplify and make my code look nicer?
This is my approach but it looks terrible with all the repetitive for loops.
ArrayList<String> KEYWORDS2 = new ArrayList<String>();
ArrayList<String> CUSTOMERS = new ArrayList<String>();
ArrayList<String> SYSTEM_DEPS = new ArrayList<String>();
ArrayList<String> MODULES = new ArrayList<String>();
ArrayList<String> DRIVE_DEFS = new ArrayList<String>();
ArrayList<String> PROCESS_IDS = new ArrayList<String>();
while (resultSet2.next()) {
CUSTOMERS.add(resultSet2.getString(1));
}
sql = "SELECT da_tag_name FROM da_tags WHERE da_tag_type_id = 6";
stmt = conn.prepareStatement(sql);
resultSet2 = stmt.executeQuery();
while (resultSet2.next()) {
SYSTEM_DEPS.add(resultSet2.getString(1));
}
while (resultSet.next()) {
String da_document_id = resultSet.getString(1);
String file_name = resultSet.getString(2);
try {
if(file_name.endsWith(".docx") || file_name.endsWith(".docm")) {
System.out.println(file_name);
XWPFDocument document = new XWPFDocument(resultSet.getBinaryStream(3));
XWPFWordExtractor wordExtractor = new XWPFWordExtractor(document);
//Return what's inside the document
System.out.println("Keywords found in the document:");
for (String keyword : KEYWORDS) {
if (wordExtractor.getText().contains(keyword)) {
System.out.println(keyword);
}
}
System.out.println("\nCustomers found in the document:");
for (String customer : CUSTOMERS) {
if (wordExtractor.getText().contains(customer)) {
System.out.println(customer);
}
}
System.out.println("\nSystem dependencies found in the document:");
for (String systemDeps : SYSTEM_DEPS) {
if (wordExtractor.getText().contains(systemDeps)) {
System.out.println(systemDeps);
}
}
System.out.println("Log number: " + findLogNumber(wordExtractor));
System.out.println("------------------------------------------");
wordExtractor.close();
}
As you can see there are 3 more to come and this doesn't look good already. Maybe there's a way to compare all of them at the same time.
I have made another attempt at this creating this method:
public void genericForEachLoop(ArrayList<String> al, POITextExtractor te) {
for (String item : al) {
if (te.getText().contains(item)) {
System.out.println(item);
}
}
}
Then calling it like so: genericForEachLoop(MODULES, wordExtractor);
Any better solutions?
I've got two ideas to shorten this: first of all you can write a general for-loop in a separate method that has an ArrayList as a parameter. Then you pass it each of your ArrayLists successively, which would mean that at least you do not have to repeat the for-loops. Secondly, you can create an ArrayList of type ArrayList and store your ArrayLists inside it. Then you can iterate over the whole thing. Only apparent disadvantage of both ideas (or a combination of them) would be, that you need to name the variable for your query string alike for the search of each ArrayList.
What you could do is use a Map and an enum like this:
enum TagType {
KEYWORDS2(2), // or whatever its da_tag_type_id is
CUSTOMERS(4),
SYSTEM_DEPS(6),
MODULES(8),
DRIVE_DEFS(10),
PROCESS_IDS(12);
public final daTagTypeId; // this will be used in queries
TagType(int daTagTypeId) {
this.daTagTypeId = daTagTypeId;
}
}
Map<TagType, List<String>> tags = new HashMap<>();
XWPFDocument document = new XWPFDocument(resultSet.getBinaryStream(3));
XWPFWordExtractor wordExtractor = new XWPFWordExtractor(document);
for(TagType tagType : TagType.values()) {
tags.put(tagType, new ArrayList<>()); // initialize
String sql = String.format("SELECT da_tag_name FROM da_tags WHERE da_tag_type_id = %d", tagType.daTagTypeId); // build query
stmt = conn.prepareStatement(sql);
resultSet2 = stmt.executeQuery();
while(resultSet2.next()) { // fill from DB
tags.get(tagType).add(.add(resultSet2.getString(1)));
}
System.out.println(String.format("%s found in the document:", tags.get(tagType).name());
for (String tag : tags.get(tagType)) { // search in text
if (wordExtractor.getText().contains(tag)) {
System.out.println(keyword);
}
}
}
But at this point I'm not sure you need those lists at all:
enum TagType {
KEYWORDS2(2), // or whatever its da_tag_type_id is
CUSTOMERS(4),
SYSTEM_DEPS(6),
MODULES(8),
DRIVE_DEFS(10),
PROCESS_IDS(12);
public final daTagTypeId; // this will be used in queries
TagType(int daTagTypeId) {
this.daTagTypeId = daTagTypeId;
}
}
XWPFDocument document = new XWPFDocument(resultSet.getBinaryStream(3));
XWPFWordExtractor wordExtractor = new XWPFWordExtractor(document);
for(TagType tagType : TagType.values()) {
String sql = String.format("SELECT da_tag_name FROM da_tags WHERE da_tag_type_id = %d", tagType.daTagTypeId); // build query
stmt = conn.prepareStatement(sql);
resultSet2 = stmt.executeQuery();
System.out.println(String.format("%s found in the document:", tags.get(tagType).name());
while(result2.next()) {
String tag = resultSet2.getString(1);
if (wordExtractor.getText().contains(tag)) {
System.out.println(keyword);
}
}
}
This given I don't know where those resultSet is declared and initialised, nor where that resultSet2 is initialised.
Basically you just fetch tags for each type from DB and then directly search them in the text without storing them at first and then re-iterating the stored ones... I mean that's what the DB is there for.

Ldap modify Attribute Java

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);
}
}

Using Java need to create a hashmap that is populated with data from a file

I am trying to figure out a way to iterate through a file and generate a new hashset based on the first column. The value in the first column will server as the key in a hashmap. So for example, say I have a file that contains the following:
element1 value1
element1 value2
element1 value3
element2 value1
element2 value2
I need to have a hashmap with a key of element1 and values of value1 value2 and value3. The next key will be of element2 and values of value1 and value2. Use of the hashset of type User is required.
I can get through element1 and populate it fine. But when it gets to element2 I am not sure how to grab that information without erasing the entire hashset. Or what would be the best way to generate a new hashset dynamically as the values of the file are not static.
Of course any help will be appreciated.
`
public class User {
public T Username;
String key = null;
public HashSet<User> friends = new HashSet<User>();
public HashSet<User> temps = new HashSet<User>();
HashMap<String, HashSet<User>> map = new HashMap<String, HashSet<User>>();
public HashSet readFile(){
String temp = null;
try
{
File f = new File("file.txt");
Scanner input = new Scanner(f);
String line = null;
line = input.nextLine();
int count = 0;
while (input.hasNextLine()){
String parts[] = line.split("\t");
temp = parts[0];
if(!parts[0].equals(temp)){
friends.add(new User(parts[1]));
map.put(parts[0], friends);
//here I had friends.clear(); thinking to clear out
//the set and start to populate with the values
//of new hashset but it clears set for all keys.
}else if(parts[0].equals(temp)){
friends.add(new User(parts[1]));
map.put(temp, friends);
}
temp = parts[0];
line = input.nextLine();
}
}
catch (FileNotFoundException e){
System.out.println("File not found");
}
return friends;
}
public void setKey(String fKey){
key = fKey;
//return key;
}
public static void outputSet(HashSet<User> set){
Iterator<User> i = set.iterator();
while (i.hasNext()){
System.out.print(i.next() + " ");
}
System.out.println();
}
public void buildMap(String fKey, HashSet<User> mappy){
map.put(fKey, mappy);
System.out.println(map);
}
#Override
public String toString() {
return ("" + Username +"");
}
}
`
It looks like you want friends = new HashSet<User>(); instead of friends.clear() to create a new list. But this code is really messy, I suggest you head over to Code Review to get help with cleaning it.

Categories