001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017package org.opends.server.controls;
018import org.forgerock.i18n.LocalizableMessage;
019
020
021
022import java.io.IOException;
023
024import org.forgerock.opendj.io.*;
025import org.forgerock.i18n.slf4j.LocalizedLogger;
026import org.opends.server.types.*;
027import org.forgerock.opendj.ldap.ResultCode;
028import org.forgerock.opendj.ldap.ByteString;
029import static org.opends.messages.ProtocolMessages.*;
030import static org.opends.server.util.ServerConstants.*;
031import static org.opends.server.util.StaticUtils.*;
032
033
034
035/**
036 * This class implements the password policy response control defined in
037 * draft-behera-ldap-password-policy.  The value may have zero, one, or two
038 * elements, which may include flags to indicate a warning and/or an error.
039 */
040public class PasswordPolicyResponseControl
041       extends Control
042{
043  /** ControlDecoder implementation to decode this control from a ByteString. */
044  private static final class Decoder
045      implements ControlDecoder<PasswordPolicyResponseControl>
046  {
047    @Override
048    public PasswordPolicyResponseControl decode(boolean isCritical,
049                                                ByteString value)
050        throws DirectoryException
051    {
052      if (value == null)
053      {
054        // The response control must always have a value.
055        LocalizableMessage message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get();
056        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
057      }
058
059      ASN1Reader reader = ASN1.getReader(value);
060      try
061      {
062        PasswordPolicyWarningType warningType  = null;
063        PasswordPolicyErrorType   errorType    = null;
064        int                       warningValue = -1;
065
066        reader.readStartSequence();
067
068        if(reader.hasNextElement() &&
069            reader.peekType() == TYPE_WARNING_ELEMENT)
070        {
071          // Its a CHOICE element. Read as sequence to retrieve
072          // nested element.
073          reader.readStartSequence();
074          warningType =
075              PasswordPolicyWarningType.valueOf(reader.peekType());
076          warningValue = (int)reader.readInteger();
077          if (warningType == null)
078          {
079            LocalizableMessage message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(
080                byteToHex(reader.peekType()));
081            throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
082                message);
083          }
084          reader.readEndSequence();
085        }
086        if(reader.hasNextElement() &&
087            reader.peekType() == TYPE_ERROR_ELEMENT)
088        {
089          int errorValue = (int)reader.readInteger();
090          errorType = PasswordPolicyErrorType.valueOf(errorValue);
091          if (errorType == null)
092          {
093            LocalizableMessage message =
094                ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue);
095            throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
096                message);
097          }
098        }
099
100        reader.readEndSequence();
101
102        return new PasswordPolicyResponseControl(isCritical,
103            warningType, warningValue,
104            errorType);
105      }
106      catch (DirectoryException de)
107      {
108        throw de;
109      }
110      catch (Exception e)
111      {
112        logger.traceException(e);
113
114        LocalizableMessage message =
115            ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e));
116        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
117      }
118    }
119
120
121    @Override
122    public String getOID()
123    {
124      return OID_ACCOUNT_USABLE_CONTROL;
125    }
126
127  }
128
129  /** The Control Decoder that can be used to decode this control. */
130  public static final ControlDecoder<PasswordPolicyResponseControl> DECODER =
131    new Decoder();
132  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
133
134
135
136
137  /** The BER type value for the warning element of the control value. */
138  public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0;
139
140
141
142  /** The BER type value for the error element of the control value. */
143  public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81;
144
145
146
147  /** The warning value for this password policy response control. */
148  private int warningValue;
149
150  /** The error type for this password policy response control. */
151  private PasswordPolicyErrorType errorType;
152
153  /** The warning type for the password policy response control. */
154  private PasswordPolicyWarningType warningType;
155
156
157
158  /**
159   * Creates a new instance of the password policy response control with the
160   * default OID and criticality, and without either a warning or an error flag.
161   */
162  public PasswordPolicyResponseControl()
163  {
164    this(false, null, -1, null);
165  }
166
167
168
169  /**
170   * Creates a new instance of this password policy response control with the
171   * default OID and criticality, and with the provided warning and/or error
172   * flag information.
173   *
174   * @param  warningType   The warning type to use for this password policy
175   *                       response control, or <CODE>null</CODE> if there
176   *                       should not be a warning flag.
177   * @param  warningValue  The warning value to use for this password policy
178   *                       response control, if applicable.
179   * @param  errorType     The error type to use for this password policy
180   *                       response control, or <CODE>null</CODE> if there
181   *                       should not be an error flag.
182   */
183  public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType,
184                                       int warningValue,
185                                       PasswordPolicyErrorType errorType)
186  {
187    this(false, warningType, warningValue, errorType);
188  }
189
190
191
192  /**
193   * Creates a new instance of the password policy request control with the
194   * provided information.
195   *
196   * @param  isCritical    Indicates whether support for this control should be
197   *                       considered a critical part of the client processing.
198   * @param  warningType   The warning type to use for this password policy
199   *                       response control, or <CODE>null</CODE> if there
200   *                       should not be a warning flag.
201   * @param  warningValue  The warning value to use for this password policy
202   *                       response control, if applicable.
203   * @param  errorType     The error type to use for this password policy
204   *                       response control, or <CODE>null</CODE> if there
205   *                       should not be an error flag.
206   */
207  public PasswordPolicyResponseControl(boolean isCritical,
208                                       PasswordPolicyWarningType warningType,
209                                       int warningValue,
210                                       PasswordPolicyErrorType errorType)
211  {
212    super(OID_PASSWORD_POLICY_CONTROL, isCritical);
213
214    this.warningType  = warningType;
215    this.warningValue = warningValue;
216    this.errorType    = errorType;
217  }
218
219
220
221  /**
222   * Writes this control's value to an ASN.1 writer. The value (if any) must be
223   * written as an ASN1OctetString.
224   *
225   * @param writer The ASN.1 writer to use.
226   * @throws IOException If a problem occurs while writing to the stream.
227   */
228  @Override
229  protected void writeValue(ASN1Writer writer) throws IOException {
230    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
231
232    writer.writeStartSequence();
233    if (warningType != null)
234    {
235      // Just write the CHOICE element as a single element SEQUENCE.
236      writer.writeStartSequence(TYPE_WARNING_ELEMENT);
237      writer.writeInteger(warningType.getType(), warningValue);
238      writer.writeEndSequence();
239    }
240
241    if (errorType != null)
242    {
243      writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue());
244    }
245    writer.writeEndSequence();
246
247    writer.writeEndSequence();
248  }
249
250
251  /**
252   * Retrieves the password policy warning type contained in this control.
253   *
254   * @return  The password policy warning type contained in this control, or
255   *          <CODE>null</CODE> if there is no warning type.
256   */
257  public PasswordPolicyWarningType getWarningType()
258  {
259    return warningType;
260  }
261
262
263
264  /**
265   * Retrieves the password policy warning value for this control.  The value is
266   * undefined if there is no warning type.
267   *
268   * @return  The password policy warning value for this control.
269   */
270  public int getWarningValue()
271  {
272    return warningValue;
273  }
274
275
276
277  /**
278   * Retrieves the password policy error type contained in this control.
279   *
280   * @return  The password policy error type contained in this control, or
281   *          <CODE>null</CODE> if there is no error type.
282   */
283  public PasswordPolicyErrorType getErrorType()
284  {
285    return errorType;
286  }
287
288  @Override
289  public void toString(StringBuilder buffer)
290  {
291    buffer.append("PasswordPolicyResponseControl(");
292
293    if (warningType != null)
294    {
295      buffer.append(warningType);
296      buffer.append("=");
297      buffer.append(warningValue);
298
299      if (errorType != null)
300      {
301        buffer.append(", ");
302      }
303    }
304
305    if (errorType != null)
306    {
307      buffer.append(errorType);
308    }
309
310    buffer.append(")");
311  }
312}
313