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 055 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 056 * for proprietary functionality or for external specifications that are not 057 * considered stable or mature enough to be guaranteed to work in an 058 * interoperable way with 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<>(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}