001/*
002 * Copyright 2015-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.controls;
022
023
024
025import java.io.Serializable;
026import java.util.ArrayList;
027
028import com.unboundid.asn1.ASN1Boolean;
029import com.unboundid.asn1.ASN1Element;
030import com.unboundid.asn1.ASN1OctetString;
031import com.unboundid.asn1.ASN1Sequence;
032import com.unboundid.ldap.sdk.LDAPException;
033import com.unboundid.ldap.sdk.ResultCode;
034import com.unboundid.ldap.sdk.unboundidds.extensions.PasswordQualityRequirement;
035import com.unboundid.util.Debug;
036import com.unboundid.util.NotMutable;
037import com.unboundid.util.StaticUtils;
038import com.unboundid.util.ThreadSafety;
039import com.unboundid.util.ThreadSafetyLevel;
040import com.unboundid.util.Validator;
041
042import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
043
044
045
046/**
047 * This class provides a data structure that holds information about the result
048 * of attempting validation with a proposed password against a password quality
049 * requirement.
050 * <BR>
051 * <BLOCKQUOTE>
052 *   <B>NOTE:</B>  This class, and other classes within the
053 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
054 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
055 *   server products.  These classes provide support for proprietary
056 *   functionality or for external specifications that are not considered stable
057 *   or mature enough to be guaranteed to work in an interoperable way with
058 *   other types of LDAP servers.
059 * </BLOCKQUOTE>
060 * <BR>
061 * If it appears in an LDAP protocol element (e.g., in a password validation
062 * details response control), then the password quality validation result object
063 * should have the following ASN.1 encoding:
064 * <PRE>
065 *   PasswordQualityRequirementValidationResult ::= SEQUENCE {
066 *        passwordRequirement      PasswordQualityRequirement,
067 *        requirementSatisfied     BOOLEAN,
068 *        additionalInfo           [0] OCTET STRING OPTIONAL }
069 * </PRE>
070 */
071@NotMutable()
072@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
073public final class PasswordQualityRequirementValidationResult
074       implements Serializable
075{
076  /**
077   * The BER type for the additional info element of the value sequence.
078   */
079  private static final byte TYPE_ADDITIONAL_INFO = (byte) 0x80;
080
081
082
083  /**
084   * The serial version UID for this serializable class.
085   */
086  private static final long serialVersionUID = -8048878239770726375L;
087
088
089
090  // Indicates whether the proposed password satisfied the constraints of the
091  // associated password quality requirement.
092  private final boolean requirementSatisfied;
093
094  // The password quality requirement to which this validation result applies.
095  private final PasswordQualityRequirement passwordRequirement;
096
097  // An optional message with additional information about the result of the
098  // validation for the proposed password with respect to the associated
099  // password quality requirement.
100  private final String additionalInfo;
101
102
103
104  /**
105   * Creates a new password quality requirement validation result object with
106   * the provided information.
107   *
108   * @param  passwordRequirement   The password quality requirement to which
109   *                               this validation result applies.  This must
110   *                               not be {@code null}.
111   * @param  requirementSatisfied  Indicates whether the proposed password
112   *                               satisfied the constraints of the associated
113   *                               password quality requirement.
114   * @param  additionalInfo        An optional message with additional
115   *                               information about the result of the
116   *                               validation for the proposed password with
117   *                               respect to the associated password quality
118   *                               requirement.
119   */
120  public PasswordQualityRequirementValidationResult(
121              final PasswordQualityRequirement passwordRequirement,
122              final boolean requirementSatisfied, final String additionalInfo)
123  {
124    Validator.ensureNotNull(passwordRequirement);
125
126    this.passwordRequirement  = passwordRequirement;
127    this.requirementSatisfied = requirementSatisfied;
128    this.additionalInfo       = additionalInfo;
129  }
130
131
132
133  /**
134   * Retrieves the password quality requirement to which this validation result
135   * applies.
136   *
137   * @return  The password quality requirement to which this validation result
138   * applies.
139   */
140  public PasswordQualityRequirement getPasswordRequirement()
141  {
142    return passwordRequirement;
143  }
144
145
146
147  /**
148   * Indicates whether the proposed password satisfied the constraints of the
149   * associated password quality requirement.
150   *
151   * @return  {@code true} if the proposed password satisfied the constraints of
152   *          the associated password quality requirement, or {@code false} if
153   *          not.
154   */
155  public boolean requirementSatisfied()
156  {
157    return requirementSatisfied;
158  }
159
160
161
162  /**
163   * Retrieves a message with additional information about the result of the
164   * validation of the proposed password with respect to the associated
165   * password quality requirement.
166   *
167   * @return  A message with additional information about the result of the
168   *          validation, or {@code null} if no additional information is
169   *          available.
170   */
171  public String getAdditionalInfo()
172  {
173    return additionalInfo;
174  }
175
176
177
178  /**
179   * Encodes this password quality requirement validation result object to an
180   * ASN.1 element.
181   *
182   * @return  The ASN.1 element that provides an encoded representation of this
183   *          object.
184   */
185  public ASN1Element encode()
186  {
187    final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
188    elements.add(passwordRequirement.encode());
189    elements.add(new ASN1Boolean(requirementSatisfied));
190
191    if (additionalInfo != null)
192    {
193      elements.add(new ASN1OctetString(TYPE_ADDITIONAL_INFO, additionalInfo));
194    }
195
196    return new ASN1Sequence(elements);
197  }
198
199
200
201  /**
202   * Decodes the provided ASN.1 element as a password quality requirement
203   * validation result.
204   *
205   * @param  element  The ASN.1 element to be decoded as a password quality
206   *                  requirement validation result.
207   *
208   * @return  The ASN.1 element containing the encoded password quality
209   *          requirement validation result.
210   *
211   * @throws  LDAPException  If a problem is encountered while attempting to
212   *                         decode the provided ASN.1 element.
213   */
214  public static PasswordQualityRequirementValidationResult decode(
215                     final ASN1Element element)
216         throws LDAPException
217  {
218    try
219    {
220      final ASN1Element[] elements =
221           ASN1Sequence.decodeAsSequence(element).elements();
222      final PasswordQualityRequirement passwordRequirement =
223           PasswordQualityRequirement.decode(elements[0]);
224      final boolean requirementSatisfied =
225           ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
226
227      String additionalInfo = null;
228      for (int i=2; i < elements.length; i++)
229      {
230        switch (elements[i].getType())
231        {
232          case TYPE_ADDITIONAL_INFO:
233            additionalInfo =
234                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
235            break;
236
237          default:
238            throw new LDAPException(ResultCode.DECODING_ERROR,
239                 ERR_PW_REQ_VALIDATION_RESULT_INVALID_ELEMENT_TYPE.get(
240                      StaticUtils.toHex(elements[i].getType())));
241        }
242      }
243
244      return new PasswordQualityRequirementValidationResult(passwordRequirement,
245           requirementSatisfied, additionalInfo);
246    }
247    catch (final LDAPException le)
248    {
249      Debug.debugException(le);
250      throw le;
251    }
252    catch (final Exception e)
253    {
254      Debug.debugException(e);
255      throw new LDAPException(ResultCode.DECODING_ERROR,
256           ERR_PW_REQ_VALIDATION_RESULT_CANNOT_DECODE.get(
257                StaticUtils.getExceptionMessage(e)),
258           e);
259    }
260  }
261
262
263
264  /**
265   * Retrieves a string representation of this password quality requirement
266   * validation result.
267   *
268   * @return  A string representation of this password quality requirement
269   *          validation result.
270   */
271  @Override()
272  public String toString()
273  {
274    final StringBuilder buffer = new StringBuilder();
275    toString(buffer);
276    return buffer.toString();
277  }
278
279
280
281  /**
282   * Appends a string representation of this password quality requirement
283   * validation result to the provided buffer.
284   *
285   * @param  buffer  The buffer to which the information should be appended.
286   */
287  public void toString(final StringBuilder buffer)
288  {
289    buffer.append("PasswordQualityRequirementValidationResult(requirement=");
290    passwordRequirement.toString(buffer);
291    buffer.append(", requirementSatisfied=");
292    buffer.append(requirementSatisfied);
293
294    if (additionalInfo != null)
295    {
296      buffer.append(", additionalInfo='");
297      buffer.append(additionalInfo);
298      buffer.append('\'');
299    }
300
301    buffer.append(')');
302  }
303}