Reputation: 8705
I have Active Directory, with Users in it, i am trying to change a users password from a Java Program as follows:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
prop.put(Context.SECURITY_AUTHENTICATION, "simple");
prop.put(Context.SECURITY_PRINCIPAL,"user1");
prop.put(Context.SECURITY_CREDENTIALS,"pass1");
prop.put(Context.SECURITY_PROTOCOL,"ADSecurityProtocol");
prop.put(Context.PROVIDER_URL, "ldap://host:389/OU=My Org,DC=domain,DC=com");
try
{
LdapContext ctx =new InitialLdapContext(prop,null);
String oldPassword="pass1";
String newPassword="passnew1";
ModificationItem[] mods = new ModificationItem[2];
String oldQuotedPassword = "\"" + oldPassword + "\"";
byte[] oldUnicodePassword = oldQuotedPassword.getBytes("UTF-16LE");
String newQuotedPassword = "\"" + newPassword + "\"";
byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute("unicodePwd", oldUnicodePassword));
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
new BasicAttribute("unicodePwd", newUnicodePassword));
String theUserName="CN="+"user1"+",OU=My Org,DC=domain,DC=com";
// Perform the update
ctx.modifyAttributes(theUserName, mods);
System.out.println("Changed Password for successfully");
ctx.close();
}
catch (Exception e) {
System.err.println("Problem changing password: " + e);
}
The error message i get is:
Problem changing password: javax.naming.NamingException:
[LDAP: error code 1 - 000020D6: SvcErr: DSID-031007DB,
problem 5012 (DIR_ERROR), data 0]; remaining name
'CN=user1,OU=My Org,DC=domain,DC=com'
Edit 1:
Based on Suggestions i have tried this with port 636 and ldaps as well:
prop.put(Context.PROVIDER_URL, "ldap://host:636/OU=My Org,DC=domain,DC=com");
Also tried
prop.put(Context.PROVIDER_URL, "ldaps://host:636/OU=My Org,DC=domain,DC=com");
I am getting MalformedURLException: Invalid URI:
Invalid URI: Org,DC=domain,DC=com]
When i try (not sure if anything is listening on 636, it appears it is tho):
$ telnet LDAPHost 636
Escape character is '^]'.
Connection closed by foreign host.
Edit2:
Changed:
prop.put(Context.PROVIDER_URL, "ldap://host:636/OU=My Org,DC=domain,DC=com");
to:
prop.put(Context.PROVIDER_URL, "ldap://host:636/OU=My%20Org,DC=domain,DC=com");
The error is:
javax.naming.CommunicationException: simple bind failed: host:636
[Root exception is java.net.SocketException: Connection reset]
Probably the LDAP Server is not even listening on ssl port: 636
Upvotes: 4
Views: 27075
Reputation: 117675
If you are on Windows, then you can call NetUserChangePassword()
function that is available inside netapi32.dll
.
Using JNA
, the code will be like this:
public static int changeActiveDirectoryUserPassword(String activeDirectoryIP, String username, String oldPassword, String newPassword)
{
int status = Netapi32.INSTANCE.NetUserChangePassword(activeDirectoryIP, username, oldPassword, newPassword);
switch(status)
{
case WinError.ERROR_INVALID_PARAMETER: // The parameter is incorrect
case WinError.ERROR_ACCESS_DENIED: // The user does not have access to the requested information
case WinError.ERROR_INVALID_PASSWORD: // The user has entered an invalid password
case LMErr.NERR_InvalidComputer: // The computer name is invalid
case LMErr.NERR_NotPrimary: // The operation is allowed only on the primary domain controller of the domain
case LMErr.NERR_UserNotFound: // The user name could not be found
case LMErr.NERR_PasswordTooShort: // The password is shorter than required. (The password could also be too
// long, be too recent in its change history, not have enough unique
// characters, or not meet another password policy requirement.)
case LMErr.NERR_Success: // function succeeds
default: return status;
}
}
Note: Unlike the ldap approach, this approach will work even if the old password is already expired.
Upvotes: 1
Reputation: 400
You have to change the attribute. Try to change unicodePwd
withuserpassword
from :
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute("unicodePwd", oldUnicodePassword));
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
new BasicAttribute("unicodePwd", newUnicodePassword));
to :
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute("userpassword", oldUnicodePassword));
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
new BasicAttribute("userpassword", newUnicodePassword));
Upvotes: 0
Reputation: 2399
Basically, you need to modify the unicodePwd
attribute of the user.
I use AWS Simple AD implementation and, as it is based on Samba 4, this attribute doesn't work. You need to use clearTextPassword
in this case. See my blog post about it:
http://blog.techutils.space/2016/02/changing-samba4-aws-simple-ad-user.html
Note: AWS Simple AD doesn't support SSL yet, so find a way to mitigate this risk.
Upvotes: 0
Reputation: 21
The JVM executing the password change call needs to be trusted by the directory service provider. This means importing a certificate generated from AD into the JVM trust store.
Upvotes: 2
Reputation: 17528
[The
unicodePwd
] attribute can be written under restricted conditions [...] In order to modify this attribute, the client must have a 128-bit Secure Socket Layer (SSL) connection to the server.
You only have a plain unsecure ldap://
connection instead of ldaps://
, so that won't work according to the above restrictions.
See more details at: http://support.microsoft.com/kb/269190
Upvotes: 6