package org.opends.sdk.controls; import static com.sun.opends.sdk.messages.Messages.*; import static com.sun.opends.sdk.util.StaticUtils.*; import java.io.IOException; import org.opends.sdk.ByteString; import org.opends.sdk.ByteStringBuilder; import org.opends.sdk.DecodeException; import org.opends.sdk.LocalizableMessage; import org.opends.sdk.asn1.ASN1; import org.opends.sdk.asn1.ASN1Reader; import org.opends.sdk.asn1.ASN1Writer; import org.opends.sdk.schema.Schema; import com.sun.opends.sdk.util.StaticUtils; import com.sun.opends.sdk.util.Validator; /** * This class implements the password policy control defined in * draft-behera-ldap-password-policy. */ public class PasswordPolicyControl { /** * The OID for the password policy control from * draft-behera-ldap-password-policy. */ public static final String OID_PASSWORD_POLICY_CONTROL = "1.3.6.1.4.1.42.2.27.8.5.1"; /** * This class implements the password policy request control defined * in draft-behera-ldap-password-policy. It does not have a value. */ public static class Request extends Control { public Request() { super(OID_PASSWORD_POLICY_CONTROL, false); } public Request(boolean isCritical) { super(OID_PASSWORD_POLICY_CONTROL, isCritical); } @Override public ByteString getValue() { return null; } @Override public boolean hasValue() { return false; } @Override public void toString(StringBuilder buffer) { buffer.append("PasswordPolicyRequestControl(oid="); buffer.append(getOID()); buffer.append(", criticality="); buffer.append(isCritical()); buffer.append(")"); } } /** * This class implements the password policy response control defined * in draft-behera-ldap-password-policy. The value may have zero, one, * or two elements, which may include flags to indicate a warning * and/or an error. */ public static class Response extends Control { // The warning value for this password policy response control. private int warningValue; // The error type for this password policy response control. private PasswordPolicyErrorType errorType; // The warning type for the password policy response control. private PasswordPolicyWarningType warningType; /** * Creates a new instance of the password policy response control * with the default OID and criticality, and without either a * warning or an error flag. */ public Response() { this(false); } /** * Creates a new instance of the password policy response control * with the default OID and criticality, and without either a * warning or an error flag. * * @param isCritical * Indicates whether support for this control should be * considered a critical part of the client processing. */ public Response(boolean isCritical) { super(OID_PASSWORD_POLICY_CONTROL, isCritical); warningType = null; errorType = null; warningValue = -1; } /** * Retrieves the password policy error type contained in this * control. * * @return The password policy error type contained in this control, * or null if there is no error type. */ public PasswordPolicyErrorType getErrorType() { return errorType; } @Override public ByteString getValue() { ByteStringBuilder buffer = new ByteStringBuilder(); ASN1Writer writer = ASN1.getWriter(buffer); try { writer.writeStartSequence(); if (warningType != null) { // Just write the CHOICE element as a single element SEQUENCE. writer.writeStartSequence(TYPE_WARNING_ELEMENT); writer.writeInteger((byte) (0x80 | warningType.intValue()), warningValue); writer.writeEndSequence(); } if (errorType != null) { writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue()); } writer.writeEndSequence(); return buffer.toByteString(); } catch (IOException ioe) { // This should never happen unless there is a bug somewhere. throw new RuntimeException(ioe); } } /** * Retrieves the password policy warning type contained in this * control. * * @return The password policy warning type contained in this * control, or null if there is no warning * type. */ public PasswordPolicyWarningType getWarningType() { return warningType; } /** * Retrieves the password policy warning value for this control. The * value is undefined if there is no warning type. * * @return The password policy warning value for this control. */ public int getWarningValue() { return warningValue; } @Override public boolean hasValue() { return true; } public Response setError(PasswordPolicyErrorType error) { Validator.ensureNotNull(error); this.errorType = error; return this; } public Response setWarning(PasswordPolicyWarningType type, int value) { Validator.ensureNotNull(type); this.warningType = type; this.warningValue = value; return this; } /** * Appends a string representation of this password policy response * control to the provided buffer. * * @param buffer * The buffer to which the information should be appended. */ @Override public void toString(StringBuilder buffer) { buffer.append("PasswordPolicyResponseControl(oid="); buffer.append(getOID()); buffer.append(", criticality="); buffer.append(isCritical()); buffer.append(", warningType="); buffer.append(warningType); buffer.append(", warningValue="); buffer.append(warningValue); buffer.append(", errorType="); buffer.append(errorType); buffer.append(")"); } } /** * ControlDecoder implentation to decode this control from a * ByteString. */ private static final class RequestDecoder implements ControlDecoder { /** * {@inheritDoc} */ public Request decode(boolean isCritical, ByteString value, Schema schema) throws DecodeException { if (value != null) { LocalizableMessage message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE.get(); throw DecodeException.error(message); } return new Request(isCritical); } public String getOID() { return OID_PASSWORD_POLICY_CONTROL; } } /** * ControlDecoder implentation to decode this control from a * ByteString. */ private final static class ResponseDecoder implements ControlDecoder { /** * {@inheritDoc} */ public Response decode(boolean isCritical, ByteString value, Schema schema) throws DecodeException { if (value == null) { // The response control must always have a value. LocalizableMessage message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get(); throw DecodeException.error(message); } ASN1Reader reader = ASN1.getReader(value); try { PasswordPolicyWarningType warningType = null; PasswordPolicyErrorType errorType = null; int warningValue = -1; reader.readStartSequence(); if (reader.hasNextElement() && (reader.peekType() == TYPE_WARNING_ELEMENT)) { // Its a CHOICE element. Read as sequence to retrieve // nested element. reader.readStartSequence(); warningType = PasswordPolicyWarningType.valueOf(0x7F & reader .peekType()); warningValue = (int) reader.readInteger(); if (warningType == null) { LocalizableMessage message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE .get(byteToHex(reader.peekType())); throw DecodeException.error(message); } reader.readEndSequence(); } if (reader.hasNextElement() && (reader.peekType() == TYPE_ERROR_ELEMENT)) { int errorValue = (int) reader.readInteger(); errorType = PasswordPolicyErrorType.valueOf(errorValue); if (errorType == null) { LocalizableMessage message = ERR_PWPOLICYRES_INVALID_ERROR_TYPE .get(errorValue); throw DecodeException.error(message); } } reader.readEndSequence(); Response response = new Response(isCritical); if (warningType != null) { response.setWarning(warningType, warningValue); } if (errorType != null) { response.setError(errorType); } return response; } catch (IOException e) { StaticUtils.DEBUG_LOG.throwing( "PasswordPolicyControl.ResponseDecoder", "decode", e); LocalizableMessage message = ERR_PWPOLICYRES_DECODE_ERROR .get(getExceptionMessage(e)); throw DecodeException.error(message); } } public String getOID() { return OID_PASSWORD_POLICY_CONTROL; } } /** * The BER type value for the warning element of the control value. */ private static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0; /** * The BER type value for the error element of the control value. */ private static final byte TYPE_ERROR_ELEMENT = (byte) 0x81; /** * The Control Decoder that can be used to decode the request control. */ public static final ControlDecoder REQUEST_DECODER = new RequestDecoder(); /** * The Control Decoder that can be used to decode the response * control. */ public static final ControlDecoder RESPONSE_DECODER = new ResponseDecoder(); }