package com.hwlcn.ldap.ldap.sdk.extensions; import java.util.ArrayList; import com.hwlcn.ldap.asn1.ASN1Element; import com.hwlcn.ldap.asn1.ASN1OctetString; import com.hwlcn.ldap.asn1.ASN1Sequence; import com.hwlcn.ldap.ldap.sdk.Control; import com.hwlcn.ldap.ldap.sdk.ExtendedRequest; import com.hwlcn.ldap.ldap.sdk.ExtendedResult; import com.hwlcn.ldap.ldap.sdk.LDAPConnection; import com.hwlcn.ldap.ldap.sdk.LDAPException; import com.hwlcn.ldap.ldap.sdk.ResultCode; import com.hwlcn.core.annotation.NotMutable; import com.hwlcn.core.annotation.ThreadSafety; import com.hwlcn.ldap.util.ThreadSafetyLevel; import static com.hwlcn.ldap.ldap.sdk.extensions.ExtOpMessages.*; import static com.hwlcn.ldap.util.Debug.*; import static com.hwlcn.ldap.util.StaticUtils.*; /** * This class provides an implementation of the LDAP password modify extended * request as defined in * <A HREF="http://www.ietf.org/rfc/rfc3062.txt">RFC 3062</A>. It may be used * to change the password for a user in the directory, and provides the ability * to specify the current password for verification. It also offers the ability * to request that the server generate a new password for the user. * <BR><BR> * The elements of a password modify extended request include: * <UL> * <LI>{@code userIdentity} -- This specifies the user for which to change the * password. It should generally be the DN for the target user (although * the specification does indicate that some servers may accept other * values). If no value is provided, then the server will attempt to * change the password for the currently-authenticated user.</LI> * <LI>{@code oldPassword} -- This specifies the current password for the * user. Some servers may require that the old password be provided when * a user is changing his or her own password as an extra level of * verification, but it is generally not necessary when an administrator * is resetting the password for another user.</LI> * <LI>{@code newPassword} -- This specifies the new password to use for the * user. If it is not provided, then the server may attempt to generate a * new password for the user, and in that case it will be included in the * {@code generatedPassword} field of the corresponding * {@link com.hwlcn.ldap.ldap.sdk.extensions.PasswordModifyExtendedResult}. Note that some servers may not * support generating a new password, in which case the client will always * be required to provide it.</LI> * </UL> * <H2>Example</H2> * The following example demonstrates the use of the password modify extended * operation to change the password for user * "uid=john.doe,ou=People,dc=example,dc=com". Neither the current password nor * a new password will be provided, so the server will generate a new password * for the user. * <PRE> * PasswordModifyExtendedRequest passwordModifyRequest = * new PasswordModifyExtendedRequest( * "uid=john.doe,ou=People,dc=example,dc=com", null, null); * PasswordModifyExtendedResult passwordModifyResult = * (PasswordModifyExtendedResult) * connection.processExtendedOperation(passwordModifyRequest); * * // NOTE: The processExtendedOperation method will only throw an exception * // if a problem occurs while trying to send the request or read the * // response. It will not throw an exception because of a non-success * // response. * * if (passwordModifyResult.getResultCode() == ResultCode.SUCCESS) * { * System.out.println("The password change was successful."); * System.out.println("The new password for the user is " + * passwordModifyResult.getGeneratedPassword()); * } * else * { * System.err.println("An error occurred while attempting to process " + * "the password modify extended request."); * } * </PRE> */ @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public final class PasswordModifyExtendedRequest extends ExtendedRequest { public static final String PASSWORD_MODIFY_REQUEST_OID = "1.3.6.1.4.1.4203.1.11.1"; private static final byte TYPE_USER_IDENTITY = (byte) 0x80; private static final byte TYPE_OLD_PASSWORD = (byte) 0x81; private static final byte TYPE_NEW_PASSWORD = (byte) 0x82; private static final long serialVersionUID = 4965048727456933570L; private final ASN1OctetString oldPassword; private final ASN1OctetString newPassword; private final String userIdentity; public PasswordModifyExtendedRequest(final String newPassword) { this(null, null, newPassword, null); } public PasswordModifyExtendedRequest(final byte[] newPassword) { this(null, null, newPassword, null); } public PasswordModifyExtendedRequest(final String oldPassword, final String newPassword) { this(null, oldPassword, newPassword, null); } public PasswordModifyExtendedRequest(final byte[] oldPassword, final byte[] newPassword) { this(null, oldPassword, newPassword, null); } public PasswordModifyExtendedRequest(final String userIdentity, final String oldPassword, final String newPassword) { this(userIdentity, oldPassword, newPassword, null); } public PasswordModifyExtendedRequest(final String userIdentity, final byte[] oldPassword, final byte[] newPassword) { this(userIdentity, oldPassword, newPassword, null); } public PasswordModifyExtendedRequest(final String userIdentity, final String oldPassword, final String newPassword, final Control[] controls) { super(PASSWORD_MODIFY_REQUEST_OID, encodeValue(userIdentity, oldPassword, newPassword), controls); this.userIdentity = userIdentity; if (oldPassword == null) { this.oldPassword = null; } else { this.oldPassword = new ASN1OctetString(TYPE_OLD_PASSWORD, oldPassword); } if (newPassword == null) { this.newPassword = null; } else { this.newPassword = new ASN1OctetString(TYPE_NEW_PASSWORD, newPassword); } } public PasswordModifyExtendedRequest(final String userIdentity, final byte[] oldPassword, final byte[] newPassword, final Control[] controls) { super(PASSWORD_MODIFY_REQUEST_OID, encodeValue(userIdentity, oldPassword, newPassword), controls); this.userIdentity = userIdentity; if (oldPassword == null) { this.oldPassword = null; } else { this.oldPassword = new ASN1OctetString(TYPE_OLD_PASSWORD, oldPassword); } if (newPassword == null) { this.newPassword = null; } else { this.newPassword = new ASN1OctetString(TYPE_NEW_PASSWORD, newPassword); } } public PasswordModifyExtendedRequest(final ExtendedRequest extendedRequest) throws LDAPException { super(extendedRequest); final ASN1OctetString value = extendedRequest.getValue(); if (value == null) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_PW_MODIFY_REQUEST_NO_VALUE.get()); } try { ASN1OctetString oldPW = null; ASN1OctetString newPW = null; String userID = null; final ASN1Element valueElement = ASN1Element.decode(value.getValue()); final ASN1Element[] elements = ASN1Sequence.decodeAsSequence(valueElement).elements(); for (final ASN1Element e : elements) { switch (e.getType()) { case TYPE_USER_IDENTITY: userID = ASN1OctetString.decodeAsOctetString(e).stringValue(); break; case TYPE_OLD_PASSWORD: oldPW = ASN1OctetString.decodeAsOctetString(e); break; case TYPE_NEW_PASSWORD: newPW = ASN1OctetString.decodeAsOctetString(e); break; default: throw new LDAPException(ResultCode.DECODING_ERROR, ERR_PW_MODIFY_REQUEST_INVALID_TYPE.get( toHex(e.getType()))); } } userIdentity = userID; oldPassword = oldPW; newPassword = newPW; } catch (LDAPException le) { debugException(le); throw le; } catch (Exception e) { debugException(e); throw new LDAPException(ResultCode.DECODING_ERROR, ERR_PW_MODIFY_REQUEST_CANNOT_DECODE.get(e), e); } } private static ASN1OctetString encodeValue(final String userIdentity, final String oldPassword, final String newPassword) { final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3); if (userIdentity != null) { elements.add(new ASN1OctetString(TYPE_USER_IDENTITY, userIdentity)); } if (oldPassword != null) { elements.add(new ASN1OctetString(TYPE_OLD_PASSWORD, oldPassword)); } if (newPassword != null) { elements.add(new ASN1OctetString(TYPE_NEW_PASSWORD, newPassword)); } return new ASN1OctetString(new ASN1Sequence(elements).encode()); } private static ASN1OctetString encodeValue(final String userIdentity, final byte[] oldPassword, final byte[] newPassword) { final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3); if (userIdentity != null) { elements.add(new ASN1OctetString(TYPE_USER_IDENTITY, userIdentity)); } if (oldPassword != null) { elements.add(new ASN1OctetString(TYPE_OLD_PASSWORD, oldPassword)); } if (newPassword != null) { elements.add(new ASN1OctetString(TYPE_NEW_PASSWORD, newPassword)); } return new ASN1OctetString(new ASN1Sequence(elements).encode()); } public String getUserIdentity() { return userIdentity; } public String getOldPassword() { if (oldPassword == null) { return null; } else { return oldPassword.stringValue(); } } public byte[] getOldPasswordBytes() { if (oldPassword == null) { return null; } else { return oldPassword.getValue(); } } public ASN1OctetString getRawOldPassword() { return oldPassword; } public String getNewPassword() { if (newPassword == null) { return null; } else { return newPassword.stringValue(); } } public byte[] getNewPasswordBytes() { if (newPassword == null) { return null; } else { return newPassword.getValue(); } } public ASN1OctetString getRawNewPassword() { return newPassword; } @Override() public PasswordModifyExtendedResult process(final LDAPConnection connection, final int depth) throws LDAPException { final ExtendedResult extendedResponse = super.process(connection, depth); return new PasswordModifyExtendedResult(extendedResponse); } @Override() public PasswordModifyExtendedRequest duplicate() { return duplicate(getControls()); } @Override() public PasswordModifyExtendedRequest duplicate(final Control[] controls) { final byte[] oldPWBytes = (oldPassword == null) ? null : oldPassword.getValue(); final byte[] newPWBytes = (newPassword == null) ? null : newPassword.getValue(); final PasswordModifyExtendedRequest r = new PasswordModifyExtendedRequest(userIdentity, oldPWBytes, newPWBytes, controls); r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); return r; } @Override() public String getExtendedRequestName() { return INFO_EXTENDED_REQUEST_NAME_PASSWORD_MODIFY.get(); } @Override() public void toString(final StringBuilder buffer) { buffer.append("PasswordModifyExtendedRequest("); boolean dataAdded = false; if (userIdentity != null) { buffer.append("userIdentity='"); buffer.append(userIdentity); buffer.append('\''); dataAdded = true; } if (oldPassword != null) { if (dataAdded) { buffer.append(", "); } buffer.append("oldPassword='"); buffer.append(oldPassword.stringValue()); buffer.append('\''); dataAdded = true; } if (newPassword != null) { if (dataAdded) { buffer.append(", "); } buffer.append("newPassword='"); buffer.append(newPassword.stringValue()); buffer.append('\''); dataAdded = true; } final Control[] controls = getControls(); if (controls.length > 0) { if (dataAdded) { buffer.append(", "); } buffer.append("controls={"); for (int i=0; i < controls.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(controls[i]); } buffer.append('}'); } buffer.append(')'); } }