Ldap search by email value can't find records - java

I have written a Java application that searches Active directory via LDAP for user information. I have a list of instances of custom Person class that is passed in. In it I have either DN or email defined. I am modifying the search criteria accordingly. Here is the code:
for (Person person : members) {
boolean ready = false;
String filter = getConfig().getUserSearchFilter();
// (&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson)))
String base = person.getDistinguishedName();
if (base != null && !base.isEmpty()) {
ready = true;
} else if (person.getEmail() != null) {
base = getConfig().getMemberSearchBase();
// ou=Users,ou=Managed,dc=division,dc=company,dc=com
String mail = person.getEmail();
StringBuilder filterBuilder = new StringBuilder(filter);
int pIdx = filterBuilder.lastIndexOf(")");
filterBuilder.insert(pIdx, "(|(mail=" + mail + ")(x-personalmail=" + mail + "))");
filter = filterBuilder.toString();
LOG.debug("New value of a filter = {}", filter);
ready = true;
}
if (ready) {
try {
NamingEnumeration<SearchResult> search = getContext().search(base, filter, searchControls);
...
} catch (NamingException nex) {
throw new IOException(nex);
}
} else {
LOG.error("Incorrect search criteria for user {} of group {}. Person skipped", person.getName(), this.group.getName());
}
}
Code is working without errors, but when DN is specified it does find a person, but when email is defined it finds nothing.
However, If I copy generated filter string and pass it to ldapsearch command in a form of:
ldapsearch -LLL -x -H ldaps://my.ldap.server.com -D 'svc-acct#corp-dev.company.com' -W -b "ou=Users,ou=Managed,dc=division,dc=company,dc=com" '(&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson))(|(mail=person#domain.com)(x-personalmail=person#domain.com)))'
It does find this person perfectly.
Did anyone faced similar problem? Do you see any flaws in my code?
Please, do help me.

I did find the cause of my problem.
In the search control I had scope defined as OBJECT_SCOPE.
It does work when you are specifying DN, but with the search per one of the fields it fails finding the object.
I changed the scope to SUBTREE_SCOPE and everything started working as expected.

Related

Performing DNS "ANY" Lookup using Java JNDI

