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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.controls;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    
034    import org.opends.server.protocols.asn1.ASN1Element;
035    import org.opends.server.protocols.asn1.ASN1Enumerated;
036    import org.opends.server.protocols.asn1.ASN1Exception;
037    import org.opends.server.protocols.asn1.ASN1Integer;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.protocols.asn1.ASN1Sequence;
040    import org.opends.server.protocols.ldap.LDAPResultCode;
041    import org.opends.server.types.Control;
042    import org.opends.server.types.LDAPException;
043    
044    import static org.opends.server.loggers.debug.DebugLogger.*;
045    import org.opends.server.loggers.debug.DebugTracer;
046    import org.opends.server.types.DebugLogLevel;
047    import static org.opends.messages.ProtocolMessages.*;
048    import static org.opends.server.util.ServerConstants.*;
049    import static org.opends.server.util.StaticUtils.*;
050    
051    
052    
053    /**
054     * This class implements the password policy response control defined in
055     * draft-behera-ldap-password-policy.  The value may have zero, one, or two
056     * elements, which may include flags to indicate a warning and/or an error.
057     */
058    public class PasswordPolicyResponseControl
059           extends Control
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = getTracer();
065    
066    
067    
068    
069      /**
070       * The BER type value for the warning element of the control value.
071       */
072      public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0;
073    
074    
075    
076      /**
077       * The BER type value for the error element of the control value.
078       */
079      public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81;
080    
081    
082    
083      // The warning value for this password policy response control.
084      private int warningValue;
085    
086      // The error type for this password policy response control.
087      private PasswordPolicyErrorType errorType;
088    
089      // The warning type for the password policy response control.
090      private PasswordPolicyWarningType warningType;
091    
092    
093    
094      /**
095       * Creates a new instance of the password policy response control with the
096       * default OID and criticality, and without either a warning or an error flag.
097       */
098      public PasswordPolicyResponseControl()
099      {
100        super(OID_PASSWORD_POLICY_CONTROL, false, encodeValue(null, -1, null));
101    
102    
103        warningType  = null;
104        errorType    = null;
105        warningValue = -1;
106      }
107    
108    
109    
110      /**
111       * Creates a new instance of this password policy response control with the
112       * default OID and criticality, and with the provided warning and/or error
113       * flag information.
114       *
115       * @param  warningType   The warning type to use for this password policy
116       *                       response control, or <CODE>null</CODE> if there
117       *                       should not be a warning flag.
118       * @param  warningValue  The warning value to use for this password policy
119       *                       response control, if applicable.
120       * @param  errorType     The error type to use for this password policy
121       *                       response control, or <CODE>null</CODE> if there
122       *                       should not be an error flag.
123       */
124      public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType,
125                                           int warningValue,
126                                           PasswordPolicyErrorType errorType)
127      {
128        super(OID_PASSWORD_POLICY_CONTROL, false,
129              encodeValue(warningType, warningValue, errorType));
130    
131    
132        this.warningType  = warningType;
133        this.warningValue = warningValue;
134        this.errorType    = errorType;
135      }
136    
137    
138    
139      /**
140       * Creates a new instance of the password policy request control with the
141       * provided information.
142       *
143       * @param  oid           The OID to use for this control.
144       * @param  isCritical    Indicates whether support for this control should be
145       *                       considered a critical part of the client processing.
146       * @param  warningType   The warning type to use for this password policy
147       *                       response control, or <CODE>null</CODE> if there
148       *                       should not be a warning flag.
149       * @param  warningValue  The warning value to use for this password policy
150       *                       response control, if applicable.
151       * @param  errorType     The error type to use for this password policy
152       *                       response control, or <CODE>null</CODE> if there
153       *                       should not be an error flag.
154       */
155      public PasswordPolicyResponseControl(String oid, boolean isCritical,
156                                           PasswordPolicyWarningType warningType,
157                                           int warningValue,
158                                           PasswordPolicyErrorType errorType)
159      {
160        super(oid, isCritical, encodeValue(warningType, warningValue, errorType));
161    
162    
163        this.warningType  = warningType;
164        this.warningValue = warningValue;
165        this.errorType    = errorType;
166      }
167    
168    
169    
170      /**
171       * Creates a new instance of the password policy request control with the
172       * provided information.
173       *
174       * @param  oid           The OID to use for this control.
175       * @param  isCritical    Indicates whether support for this control should be
176       *                       considered a critical part of the client processing.
177       * @param  warningType   The warning type to use for this password policy
178       *                       response control, or <CODE>null</CODE> if there
179       *                       should not be a warning flag.
180       * @param  warningValue  The warning value to use for this password policy
181       *                       response control, if applicable.
182       * @param  errorType     The error type to use for this password policy
183       *                       response control, or <CODE>null</CODE> if there
184       *                       should not be an error flag.
185       * @param  encodedValue  The pre-encoded value to use for this control.
186       */
187      private PasswordPolicyResponseControl(String oid, boolean isCritical,
188                                            PasswordPolicyWarningType warningType,
189                                            int warningValue,
190                                            PasswordPolicyErrorType errorType,
191                                            ASN1OctetString encodedValue)
192      {
193        super(oid, isCritical, encodedValue);
194    
195    
196        this.warningType  = warningType;
197        this.warningValue = warningValue;
198        this.errorType    = errorType;
199      }
200    
201    
202    
203      /**
204       * Encodes the provided information into an ASN.1 octet string suitable for
205       * use as the value for this control.
206       *
207       * @param  warningType   The warning type to use for this password policy
208       *                       response control, or <CODE>null</CODE> if there
209       *                       should not be a warning flag.
210       * @param  warningValue  The warning value to use for this password policy
211       *                       response control, if applicable.
212       * @param  errorType     The error type to use for this password policy
213       *                       response control, or <CODE>null</CODE> if there
214       *                       should not be an error flag.
215       *
216       * @return  An ASN.1 octet string containing the encoded control value.
217       */
218      private static ASN1OctetString encodeValue(
219                                          PasswordPolicyWarningType warningType,
220                                          int warningValue,
221                                          PasswordPolicyErrorType errorType)
222      {
223        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
224    
225        if (warningType != null)
226        {
227          ASN1Integer warningInteger = new ASN1Integer(warningType.getType(),
228                                                       warningValue);
229          elements.add(new ASN1Element(TYPE_WARNING_ELEMENT,
230                                       warningInteger.encode()));
231        }
232    
233        if (errorType != null)
234        {
235          elements.add(new ASN1Enumerated(TYPE_ERROR_ELEMENT,
236                                          errorType.intValue()));
237        }
238    
239        ASN1Sequence valueSequence = new ASN1Sequence(elements);
240        return new ASN1OctetString(valueSequence.encode());
241      }
242    
243    
244    
245      /**
246       * Creates a new password policy response control from the contents of the
247       * provided control.
248       *
249       * @param  control  The generic control containing the information to use to
250       *                  create this password policy response control.
251       *
252       * @return  The password policy response control decoded from the provided
253       *          control.
254       *
255       * @throws  LDAPException  If this control cannot be decoded as a valid
256       *                         password policy response control.
257       */
258      public static PasswordPolicyResponseControl decodeControl(Control control)
259             throws LDAPException
260      {
261        ASN1OctetString controlValue = control.getValue();
262        if (controlValue == null)
263        {
264          // The response control must always have a value.
265          Message message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get();
266          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
267        }
268    
269    
270        try
271        {
272          PasswordPolicyWarningType warningType  = null;
273          PasswordPolicyErrorType   errorType    = null;
274          int                       warningValue = -1;
275    
276          ASN1Sequence valueSequence =
277               ASN1Sequence.decodeAsSequence(controlValue.value());
278          for (ASN1Element e : valueSequence.elements())
279          {
280            switch (e.getType())
281            {
282              case TYPE_WARNING_ELEMENT:
283                ASN1Integer integerElement = ASN1Integer.decodeAsInteger(e.value());
284                warningValue = integerElement.intValue();
285                warningType =
286                     PasswordPolicyWarningType.valueOf(integerElement.getType());
287                if (warningType == null)
288                {
289                  Message message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(
290                      byteToHex(integerElement.getType()));
291                  throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
292                }
293                break;
294    
295              case TYPE_ERROR_ELEMENT:
296                int errorValue = e.decodeAsEnumerated().intValue();
297                errorType = PasswordPolicyErrorType.valueOf(errorValue);
298                if (errorType == null)
299                {
300                  Message message =
301                      ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue);
302                  throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
303                }
304                break;
305    
306              default:
307                Message message = ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE.get(
308                    byteToHex(e.getType()));
309                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
310            }
311          }
312    
313          return new PasswordPolicyResponseControl(control.getOID(),
314                                                   control.isCritical(),
315                                                   warningType, warningValue,
316                                                   errorType, controlValue);
317        }
318        catch (LDAPException le)
319        {
320          throw le;
321        }
322        catch (ASN1Exception ae)
323        {
324          if (debugEnabled())
325          {
326            TRACER.debugCaught(DebugLogLevel.ERROR, ae);
327          }
328    
329          Message message = ERR_PWPOLICYRES_DECODE_ERROR.get(ae.getMessage());
330          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
331        }
332        catch (Exception e)
333        {
334          if (debugEnabled())
335          {
336            TRACER.debugCaught(DebugLogLevel.ERROR, e);
337          }
338    
339          Message message =
340              ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e));
341          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
342        }
343      }
344    
345    
346    
347      /**
348       * Retrieves the password policy warning type contained in this control.
349       *
350       * @return  The password policy warning type contained in this control, or
351       *          <CODE>null</CODE> if there is no warning type.
352       */
353      public PasswordPolicyWarningType getWarningType()
354      {
355        return warningType;
356      }
357    
358    
359    
360      /**
361       * Retrieves the password policy warning value for this control.  The value is
362       * undefined if there is no warning type.
363       *
364       * @return  The password policy warning value for this control.
365       */
366      public int getWarningValue()
367      {
368        return warningValue;
369      }
370    
371    
372    
373      /**
374       * Retrieves the password policy error type contained in this control.
375       *
376       * @return  The password policy error type contained in this control, or
377       *          <CODE>null</CODE> if there is no error type.
378       */
379      public PasswordPolicyErrorType getErrorType()
380      {
381        return errorType;
382      }
383    
384    
385    
386      /**
387       * Retrieves a string representation of this password policy response control.
388       *
389       * @return  A string representation of this password policy response control.
390       */
391      public String toString()
392      {
393        StringBuilder buffer = new StringBuilder();
394        toString(buffer);
395        return buffer.toString();
396      }
397    
398    
399    
400      /**
401       * Appends a string representation of this password policy response control to
402       * the provided buffer.
403       *
404       * @param  buffer  The buffer to which the information should be appended.
405       */
406      public void toString(StringBuilder buffer)
407      {
408        buffer.append("PasswordPolicyResponseControl(");
409    
410        if (warningType != null)
411        {
412          buffer.append(warningType.toString());
413          buffer.append("=");
414          buffer.append(warningValue);
415    
416          if (errorType != null)
417          {
418            buffer.append(", ");
419          }
420        }
421    
422        if (errorType != null)
423        {
424          buffer.append(errorType.toString());
425        }
426    
427        buffer.append(")");
428      }
429    }
430