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