Changing Distinguished Name Using Java Naming - java

I am Trying to Change The Group Distinguished name using Java Naming Package
but every Time i get the same error message
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, user);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.REFERRAL, "follow");
DirContext ctx = new InitialDirContext(env);
ModificationItem[] roleMods = new ModificationItem[]
{
new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("distinguishedName",DN2))
};
ctx.modifyAttributes(DN1,roleMods);
And Every time i get this error :
Exception in thread "main" javax.naming.directory.InvalidAttributeValueException: [LDAP: error code 19 - 000020B1: AtrErr: DSID-030F04A3, #1:
0: 000020B1: DSID-030F04A3, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 31 (distinguishedName)
Is it at all posibble to change DN if yes how should i do it ?

In general, renaming in LDAP is not a modification as the change applies to the DN (distinguished name). You more often find examples when you look for rename or the modify DN / modify RDN operation.
Here is an example how to do renames using the JNDI LDAP provider.
I hope this helps.

Related

How to authorize an user against ldap group

I am writing a little tool, which can execute some operations within ldap (e.g. create user, delete user, assign user to group, read specific attributes, etc.) That works perfect.
Now I want to add a little security aspect. Only some users are allowed to execute these operations. That's why I want to check first, if the user who wants to do the executions is in a specific ldap-group (e.g. administrators). If the user is not in this group, he should get a message ("your are not authorized").
My standard login is like described everywhere:
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, LDAP_SERVER_URL + ":" + LDAP_PORT + "/" + LDAP_BASE_DN);
if (LDAP_SERVER_URL.startsWith("ldaps")) {
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put("java.naming.ldap.factory.socket", "com.ibm.devopscoc.ldap.util.LdapSSLSocketFactory");
InputStream truststoreStream = LdapSSLSocketFactory.class.getResourceAsStream("truststoreldap.jks");
LdapSSLSocketFactory.init(null, null, null, truststoreStream, "<password>", "JKS");
}
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, probs.getAdminName());
env.put(Context.SECURITY_CREDENTIALS, probs.getAdminPassword());
env.put(Context.REFERRAL, "follow");
Where do I have to specify the group?
Thanks in advance.

A hard quеstion: why javax.naming.AuthenticationException in this Java code? [duplicate]

LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1
I know "52e" code is when username is valid, but password is invalid. I am using the same user name and password in my apache studio, I was able to establish the connection succesfully to LDAP.
Here is my java code
String userName = "*******";
String password = "********";
String base ="DC=PSLTESTDOMAIN,DC=LOCAL";
String dn = "cn=" + userName + "," + base;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://******");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, dn);
env.put(Context.SECURITY_CREDENTIALS, password);
LDAPAuthenticationService ldap = new LDAPAuthenticationService();
// LdapContext ctx;
DirContext ctx = null;
try {
ctx = new InitialDirContext(env);
My error is on this line: ctx = new InitialDirContext(env);
I do not know what exactly is causing this error.
data 52e - Returns when username is valid but password/credential is invalid.
You probably need something like
String dn = "cn=" + userName + "," + "CN=Users," + base;
For me the issue resolved when I set the principal section like this:
env.put(Context.SECURITY_PRINCIPAL, userId#domainWithoutProtocolAndPortNo);
52e 1326 ERROR_LOGON_FAILURE Returns when username is valid but password/credential is invalid. Will prevent most other errors from being displayed as noted.
http://ldapwiki.com/wiki/Common%20Active%20Directory%20Bind%20Errors
In my case I have to use something like <username>#<domain> to successfully login.
sample_user#sample_domain
When you use Context.SECURITY_AUTHENTICATION as "simple", you need to supply the userPrincipalName attribute value (user#domain_base).
I had a similar issue when using AD on CAS , i.e. 52e error, In my case application accepts the Full Name when in the form of CN= instead of the actual username.
For example, if you had a user who's full name is Ross Butler and their login username is rbutler --you would normally put something like, cn=rbutler,ou=Users,dc=domain,dc=com but ours failed everytime. By changing this to cn=Ross Butler,ou=Users,dc=domain,dc=com it passed!!
For me the issue is resolved by adding domain name in user name as follow:
string userName="yourUserName";
string password="passowrd";
string hostName="LdapServerHostName";
string domain="yourDomain";
System.DirectoryServices.AuthenticationTypes option = System.DirectoryServices.AuthenticationTypes.SecureSocketsLayer;
string userNameWithDomain = string.Format("{0}#{1}",userName , domain);
DirectoryEntry directoryOU = new DirectoryEntry("LDAP://" + hostName, userNameWithDomain, password, option);
if you debug and loook at ctx=null,maybe your username hava proble ,you shoud write like
"ac\administrator"(double "\") or "administrator#ac"
For me the cause of the issue was that the format of username was incorrect. It was earlierly specified as "mydomain\user". I removed the domain part and the error was gone.
PS I was using ServerBind authentication.
LDAP is trying to authenticate with AD when sending a transaction to another server DB. This authentication fails because the user has recently changed her password, although this transaction was generated using the previous credentials. This authentication will keep failing until ... unless you change the transaction status to Complete or Cancel in which case LDAP will stop sending these transactions.
For me issue is resolved by changing envs like this:
env.put("LDAP_BASEDN", base)
env.put(Context.SECURITY_PRINCIPAL,"user#domain")
Using domain Name may solve the problem (get domain name using powershell: $env:userdomain):
Hashtable<String, Object> env = new Hashtable<String, Object>();
String principalName = "domainName\\userName";
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://URL:389/OU=ou-xx,DC=fr,DC=XXXXXX,DC=com");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, principalName);
env.put(Context.SECURITY_CREDENTIALS, "Your Password");
try {
DirContext authContext = new InitialDirContext(env);
// user is authenticated
System.out.println("USER IS AUTHETICATED");
} catch (AuthenticationException ex) {
// Authentication failed
System.out.println("AUTH FAILED : " + ex);
} catch (NamingException ex) {
ex.printStackTrace();
}
I've tested three diferent approaches and them all worked:
env.put(Context.SECURITY_PRINCIPAL, "user");
env.put(Context.SECURITY_PRINCIPAL, "user#domain.com");
env.put(Context.SECURITY_PRINCIPAL, "CN=user,OU=one,OU=two,DC=domain,DC=com");
If you use the last one, don't forget to set all the OU's where the user belongs to. Otherwise it won't work.
In my case I misconfigured email credentials then I corrected
var passport = require('passport'),
WindowsStrategy = require('passport-windowsauth'),
User = require('mongoose').model('User');
module.exports = function () {
passport.use(new WindowsStrategy({ldap: {
url: 'ldap://corp.company.com:389/DC=corp,DC=company,DC=com',
base: 'DC=corp,DC=company,DC=com',
bindDN: 'myid#corp.company.com',
bindCredentials:'password',
tlsOptions: {
ca: [fs.readFileSync("./cert.pem")],
},
}, integrated: false},
function(profile, done) {
console.log('Windows');
console.log(profile);
User.findOrCreate({
username: profile.id
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown user'
});
}
if (!user.authenticate(password)) {
return done(null, false, {
message: 'Invalid password'
});
}
return done(null, user);
});
}));
};
Please remove domain from the username "mydomain\user". please put "user" only. do not put domain and backslash .
You do not use ldaps://examplehost:8080(do not use s with ldaps coz cert is required), use ldap://examplehost:8080 then use non-TLS port number. it worked for me.

Java Active Directory query returning incomplete user list

I want to list all AD users in Java. I'm using this code:
String ldapUri = "ldap://" + serverName;
LdapContext ctx = null;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
//it can be <domain\\userid> something that you use for windows login
//it can also be
env.put(Context.SECURITY_PRINCIPAL, adminName);
try {
env.put(Context.SECURITY_CREDENTIALS, adminPass.getBytes("UTF8"));
env.put(Context.REFERRAL, "follow");
} catch (java.io.UnsupportedEncodingException e) {
log.error("Non-Fatal exception : ", e);
/* ignore */
}
//in following property we specify ldap protocol and connection url.
//generally the port is 389
env.put(Context.PROVIDER_URL, ldapUri);
log.info("AD Server: " + ldapUri + ", admin " + adminName);
ctx = new InitialLdapContext(env, null);
DirContext ctx1 = new InitialDirContext(env);
SearchControls ctls = new SearchControls();
String[] attrIDs = {"distinguishedName", "cn", "name", "uid",
"sn",
"name",
"memberOf",
"displayName",
"userPrincipalName"};
ctls.setReturningAttributes(attrIDs);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration answer = ctx1.search(searchPath, "(&(objectClass=user)(objectCategory=person))", ctls);
while (answer.hasMoreElements()) {
// Process user
SearchResult rslt = (SearchResult) answer.next();
}
The code works fine in most environments but there is a customer that reports that some users are missing. I've tried to troubleshoot it but the user aren't listed but they are listed using Active Directory admin or Active Directory Explorer.
Any ideas?
I assume that account you are using has enough permissions. As far as I recall any instance of domain controller will return 1000 objects by default. It is very likely you are running into this situation. You have to use LDAP pagination In order to solve this problem. Take a look into JNDI page controls - https://docs.oracle.com/javase/tutorial/jndi/newstuff/paged-results.html.
Also, take a look into JNDI code samples from Java forum - https://community.oracle.com/thread/1157644?tstart=0.
Hope this helps.
Besides making sure that you don't hit any query limits you should consider that some of your customers might run a more complex Active Directory setup.
This might involve multiple domains. In order to address those you need to connect to the global catalog. You do so by binding to port 3268.
You should either make this your standard way of connecting or make this configurable by an administrator at your customers site.
Read more about this at Microsoft: https://technet.microsoft.com/de-de/library/cc978012.aspx

How to find out the right ldap parameters

I'm currently working on a small project with Active Directory and some LDAP stuff...
I try to connect to the LDAP server and it always gives me the same error:
[LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1
As much as I know this means that the credentials are wrong, but I'm 100% sure that they're right!
Could it be that I forgot a parameter?
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://libertycity.ch:389/dc=libertycity,dc=ch");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.SECURITY_PRINCIPAL, "uid=" + username + ",ou=Users");
env.put("java.naming.ldap.attributes.binary", "objectSID");
DirContext ctx = new InitialDirContext(env);
I think my code looks right, or did I miss something? What could be the problem and how can I find that out?
The value, "data 52e", provided in the error implies the bind failed due to:
Returns when username is valid but password/credential is invalid.
http://ldapwiki.com/wiki/Common%20Active%20Directory%20Bind%20Errors
This problem may also arise if the full domain is not included with the user name.
Set the security principal as username#domain.
InitialLdapContext ldapContext = new InitialLdapContext();
ldapContext.addToEnvironment(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, userId + "#mydomain.com");
ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
ldapContext.addToEnvironment(Context.PROVIDER_URL, "ldap://" + ldapHost + ":" + ldapPort);
I have had the issues trying to secure a connection from wildfly to an Microsoft active directory server, the main problem is not knowing what connection string should be.
If you install the 'Active Directory Explorer' from Sysinternals took kit provided by Microsoft. Search for the object that you wish to bind to, a 'Path:' setting will be displayed. That is the string of values that you need to quote in the argument to the Context.SECURITY_PRINCIPAL value.
In my case the path string was of the format
CN=Fred Blogs,OU=XXX Users,DC=foo-bar,DC=com,xxx.foo-bar.com:389 [xxx.foo-bar.com]]
The required argument would be
"CN=Fred Blogs,OU=XXX Users,DC=foo-bar,DC=com"
Please note that spaces are very important
LDAP error code 49 indicates "Invalid credentials" which means the password you sent to the LDAP server was not correct.
Active Directory: Check your Domain Containers.
I had the same error working on a migration from eDirectory to Active Directory, the user name and password seemed to be correct but for some reason i was still getting the "52e" error which indicates the password is not correct.
I had to add the DC's (Domain Containers) to the principal to make it work:
This wasn't working:
env.put(Context.SECURITY_PRINCIPAL, "CN="+username+",OU=Users,OU=Org,OU=ETC");
Adding the DCs: (This worked for me)
env.put(Context.SECURITY_PRINCIPAL, "CN="+username+",OU=Users,OU=Org,OU=ETC,DC=yourorg,DC=com");
This solved the problem to me for Active Directory.
Something that really helped my to solve this issue was trying to bind using the linux ldapbind / ldapsearch command https://docs.oracle.com/cd/B10501_01/network.920/a96579/comtools.htm.
if you make it work from the OS using ldapbind / ldapsearch commands then you will know what exact parameters you should use in your code.
DirContext ldapContext;
Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
//ldapEnv.put(Context.PROVIDER_URL, "ldap://societe.fr:389");
ldapEnv.put(Context.PROVIDER_URL, "ldap://10.112.115.14:389");
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, "vmware-china#viewconnection.com");
ldapEnv.put(Context.SECURITY_CREDENTIALS, "ca$hc0w");
//ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
//ldapEnv.put(Context.SECURITY_PROTOCOL, "simple");
ldapContext = new InitialDirContext(ldapEnv);
System.out.println(ldapContext);
// Create the search controls
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[]={"sn","givenName", "samAccountName", "mail"};
searchCtls.setReturningAttributes(returnedAtts);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//specify the LDAP search filter
String searchFilter = "(&(objectClass=user)(mail=*))";
//Specify the Base for the search
String searchBase = "DC=VIEWCONNECTION, DC=COM";
//initialize counter to total the results
int totalResults = 0;
// Search for objects using the filter
NamingEnumeration<SearchResult> answer = ldapContext.search(searchBase, searchFilter, searchCtls);
//Loop through the search results
while (answer.hasMoreElements())
{
SearchResult sr = (SearchResult)answer.next();
totalResults++;
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
System.out.println(">>>>>>" + attrs.get("samAccountName"));
}
System.out.println("Total results: " + totalResults);
ldapContext.close();

