Ok, this is driving me crazy. I'm trying to create an LDAP authentication with Java and everything is fine if I use my First name and Last name in the SECURITY_PRINCIPAL. This is my code:
try {
Hashtable<String, String> ldapEnv = new Hashtable<String, String>();
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, "LDAP://myldap.mydomain.com:389");
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, "CN=FirstName LastName" + ",ou=Users");
ldapEnv.put(Context.SECURITY_CREDENTIALS, "password");
DirContext ldapContext = new InitialLdapContext(ldapEnv, null);
}
catch (Exception e) {
System.out.println(" bind error: " + e);
e.printStackTrace();
}
The problem is that it does not work with my username. If I try:
ldapEnv.put(Context.SECURITY_PRINCIPAL, "CN=myusername" + ",ou=Users");
Or
ldapEnv.put(Context.SECURITY_PRINCIPAL, "uid=myusername" + ",ou=Users");
I always get [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1]
This only seems to work with my First name and Last name for some reason. I checked the AD and my sAMAccountName is my correct username. Not sure why this is happening. Anyone else had such issues? Can I pass something else to Context.SECURITY_PRINCIPAL? I tried ldapEnv.put(Context.SECURITY_PRINCIPAL, "sAMAccountName=myusername" + ",ou=Users"); but it also fails... Can anyone please help?
EJP, thanks for your input. You are indeed correct but I was looking for something simple - just pass a username and password to the AD and see if it authenticates or not .I should have been more specific in my first post. Your suggestion will work but I think this is much simpler:
Hashtable props = new Hashtable();
String principalName = "username#mydomain.com";
props.put(Context.SECURITY_PRINCIPAL, principalName);
props.put(Context.SECURITY_CREDENTIALS, "mypassword");
DirContext context;
//try to authenticate
try {
context = com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance("LDAP://myldap.mydomain.com:389" + '/', props);
context.close();
}
This way I don't care about the DN. Just passing the username#domain and voila - works like a charm :) Thanks again!
There is no entry whose DN contains a UID or CN=username. You have to provide an entry which exists, not just an arbitrary string of attributes. The usual technique is to bind as an admin user, search for the user who has that UID or whatever he provided to your login system, retrieve the DN of that user, then try to bind as that DN with the user-supplied password.
Related
First i want to explain what i want to do and how the code is looking:
I want to add a User via JNDI on my LDAP with JAVA, i added following code:
public void addUser(String firstName, String lastName, String number) throws NamingException {
Properties initialProperties = new Properties();
initialProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
initialProperties.put(Context.PROVIDER_URL, "***");
initialProperties.put(Context.SECURITY_AUTHENTICATION, "simple");
initialProperties.put(Context.SECURITY_PRINCIPAL, "***");
initialProperties.put(Context.SECURITY_CREDENTIALS, "***");
DirContext context = new InitialDirContext(initialProperties);
BasicAttributes attributes = new BasicAttributes();
Attribute attribute = new BasicAttribute("objectClass");
attribute.add("top");
attribute.add("person");
attribute.add("organizationalPerson");
attribute.add("inetOrgPerson");
Attribute sn = new BasicAttribute("sn");
Attribute cn = new BasicAttribute("cn");
sn.add(lastName);
cn.add(firstName);
attributes.put(sn);
attributes.put(cn);
attributes.put(attribute);
try {
context.createSubcontext("***", attributes);
} catch(NamingException e) {
e.printStackTrace();
}
}
When i call the method i get following error:
javax.naming.NoPermissionException: [LDAP: error code 50 - 00000005: SecErr: DSID-031528D2, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
Which makes no sense in my point of view because i created two other methods, one for getting all the users which works and one for editing a user which works too, so i have the rights to read and write a user, but when i want to create a user it says i have no permission ?
Do anyone else had this problem?
Is there any configuration on the Administrator user necessary on the LDAP? But the Administrator should be have all rights?
I hope anyone can help me! :)
Greetings,
Fabian.
so i have the rights to read and write a user, but when i want to create a user it says i have no permission
Read, write and create are 3 separate permissions. A user can have write permissions to existing objects, but not have permission to create a new object. Those permissions can be set differently on each OU.
I'd like to be ask an LDAP server if the provided username and password are correct in a Java application.
I ended up using jndi with this function (it is a test function I am using to explore LDAP that returns the exception message):
public static String checkCredentials(String securityPrincipal,
String password,
String ldapUrl,
String securityAuthentication)
{
String userVerify = "";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapUrl);
env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
env.put(Context.SECURITY_PRINCIPAL, securityPrincipal);
env.put(Context.SECURITY_CREDENTIALS, password);
try {
DirContext authContext = new InitialDirContext(env);
userVerify = testDescription + " - Success";
authContext.close();
} catch (AuthenticationException authEx) {
userVerify = "AuthenticationException: " + authEx.getMessage();//"Authentication failed!";
} catch (NamingException namEx) {
userVerify = "NamingException: " + namEx.getMessage();//"Something went wrong!";
}
return userVerify;
}
As I call checkCredentials by passing the correct ldapUrl (that in my case it's ldap://192.168.48.60:389) i always get as result (the function returns a String):
AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr:
DSID-0C0903A8, comment: AcceptSecurityContext error, data 52e, v1db1]
This page says that it is an authentication error (49) and "username is valid but password/credential is invalid" (52e).
I tried all of these for securityPrincipal:
john
john#mycompany
CN=john,conn
CN=john,OU=internal users,DC=mycompany
password and secuirityAuthentication seem ignored.
I tried to install LDAP admin from http://www.ldapadmin.org/ and also from it I get:
LDAP error! Invalid credentials: 80090308: LdapErr: DSID-0C0903A8,
comment: AcceptSecurityContext error, data 52e, v1db1.
Invalid token passed to the function.
Somehow this tells me something more "invalid token".
Any pointers? I am stuck.
Passing "none" instead of "simple" in securityAuthentication made the job.
At least there are no exceptions, even if UserVerifyT returns success even if the passowrd is wrong, i will handle this as i did in the past by retrieving the mail of the user, if mail is returned password is ok.
I'm working with Openfire and XMPP. My problem is: whenever I want to sign someone up I need to log into Openfire, like this.
connection.login(Username, Password);
AccountManager accountManager = AccountManager.getInstance(connection);
accountManager.createAccount(Username1, Password1);
So, how can I avoid this useless login?
Thank you.
You have to split login functionality from createAccount().
You must connect on Openfire server (without provide user and password), then ask for createAccount
//...connection builder
connection.connect();
AccountManager.getInstance(connection).sensitiveOperationOverInsecureConnection(true);
username = username.toLowerCase();
Map<String,String> attributes = new HashMap<String, String>(2);
attributes.put("name", fullName);
attributes.put("email", email);
AccountManager.getInstance(connection).createAccount(username, password, attributes);
//now you can do connection.login(username,password)
We have a couple of sites that use our company AD.
Currently in order to login we have to use the following
iuser\userid
with the code:
Hashtable<String, String> config = new Hashtable<String, String>();
config.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
config.put("java.naming.provider.url", ldapUrl);
config.put("java.naming.security.authentication", "simple");
config.put("java.naming.security.principal", "iuser\\" + username);
config.put("java.naming.security.credentials", password);
InitialDirContext dirCxt = new InitialDirContext(config);
However when we go to search the AD we can only use just the userid
SearchControls cons = new SearchControls();
cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> resultsEnum =
derek.search("dc=iuser,dc=example,dc=example,dc=com", "(&(objectCategory=user)(cn={0}))", new Object[] {username}, cons);
When we try to create the InitialDirContext without putting the domain first then we get User not found response
Is there a way of creating the InitialDirContext without having to put our domain infront of the username?
While I would recommend you to rather use Kerberos. You should try the global catalog and not use commonName but rather a unique attribute like userPrincipalName or aAMAccountName.
I'm currently working on a app that contains official employees information even the login.
I would like to do an LDAP search filter that retrieve for me all the information concerning specific users that corresspond to a list of logins I provide.
A bit like a select statement in sql : select * from ldap where login in(my list of login)
I'm using the basic javax.naming.directory with all the blah blah comming with.
// set properties for our connection and provider
Properties properties = new Properties();
properties.put( Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory" );
properties.put( Context.PROVIDER_URL, "ldap://myserver.somewhere.com:389"; );
properties.put( Context.REFERRAL, "ignore" );
// set properties for authentication
properties.put( Context.SECURITY_PRINCIPAL, "User Name" );
properties.put( Context.SECURITY_CREDENTIALS, "password" );
InitialDirContext context = new InitialDirContext( properties );
The only thing I could do so far is lising all the object users if I could get directly those I'm looking for that could be very nice :)
Thanks a lot for your help guys :)
String searchFilter = "your_query";
String ldapSearchBase = "dc=ad,dc=my-domain,dc=com"
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> results = context.search(ldapSearchBase, searchFilter, searchControls);
an query might be like this:
(&(objectClass=user)(sAMAccountName=" + accountName + "))
complete example here:
http://www.adamretter.org.uk/blog/entries/LDAPTest.java
So the final query in the search filter I had to put is :
(&(objectCategory=person)
(|
(sAMAccountName=login1)
(sAMAccountName=login2)
(sAMAccountName=login3)
)
)
Thanks for you help :)