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