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-2016 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 /** ControlDecoder implementation to decode this control from a ByteString. */ 044 private static final class Decoder 045 implements ControlDecoder<PasswordPolicyResponseControl> 046 { 047 @Override 048 public PasswordPolicyResponseControl decode(boolean isCritical, 049 ByteString value) 050 throws DirectoryException 051 { 052 if (value == null) 053 { 054 // The response control must always have a value. 055 LocalizableMessage message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get(); 056 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 057 } 058 059 ASN1Reader reader = ASN1.getReader(value); 060 try 061 { 062 PasswordPolicyWarningType warningType = null; 063 PasswordPolicyErrorType errorType = null; 064 int warningValue = -1; 065 066 reader.readStartSequence(); 067 068 if(reader.hasNextElement() && 069 reader.peekType() == TYPE_WARNING_ELEMENT) 070 { 071 // Its a CHOICE element. Read as sequence to retrieve 072 // nested element. 073 reader.readStartSequence(); 074 warningType = 075 PasswordPolicyWarningType.valueOf(reader.peekType()); 076 warningValue = (int)reader.readInteger(); 077 if (warningType == null) 078 { 079 LocalizableMessage message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get( 080 byteToHex(reader.peekType())); 081 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, 082 message); 083 } 084 reader.readEndSequence(); 085 } 086 if(reader.hasNextElement() && 087 reader.peekType() == TYPE_ERROR_ELEMENT) 088 { 089 int errorValue = (int)reader.readInteger(); 090 errorType = PasswordPolicyErrorType.valueOf(errorValue); 091 if (errorType == null) 092 { 093 LocalizableMessage message = 094 ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue); 095 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, 096 message); 097 } 098 } 099 100 reader.readEndSequence(); 101 102 return new PasswordPolicyResponseControl(isCritical, 103 warningType, warningValue, 104 errorType); 105 } 106 catch (DirectoryException de) 107 { 108 throw de; 109 } 110 catch (Exception e) 111 { 112 logger.traceException(e); 113 114 LocalizableMessage message = 115 ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e)); 116 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 117 } 118 } 119 120 121 @Override 122 public String getOID() 123 { 124 return OID_ACCOUNT_USABLE_CONTROL; 125 } 126 127 } 128 129 /** The Control Decoder that can be used to decode this control. */ 130 public static final ControlDecoder<PasswordPolicyResponseControl> DECODER = 131 new Decoder(); 132 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 133 134 135 136 137 /** The BER type value for the warning element of the control value. */ 138 public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0; 139 140 141 142 /** The BER type value for the error element of the control value. */ 143 public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81; 144 145 146 147 /** The warning value for this password policy response control. */ 148 private int warningValue; 149 150 /** The error type for this password policy response control. */ 151 private PasswordPolicyErrorType errorType; 152 153 /** The warning type for the password policy response control. */ 154 private PasswordPolicyWarningType warningType; 155 156 157 158 /** 159 * Creates a new instance of the password policy response control with the 160 * default OID and criticality, and without either a warning or an error flag. 161 */ 162 public PasswordPolicyResponseControl() 163 { 164 this(false, null, -1, null); 165 } 166 167 168 169 /** 170 * Creates a new instance of this password policy response control with the 171 * default OID and criticality, and with the provided warning and/or error 172 * flag information. 173 * 174 * @param warningType The warning type to use for this password policy 175 * response control, or <CODE>null</CODE> if there 176 * should not be a warning flag. 177 * @param warningValue The warning value to use for this password policy 178 * response control, if applicable. 179 * @param errorType The error type to use for this password policy 180 * response control, or <CODE>null</CODE> if there 181 * should not be an error flag. 182 */ 183 public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType, 184 int warningValue, 185 PasswordPolicyErrorType errorType) 186 { 187 this(false, warningType, warningValue, errorType); 188 } 189 190 191 192 /** 193 * Creates a new instance of the password policy request control with the 194 * provided information. 195 * 196 * @param isCritical Indicates whether support for this control should be 197 * considered a critical part of the client processing. 198 * @param warningType The warning type to use for this password policy 199 * response control, or <CODE>null</CODE> if there 200 * should not be a warning flag. 201 * @param warningValue The warning value to use for this password policy 202 * response control, if applicable. 203 * @param errorType The error type to use for this password policy 204 * response control, or <CODE>null</CODE> if there 205 * should not be an error flag. 206 */ 207 public PasswordPolicyResponseControl(boolean isCritical, 208 PasswordPolicyWarningType warningType, 209 int warningValue, 210 PasswordPolicyErrorType errorType) 211 { 212 super(OID_PASSWORD_POLICY_CONTROL, isCritical); 213 214 this.warningType = warningType; 215 this.warningValue = warningValue; 216 this.errorType = errorType; 217 } 218 219 220 221 /** 222 * Writes this control's value to an ASN.1 writer. The value (if any) must be 223 * written as an ASN1OctetString. 224 * 225 * @param writer The ASN.1 writer to use. 226 * @throws IOException If a problem occurs while writing to the stream. 227 */ 228 @Override 229 protected void writeValue(ASN1Writer writer) throws IOException { 230 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 231 232 writer.writeStartSequence(); 233 if (warningType != null) 234 { 235 // Just write the CHOICE element as a single element SEQUENCE. 236 writer.writeStartSequence(TYPE_WARNING_ELEMENT); 237 writer.writeInteger(warningType.getType(), warningValue); 238 writer.writeEndSequence(); 239 } 240 241 if (errorType != null) 242 { 243 writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue()); 244 } 245 writer.writeEndSequence(); 246 247 writer.writeEndSequence(); 248 } 249 250 251 /** 252 * Retrieves the password policy warning type contained in this control. 253 * 254 * @return The password policy warning type contained in this control, or 255 * <CODE>null</CODE> if there is no warning type. 256 */ 257 public PasswordPolicyWarningType getWarningType() 258 { 259 return warningType; 260 } 261 262 263 264 /** 265 * Retrieves the password policy warning value for this control. The value is 266 * undefined if there is no warning type. 267 * 268 * @return The password policy warning value for this control. 269 */ 270 public int getWarningValue() 271 { 272 return warningValue; 273 } 274 275 276 277 /** 278 * Retrieves the password policy error type contained in this control. 279 * 280 * @return The password policy error type contained in this control, or 281 * <CODE>null</CODE> if there is no error type. 282 */ 283 public PasswordPolicyErrorType getErrorType() 284 { 285 return errorType; 286 } 287 288 @Override 289 public void toString(StringBuilder buffer) 290 { 291 buffer.append("PasswordPolicyResponseControl("); 292 293 if (warningType != null) 294 { 295 buffer.append(warningType); 296 buffer.append("="); 297 buffer.append(warningValue); 298 299 if (errorType != null) 300 { 301 buffer.append(", "); 302 } 303 } 304 305 if (errorType != null) 306 { 307 buffer.append(errorType); 308 } 309 310 buffer.append(")"); 311 } 312} 313