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