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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS. 026 */ 027package org.opends.server.controls; 028import org.forgerock.i18n.LocalizableMessage; 029 030 031 032import java.io.IOException; 033 034import org.forgerock.opendj.io.*; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036import org.opends.server.types.*; 037import org.forgerock.opendj.ldap.ResultCode; 038import org.forgerock.opendj.ldap.ByteString; 039import static org.opends.messages.ProtocolMessages.*; 040import static org.opends.server.util.ServerConstants.*; 041import static org.opends.server.util.StaticUtils.*; 042 043 044 045/** 046 * This class implements the password policy response control defined in 047 * draft-behera-ldap-password-policy. The value may have zero, one, or two 048 * elements, which may include flags to indicate a warning and/or an error. 049 */ 050public class PasswordPolicyResponseControl 051 extends Control 052{ 053 /** 054 * ControlDecoder implementation to decode this control from a ByteString. 055 */ 056 private static final class Decoder 057 implements ControlDecoder<PasswordPolicyResponseControl> 058 { 059 /** {@inheritDoc} */ 060 public PasswordPolicyResponseControl decode(boolean isCritical, 061 ByteString value) 062 throws DirectoryException 063 { 064 if (value == null) 065 { 066 // The response control must always have a value. 067 LocalizableMessage message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get(); 068 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 069 } 070 071 ASN1Reader reader = ASN1.getReader(value); 072 try 073 { 074 PasswordPolicyWarningType warningType = null; 075 PasswordPolicyErrorType errorType = null; 076 int warningValue = -1; 077 078 reader.readStartSequence(); 079 080 if(reader.hasNextElement() && 081 reader.peekType() == TYPE_WARNING_ELEMENT) 082 { 083 // Its a CHOICE element. Read as sequence to retrieve 084 // nested element. 085 reader.readStartSequence(); 086 warningType = 087 PasswordPolicyWarningType.valueOf(reader.peekType()); 088 warningValue = (int)reader.readInteger(); 089 if (warningType == null) 090 { 091 LocalizableMessage message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get( 092 byteToHex(reader.peekType())); 093 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, 094 message); 095 } 096 reader.readEndSequence(); 097 } 098 if(reader.hasNextElement() && 099 reader.peekType() == TYPE_ERROR_ELEMENT) 100 { 101 int errorValue = (int)reader.readInteger(); 102 errorType = PasswordPolicyErrorType.valueOf(errorValue); 103 if (errorType == null) 104 { 105 LocalizableMessage message = 106 ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue); 107 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, 108 message); 109 } 110 } 111 112 reader.readEndSequence(); 113 114 return new PasswordPolicyResponseControl(isCritical, 115 warningType, warningValue, 116 errorType); 117 } 118 catch (DirectoryException de) 119 { 120 throw de; 121 } 122 catch (Exception e) 123 { 124 logger.traceException(e); 125 126 LocalizableMessage message = 127 ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e)); 128 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 129 } 130 } 131 132 133 public String getOID() 134 { 135 return OID_ACCOUNT_USABLE_CONTROL; 136 } 137 138 } 139 140 /** 141 * The Control Decoder that can be used to decode this control. 142 */ 143 public static final ControlDecoder<PasswordPolicyResponseControl> DECODER = 144 new Decoder(); 145 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 146 147 148 149 150 /** 151 * The BER type value for the warning element of the control value. 152 */ 153 public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0; 154 155 156 157 /** 158 * The BER type value for the error element of the control value. 159 */ 160 public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81; 161 162 163 164 /** The warning value for this password policy response control. */ 165 private int warningValue; 166 167 /** The error type for this password policy response control. */ 168 private PasswordPolicyErrorType errorType; 169 170 /** The warning type for the password policy response control. */ 171 private PasswordPolicyWarningType warningType; 172 173 174 175 /** 176 * Creates a new instance of the password policy response control with the 177 * default OID and criticality, and without either a warning or an error flag. 178 */ 179 public PasswordPolicyResponseControl() 180 { 181 this(false, null, -1, null); 182 } 183 184 185 186 /** 187 * Creates a new instance of this password policy response control with the 188 * default OID and criticality, and with the provided warning and/or error 189 * flag information. 190 * 191 * @param warningType The warning type to use for this password policy 192 * response control, or <CODE>null</CODE> if there 193 * should not be a warning flag. 194 * @param warningValue The warning value to use for this password policy 195 * response control, if applicable. 196 * @param errorType The error type to use for this password policy 197 * response control, or <CODE>null</CODE> if there 198 * should not be an error flag. 199 */ 200 public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType, 201 int warningValue, 202 PasswordPolicyErrorType errorType) 203 { 204 this(false, warningType, warningValue, errorType); 205 } 206 207 208 209 /** 210 * Creates a new instance of the password policy request control with the 211 * provided information. 212 * 213 * @param isCritical Indicates whether support for this control should be 214 * considered a critical part of the client processing. 215 * @param warningType The warning type to use for this password policy 216 * response control, or <CODE>null</CODE> if there 217 * should not be a warning flag. 218 * @param warningValue The warning value to use for this password policy 219 * response control, if applicable. 220 * @param errorType The error type to use for this password policy 221 * response control, or <CODE>null</CODE> if there 222 * should not be an error flag. 223 */ 224 public PasswordPolicyResponseControl(boolean isCritical, 225 PasswordPolicyWarningType warningType, 226 int warningValue, 227 PasswordPolicyErrorType errorType) 228 { 229 super(OID_PASSWORD_POLICY_CONTROL, isCritical); 230 231 this.warningType = warningType; 232 this.warningValue = warningValue; 233 this.errorType = errorType; 234 } 235 236 237 238 /** 239 * Writes this control's value to an ASN.1 writer. The value (if any) must be 240 * written as an ASN1OctetString. 241 * 242 * @param writer The ASN.1 writer to use. 243 * @throws IOException If a problem occurs while writing to the stream. 244 */ 245 @Override 246 protected void writeValue(ASN1Writer writer) throws IOException { 247 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 248 249 writer.writeStartSequence(); 250 if (warningType != null) 251 { 252 // Just write the CHOICE element as a single element SEQUENCE. 253 writer.writeStartSequence(TYPE_WARNING_ELEMENT); 254 writer.writeInteger(warningType.getType(), warningValue); 255 writer.writeEndSequence(); 256 } 257 258 if (errorType != null) 259 { 260 writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue()); 261 } 262 writer.writeEndSequence(); 263 264 writer.writeEndSequence(); 265 } 266 267 268 /** 269 * Retrieves the password policy warning type contained in this control. 270 * 271 * @return The password policy warning type contained in this control, or 272 * <CODE>null</CODE> if there is no warning type. 273 */ 274 public PasswordPolicyWarningType getWarningType() 275 { 276 return warningType; 277 } 278 279 280 281 /** 282 * Retrieves the password policy warning value for this control. The value is 283 * undefined if there is no warning type. 284 * 285 * @return The password policy warning value for this control. 286 */ 287 public int getWarningValue() 288 { 289 return warningValue; 290 } 291 292 293 294 /** 295 * Retrieves the password policy error type contained in this control. 296 * 297 * @return The password policy error type contained in this control, or 298 * <CODE>null</CODE> if there is no error type. 299 */ 300 public PasswordPolicyErrorType getErrorType() 301 { 302 return errorType; 303 } 304 305 306 307 /** 308 * Appends a string representation of this password policy response control to 309 * the provided buffer. 310 * 311 * @param buffer The buffer to which the information should be appended. 312 */ 313 @Override 314 public void toString(StringBuilder buffer) 315 { 316 buffer.append("PasswordPolicyResponseControl("); 317 318 if (warningType != null) 319 { 320 buffer.append(warningType); 321 buffer.append("="); 322 buffer.append(warningValue); 323 324 if (errorType != null) 325 { 326 buffer.append(", "); 327 } 328 } 329 330 if (errorType != null) 331 { 332 buffer.append(errorType); 333 } 334 335 buffer.append(")"); 336 } 337} 338