LDAP+ Java : How can I know my active directory's names

How can I know all my attributes for my active directory ??
I saw example like "ou=People" but I don't know how to access to the name "People" who is specific in my company. I don't have access of LDAP (or I don't know how to) so I don't know what I'm suppose to put.
DirContext ctx = null;
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://"+serverAddress+":389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, DOMAIN+username);
env.put(Context.SECURITY_CREDENTIALS, password);
try {
ctx = new InitialDirContext(env);
Attributes matchAttrs = new BasicAttributes(true); // ignore attribute name case
matchAttrs.put(new BasicAttribute("mail", "XXXXXX#XXXX.com"));
Attributes attrs = ctx.getAttributes("");
// Search for objects that have those matching attributes
NamingEnumeration<SearchResult> answer = ctx.search("ou=Users", matchAttrs);
while (answer.hasMore()) {
SearchResult sr = (SearchResult)answer.next();
System.out.println(">>>" + sr.getName());
}
I have the error : Failed to bind to LDAP [LDAP: error code 1 - 000020D6: SvcErr: DSID-03100754, problem 5012 (DIR_ERROR), data 0 remaining name 'ou=Users'
How can I know which name the company use to put after ou=....
Thanks a lot !
You can use a ldap browser to explore the ldap. (I usually use softerra Ldap administrator)
All the info you need to connect are within the first lines of your code (address, port and so on... )

Categories