001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014 ForgeRock AS
026 */
027package org.forgerock.opendj.ldap.controls;
028
029import static com.forgerock.opendj.ldap.CoreMessages.ERR_PWPOLICYREQ_CONTROL_BAD_OID;
030import static com.forgerock.opendj.ldap.CoreMessages.ERR_PWPOLICYREQ_CONTROL_HAS_VALUE;
031
032import org.forgerock.i18n.LocalizableMessage;
033import org.forgerock.opendj.ldap.ByteString;
034import org.forgerock.opendj.ldap.DecodeException;
035import org.forgerock.opendj.ldap.DecodeOptions;
036
037import org.forgerock.util.Reject;
038
039/**
040 * The password policy request control as defined in
041 * draft-behera-ldap-password-policy.
042 * <p>
043 * This control may be sent with any request in order to convey to the server
044 * that this client is aware of, and can process the password policy response
045 * control. When a server receives this control, it will return the password
046 * policy response control when appropriate and with the proper data.
047 *
048 * <pre>
049 * Connection connection = ...;
050 * String DN = ...;
051 * char[] password = ...;
052 *
053 * try {
054 *     BindRequest request = Requests.newSimpleBindRequest(DN, password)
055 *             .addControl(PasswordPolicyRequestControl.newControl(true));
056 *
057 *     BindResult result = connection.bind(request);
058 *
059 *     PasswordPolicyResponseControl control =
060 *             result.getControl(PasswordPolicyResponseControl.DECODER,
061 *                     new DecodeOptions());
062 *     if (!(control == null) && !(control.getWarningType() == null)) {
063 *         // Password policy warning, use control.getWarningType(),
064 *         // and control.getWarningValue().
065 *     }
066 * } catch (LdapException e) {
067 *     Result result = e.getResult();
068 *     try {
069 *         PasswordPolicyResponseControl control =
070 *                 result.getControl(PasswordPolicyResponseControl.DECODER,
071 *                         new DecodeOptions());
072 *         if (!(control == null)) {
073 *             // Password policy error, use control.getErrorType().
074 *         }
075 *     } catch (DecodeException de) {
076 *         // Failed to decode the response control.
077 *     }
078 * } catch (DecodeException e) {
079 *     // Failed to decode the response control.
080 * }
081 * </pre>
082 *
083 * @see PasswordPolicyResponseControl
084 * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy">
085 *      draft-behera-ldap-password-policy - Password Policy for LDAP Directories
086 *      </a>
087 */
088public final class PasswordPolicyRequestControl implements Control {
089    /**
090     * The OID for the password policy control from
091     * draft-behera-ldap-password-policy.
092     */
093    public static final String OID = "1.3.6.1.4.1.42.2.27.8.5.1";
094
095    private final boolean isCritical;
096
097    private static final PasswordPolicyRequestControl CRITICAL_INSTANCE =
098            new PasswordPolicyRequestControl(true);
099    private static final PasswordPolicyRequestControl NONCRITICAL_INSTANCE =
100            new PasswordPolicyRequestControl(false);
101
102    /**
103     * A decoder which can be used for decoding the password policy request
104     * control.
105     */
106    public static final ControlDecoder<PasswordPolicyRequestControl> DECODER =
107            new ControlDecoder<PasswordPolicyRequestControl>() {
108
109                public PasswordPolicyRequestControl decodeControl(final Control control,
110                        final DecodeOptions options) throws DecodeException {
111                    Reject.ifNull(control);
112
113                    if (control instanceof PasswordPolicyRequestControl) {
114                        return (PasswordPolicyRequestControl) control;
115                    }
116
117                    if (!control.getOID().equals(OID)) {
118                        final LocalizableMessage message =
119                                ERR_PWPOLICYREQ_CONTROL_BAD_OID.get(control.getOID(), OID);
120                        throw DecodeException.error(message);
121                    }
122
123                    if (control.hasValue()) {
124                        final LocalizableMessage message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE.get();
125                        throw DecodeException.error(message);
126                    }
127
128                    return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
129                }
130
131                public String getOID() {
132                    return OID;
133                }
134            };
135
136    /**
137     * Creates a new password policy request control having the provided
138     * criticality.
139     *
140     * @param isCritical
141     *            {@code true} if it is unacceptable to perform the operation
142     *            without applying the semantics of this control, or
143     *            {@code false} if it can be ignored.
144     * @return The new control.
145     */
146    public static PasswordPolicyRequestControl newControl(final boolean isCritical) {
147        return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
148    }
149
150    private PasswordPolicyRequestControl(final boolean isCritical) {
151        this.isCritical = isCritical;
152    }
153
154    /** {@inheritDoc} */
155    public String getOID() {
156        return OID;
157    }
158
159    /** {@inheritDoc} */
160    public ByteString getValue() {
161        return null;
162    }
163
164    /** {@inheritDoc} */
165    public boolean hasValue() {
166        return false;
167    }
168
169    /** {@inheritDoc} */
170    public boolean isCritical() {
171        return isCritical;
172    }
173
174    /** {@inheritDoc} */
175    @Override
176    public String toString() {
177        final StringBuilder builder = new StringBuilder();
178        builder.append("PasswordPolicyRequestControl(oid=");
179        builder.append(getOID());
180        builder.append(", criticality=");
181        builder.append(isCritical());
182        builder.append(")");
183        return builder.toString();
184    }
185
186}