I am using Java JNDI to perform DNS lookups using the following basic syntax as per the SSCCE below, but I am trying to query all records using the "ANY" attribute:
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
public class SSCCE {
public static void main(String[] args) {
try {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
InitialDirContext idc = new InitialDirContext(p);
Attributes attrs = idc.getAttributes("netnix.org", new String[] { "* *" });
Attribute attr = attrs.get("* *");
if (attr != null) {
for (int i = 0; i < attr.size(); i++) {
System.out.println("Found " + (String)attr.get(i));
}
}
else {
System.out.println("Found nothing");
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
My question is around being able to query a resource type of "ANY" which should return all the DNS resource records associated with a specific domain - example below using the "host" utility.
chrixm#puffy(:):~$ host -t ANY netnix.org
netnix.org has SPF record "v=spf1 include:_spf.google.com ~all"
netnix.org mail is handled by 10 aspmx2.googlemail.com.
netnix.org mail is handled by 5 alt1.aspmx.l.google.com.
netnix.org mail is handled by 1 aspmx.l.google.com.
netnix.org mail is handled by 5 alt2.aspmx.l.google.com.
netnix.org mail is handled by 10 aspmx3.googlemail.com.
netnix.org name server ns-1154.awsdns-16.org.
netnix.org name server ns-941.awsdns-53.net.
netnix.org name server ns-61.awsdns-07.com.
netnix.org name server ns-1880.awsdns-43.co.uk.
I have read http://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-dns.html, which says:
Superclass attribute identifiers are also defined. These may be useful when querying records using the DirContext.getAttributes() method. If an attribute name has "*" in place of a type name (or class name), it represents records of any type (or class). For example, the attribute identifier "IN *" may be passed to the getAttributes() method to find all internet class records. The attribute identifier "* *" represents records of any class or type.
However, Java JNDI doesn't understand a resource record of "*" or "* *" as the above code doesn't return any records (I am able to query "NS" or "SOA", etc individually) - has anyone had any experience of getting this working. I can of course query each individual resource type, but considering there is a valid record type of "ANY" as per RFC 1035 (Type ID 255) this seems very inefficient?
After examining the methods of the Attributes class I noticed a getAll() method. After further searching I was able to implement the following which now allows you to search using "*" as the record type and print all the records.
Attributes attrs = idc.getAttributes("netnix.org", new String[] { "*" });
NamingEnumeration<?> ae = attrs.getAll();
while (ae.hasMore()) {
Attribute attr = (Attribute)ae.next();
for (int i = 0; i < attr.size(); i++) {
Object a = attr.get(i);
if (a instanceof String) {
System.out.println(attr.getID() + " " + a);
}
else {
System.out.println(attr.getID() + " NOT ASCII");
}
}
}
ae.close();
You're inventing semantics here. There is no support anywhere in JNDI for "* *" as either an attribute set or an attribute name. The correct syntax for 'all attributes' as an attribute set to return is "*", and the correct way to enumerate them all is via Attributes.getAll().

"Cast" a String Attribute to String Java [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I have a little problem with Attributes. I am currently working on a project that parses emails from an LDAP server into the Java application that will be doing some interesting stuff with emails in the future.
I am currently having this code that takes emails from users on LDAP and it needs to put emails in the User class as seen in my code:
[some code here, TRY CATCH is also included]
LdapContext ctx = new InitialLdapContext(env, null);
ctx.setRequestControls(null);
NamingEnumeration<?> namingEnum2 = ctx.search("[path to the server]", "(objectClass=user)", getSimpleSearchControls());
System.out.println("Test: print emails from whole DIRECOTRY: \n");
while (namingEnum2.hasMore()) {
SearchResult result = (SearchResult) namingEnum2.next();
Attributes attrs = result.getAttributes();
System.out.println(attrs.get("mail"));
/** This line above works fine, but every time there is no email
in User info, it prints "null" in some cases when there is
no email, which is not perfect. But this is just here to see
if everything works and indeed it does.**/
/**User Class accepts a String parameter, checks if it's empty
and all that, does some checking and etc... BUT! attrs.get("mail")
is an Attribute, NOT a String. And I need to somehow "cast" this
attribute to a String, so I can work with it.**/
User user = new User(attrs.get("mail")); //error yet,because the parameter is not a String.
User user = new User(attrs.get("mail").toString());//gives an expeption.
/** And I know that there is a toString() method in Attribute Class,
but it doesn't work, it gives an "java.lang.NullPointerException"
exception when I use it as attrs.get("mail").toString() **/
}
Here is User class's constructor:
public User(String mail){
eMail = "NO EMAIL!";
if (mail != null && !mail.isEmpty()){
eMail = mail;
}
else
{
eMail = "NO EMAIL!";
}
}
try this
User user = new User(attrs.get("mail")!=null?attrs.get("mail").toString():null);
First you need to check that given attribute exists by using != null (e.g. using Objects.toString which does that inside, or manual if) check, and then use either toString on the Attribute, just like println does inside:
User user = new User(Objects.toString(attrs.get("mail")));
Or you can also use (to retrieve a single value in the attribute, if you have many you need to use getAll):
Object mail = null;
if (attrs.get("mail") != null) {
mail = attrs.get("mail").get();
}
User user = new User(mail.toString());

Java - LDAP: Attribute is Read-Only

I am using UnboundID-LDAPSDK (2.3.8) to change the user's photo in our Microsoft Active Directory.
LDAPConnection ldap = null;
try {
ldap = new LDAPConnection("domain-srv", 389, "CN=admin,OU=Users,OU=ADM,DC=domain,DC=local", "password");
SearchResult sr = ldap.search("DC=domain,DC=local", SearchScope.SUB, "(sAMAccountName=" + getUser().getUsername() + ")");
if (sr.getEntryCount() == 1) {
SearchResultEntry entry = sr.getSearchEntries().get(0);
entry.setAttribute("thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.close();
return true;
} else
return false;
} catch (LDAPException e) {
e.printStackTrace();
}
But I get a java.lang.UnsupportedOperationException.
The documentation for setAttribute states:
Throws an UnsupportedOperationException to indicate that this is a
read-only entry.
I also tried to change the postalCode but I get the same exception.
Changing those attributes should be possible, because I can change them with jXplorer.
Do I have to enable a write-mode somehow?
Thank you
The SearchResultEntry object extends ReadOnlyEntry and is therefore immutable. But even if it weren't, merely calling entry.setAttribute would have no effect on the data in the server. You have to use a modify operation for that.
To do that, you'd need something like:
ModifyRequest modifyRequest = new ModifyRequest(entry.getDN(),
new Modification(ModificationType.REPLACE,
"thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.modify(modifyRequest);
Also, you should put the call to ldap.close() in a finally block because as the code is written now, you're only closing the connection if the search is successful and returns exactly one entry, but not if the search fails, doesn't match any entries, or the attempt to perform the modify fails.

Retrieving user object by ID

I still can't work with GAE's keys/ids. I keep getting the error: No entity was found matching the key: Key(Medewerker(5201690726760448)). The entities exist in the datastore, I checked this multiple times.
I'm trying to just simply get an user object with a certain ID. In my servlet I have the following code:
Long userId = Long.parseLong(req.getParameter("user"));
User user = userDao.getUser(userId);
The above code brings up the error. In userDaoOfyImpl.java I have the following method 'getUser':
public Gebruiker getGebruiker(Long id) {
Gebruiker result = null;
Gebruiker leerling = (Gebruiker) ofy.get(Leerling.class, id);
Gebruiker medewerker = (Gebruiker) ofy.get(Medewerker.class, id);
Gebruiker stagebedrijf = (Gebruiker)ofy.get(StageBedrijf.class, id);
//Gebruiker instantie returnen
if(leerling != null) {
result = leerling;
} else if(medewerker != null) {
result = medewerker;
} else if(stagebedrijf != null) {
result = stagebedrijf;
}
return result;
}
The variables are dutch but I think you guys know the idea. The above method searches in different classes looking for a user that matches the ID and then returns it.
The problem is I get the error shown above and I'm really getting frustrated, what am I doing wrong guys? Is it the method or the way I use ID's or...?
Thanks in advance!
here you can read for the get method:
Throws: NotFoundException - if the key does not exist in the datastore
use
Gebruiker leerling = (Gebruiker) ofy.find(Leerling.class, id);
the find method doesn't throws NotFoundException when the key doesn't exist but null.

Controlling the list of URL(s) to be crawled at runtime

In crawler4j we can override a function boolean shouldVisit(WebUrl url) and control whether that particular url should be allowed to be crawled by returning 'true' and 'false'.
But can we add URL(s) at runtime ? if yes , what are ways to do that ?
Currently I can add URL(s) at beginning of program using addSeed(String url) function before the start(BasicCrawler.class, numberOfCrawlers) in CrawlController class and if I try to add new url using addSeed(String url), it gives error. Here is error image .
Any help will be appreciative and please let me know if any more detail about project is required to answer the question .
You can do this.
Use public void schedule(WebURL url) to add URLs to the crawler frontier which is a member of the Frontier.java class. But for this you need to have your url of type WebURL. If you want to make a WebURL out of your string. Please have a look at the addSeed() (below code) which is in the CrawlController.java class to see how it has converted the string (url) into a WebURL.
Also use the existing frontier instance.
Hope this helps..
public void addSeed(String pageUrl, int docId) {
String canonicalUrl = URLCanonicalizer.getCanonicalURL(pageUrl);
if (canonicalUrl == null) {
logger.error("Invalid seed URL: " + pageUrl);
return;
}
if (docId < 0) {
docId = docIdServer.getDocId(canonicalUrl);
if (docId > 0) {
// This URL is already seen.
return;
}
docId = docIdServer.getNewDocID(canonicalUrl);
} else {
try {
docIdServer.addUrlAndDocId(canonicalUrl, docId);
} catch (Exception e) {
logger.error("Could not add seed: " + e.getMessage());
}
}
WebURL webUrl = new WebURL();
webUrl.setURL(canonicalUrl);
webUrl.setDocid(docId);
webUrl.setDepth((short) 0);
if (!robotstxtServer.allows(webUrl)) {
logger.info("Robots.txt does not allow this seed: " + pageUrl);
} else {
frontier.schedule(webUrl); //method that adds URL to the frontier at run time
}
}
Presumably you can implement this function however you like, and have it depend on a list of URLs that should not be crawled. The implementation of shouldVisit is then going to involve asking if a given URL is in your list of forbidden URLs (or permitted URLs), and returning true or false on that basis.

Categories