changing user password in Active Directory using the JNDI GSS-API/Kerberos5

110 views
Skip to first unread message

ravi

unread,
Nov 18, 2009, 5:20:12 PM11/18/09
to
Hello,
I am trying to the JNDI GSS-API to change a user password on an Active
Directory Server 2003. I have seen a variation of this using SSL on
the thread [*http://forums.sun.com/thread.jspa?
threadID=592611&start=0&tstart=0*|http://forums.sun.com/thread.jspa?
threadID=592611&start=0&tstart=0]
but I can't seem to make this work using the GSS-API. I can
successfully create a
javax.security.auth.login.LoginContext.LoginContext and then call the
login method on it to log in as a user. I then call the
javax.security.auth.Subject.doAs() method which calls the run method
in a class extending the javax.security.PrivilegedActionClass. But
when I actually try to change the password using
InitialDirContext.modifyAttributes(), I get the exception:

*javax.naming.OperationNotSupportedException: [LDAP: error code 53 -
00002077: SvcErr: DSID-03190DC9, problem 5003 (WILL_NOT_PERFORM), data
0*

*If anyone can help me figure out why it doesn't work, that would be
great!*

P.S: I know the error seems to suggest that there might be some active
directory setting that is preventing this from working, but I've
checked all relevant settings on the Windows 2003 server Active
Directory that I can think of: In the User properties->Account-
>Account options, I've made sure the user can change password. Also,
in the Group Policy->Computer Configuration->Windows Settings-
>Security Settings->Account Policies->Password Policy, Maximum
password age is zero and so is minimum password age.

Here's my java code:

{code}import javax.naming.*;
import javax.security.auth.*;
import java.security.PrivilegedAction;
import java.io.UnsupportedEncodingException;

public void changeSecret((String uid, String oldPassword, String
newPassword)
throws NamingException, ACException{
try {
K5CallbackHandler cb = new K5CallbackHandler(uid,
oldPassword);
LoginContext lc = new LoginContext("marker", cb);
lc.login();
Subject.doAs(lc.getSubject(), new ChangePasswordAction
(rz.getName(), oldPassword, newPassword));
}
catch(LoginException e) {

}
try {
lc.logout();
}
catch(LoginException e) {

}
}{code}

ChangePasswordAction.java is:

{code}import javax.naming.*;
import javax.naming.naming.directory.*;
import java.io.UnsupportedEncodingException;

private class ChangePasswordAction implements PrivilegedAction {
private String uid;
private String quotedOldPassword;
private String quotedNewPassword;

public ChangePasswordAction(String uid, String oldPassword, String
newPassword) {
this.uid = uid;
quotedOldPassword = "\"" + oldPassword + "\"";
quotedNewPassword = "\"" + newPassword + "\"";

}
public Object run() {
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ad2k3:389");
env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
try {
DirContext ctx = new InitialDirContext(env);
ModificationItem[] mods = new ModificationItem[2];
byte[] oldPasswordUnicode = quotedOldPassword.getBytes("UTF-16LE");
byte[] newPasswordUnicode = quotedNewPassword.getBytes("UTF-16LE");
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new
BasicAttribute("unicodePwd", oldPasswordUnicode));
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new
BasicAttribute("unicodePwd", newPasswordUnicode));
ctx.modifyAttributes(uid, mods);
ctx.close();
} catch (NamingException e) {

} catch (UnsupportedEncodingException e) {

}
return null;
}
}{code}

K5CallbackHandler is:

{code}import javax.security.auth.callback.*;

final class K5CallbackHandler
implements CallbackHandler {

private final String name;
private final char[] passwd;

public K5CallbackHandler(String nm, String pw) {
name = nm;
if(pw == null) {
passwd = new char[0];
}
else {
passwd = pw.toCharArray();
}
}

public void handle(Callback[] callbacks)
throws java.io.IOException, UnsupportedCallbackException {

for(int i = 0; i < callbacks.length; i++) {
if(callbacks[i] instanceof NameCallback) {
NameCallback cb = (NameCallback) callbacks[i];
cb.setName(name);
}
else {
if(callbacks[i] instanceof PasswordCallback) {
PasswordCallback cb = (PasswordCallback) callbacks[i];
cb.setPassword(passwd);
}
else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
}
}{code}

The relevant entry in the JAAS.conf file that is referred to as
"marker" in the LoginContext constructor is:

marker {
com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};

Joe Kaplan

unread,
Nov 19, 2009, 12:29:36 PM11/19/09
to
LDAP password modifications required 128 bit encryption. You get this for
free with SSL.

With any type of Windows authentication (NTLM or Kerberos), you CAN also get
channel encryption IF your stack supports a way to enable that. In Windows
LDAP, you do your Negotiate auth and with the "Encrypt" session option
enabled and "it just works". However, if your stack does not have a way to
use that feature, you won't have channel encryption and therefore won't be
able to use this the feature. The fact that the Kerb auth worked doesn't
matter here because that does not actually provide the encryption of the
traffic, just a secure authentication mechanism.

No idea if JDNI supports this feature.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
"ravi" <thejed...@gmail.com> wrote in message
news:23eca8d9-6b5d-4607...@m7g2000prd.googlegroups.com...

ravi

unread,
Nov 23, 2009, 5:21:42 PM11/23/09
to
Thanks Joe,
I am going to try and explore if I am using channel encryption and if
I am doing it right.
Ravi.

On Nov 19, 9:29 am, "Joe Kaplan"


<joseph.e.kap...@removethis.accenture.com> wrote:
> LDAP password modifications required 128 bit encryption.  You get this for
> free with SSL.
>
> With any type of Windows authentication (NTLM or Kerberos), you CAN also get
> channel encryption IF your stack supports a way to enable that. In Windows
> LDAP, you do your Negotiate auth and with the "Encrypt" session option
> enabled and "it just works".  However, if your stack does not have a way to
> use that feature, you won't have channel encryption and therefore won't be
> able to use this the feature. The fact that the Kerb auth worked doesn't
> matter here because that does not actually provide the encryption of the
> traffic, just a secure authentication mechanism.
>
> No idea if JDNI supports this feature.
>
> --
> Joe Kaplan-MS MVP Directory Services Programming

> Co-author of "The .NET Developer's Guide to Directory Services Programming"http://www.directoryprogramming.net"ravi" <thejedikni...@gmail.com> wrote in message

ravitej...@gmail.com

unread,
Mar 3, 2016, 2:09:08 AM3/3/16
to
Hi Ravi,
Is there any update. I am stuck in this exact problem. Could not find a way out.
Can you please help me.?
Reply all
Reply to author
Forward
0 new messages