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