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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.controls; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.ArrayList; 033 034 import org.opends.server.protocols.asn1.ASN1Element; 035 import org.opends.server.protocols.asn1.ASN1Enumerated; 036 import org.opends.server.protocols.asn1.ASN1Exception; 037 import org.opends.server.protocols.asn1.ASN1Integer; 038 import org.opends.server.protocols.asn1.ASN1OctetString; 039 import org.opends.server.protocols.asn1.ASN1Sequence; 040 import org.opends.server.protocols.ldap.LDAPResultCode; 041 import org.opends.server.types.Control; 042 import org.opends.server.types.LDAPException; 043 044 import static org.opends.server.loggers.debug.DebugLogger.*; 045 import org.opends.server.loggers.debug.DebugTracer; 046 import org.opends.server.types.DebugLogLevel; 047 import static org.opends.messages.ProtocolMessages.*; 048 import static org.opends.server.util.ServerConstants.*; 049 import static org.opends.server.util.StaticUtils.*; 050 051 052 053 /** 054 * This class implements the password policy response control defined in 055 * draft-behera-ldap-password-policy. The value may have zero, one, or two 056 * elements, which may include flags to indicate a warning and/or an error. 057 */ 058 public class PasswordPolicyResponseControl 059 extends Control 060 { 061 /** 062 * The tracer object for the debug logger. 063 */ 064 private static final DebugTracer TRACER = getTracer(); 065 066 067 068 069 /** 070 * The BER type value for the warning element of the control value. 071 */ 072 public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0; 073 074 075 076 /** 077 * The BER type value for the error element of the control value. 078 */ 079 public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81; 080 081 082 083 // The warning value for this password policy response control. 084 private int warningValue; 085 086 // The error type for this password policy response control. 087 private PasswordPolicyErrorType errorType; 088 089 // The warning type for the password policy response control. 090 private PasswordPolicyWarningType warningType; 091 092 093 094 /** 095 * Creates a new instance of the password policy response control with the 096 * default OID and criticality, and without either a warning or an error flag. 097 */ 098 public PasswordPolicyResponseControl() 099 { 100 super(OID_PASSWORD_POLICY_CONTROL, false, encodeValue(null, -1, null)); 101 102 103 warningType = null; 104 errorType = null; 105 warningValue = -1; 106 } 107 108 109 110 /** 111 * Creates a new instance of this password policy response control with the 112 * default OID and criticality, and with the provided warning and/or error 113 * flag information. 114 * 115 * @param warningType The warning type to use for this password policy 116 * response control, or <CODE>null</CODE> if there 117 * should not be a warning flag. 118 * @param warningValue The warning value to use for this password policy 119 * response control, if applicable. 120 * @param errorType The error type to use for this password policy 121 * response control, or <CODE>null</CODE> if there 122 * should not be an error flag. 123 */ 124 public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType, 125 int warningValue, 126 PasswordPolicyErrorType errorType) 127 { 128 super(OID_PASSWORD_POLICY_CONTROL, false, 129 encodeValue(warningType, warningValue, errorType)); 130 131 132 this.warningType = warningType; 133 this.warningValue = warningValue; 134 this.errorType = errorType; 135 } 136 137 138 139 /** 140 * Creates a new instance of the password policy request control with the 141 * provided information. 142 * 143 * @param oid The OID to use for this control. 144 * @param isCritical Indicates whether support for this control should be 145 * considered a critical part of the client processing. 146 * @param warningType The warning type to use for this password policy 147 * response control, or <CODE>null</CODE> if there 148 * should not be a warning flag. 149 * @param warningValue The warning value to use for this password policy 150 * response control, if applicable. 151 * @param errorType The error type to use for this password policy 152 * response control, or <CODE>null</CODE> if there 153 * should not be an error flag. 154 */ 155 public PasswordPolicyResponseControl(String oid, boolean isCritical, 156 PasswordPolicyWarningType warningType, 157 int warningValue, 158 PasswordPolicyErrorType errorType) 159 { 160 super(oid, isCritical, encodeValue(warningType, warningValue, errorType)); 161 162 163 this.warningType = warningType; 164 this.warningValue = warningValue; 165 this.errorType = errorType; 166 } 167 168 169 170 /** 171 * Creates a new instance of the password policy request control with the 172 * provided information. 173 * 174 * @param oid The OID to use for this control. 175 * @param isCritical Indicates whether support for this control should be 176 * considered a critical part of the client processing. 177 * @param warningType The warning type to use for this password policy 178 * response control, or <CODE>null</CODE> if there 179 * should not be a warning flag. 180 * @param warningValue The warning value to use for this password policy 181 * response control, if applicable. 182 * @param errorType The error type to use for this password policy 183 * response control, or <CODE>null</CODE> if there 184 * should not be an error flag. 185 * @param encodedValue The pre-encoded value to use for this control. 186 */ 187 private PasswordPolicyResponseControl(String oid, boolean isCritical, 188 PasswordPolicyWarningType warningType, 189 int warningValue, 190 PasswordPolicyErrorType errorType, 191 ASN1OctetString encodedValue) 192 { 193 super(oid, isCritical, encodedValue); 194 195 196 this.warningType = warningType; 197 this.warningValue = warningValue; 198 this.errorType = errorType; 199 } 200 201 202 203 /** 204 * Encodes the provided information into an ASN.1 octet string suitable for 205 * use as the value for this control. 206 * 207 * @param warningType The warning type to use for this password policy 208 * response control, or <CODE>null</CODE> if there 209 * should not be a warning flag. 210 * @param warningValue The warning value to use for this password policy 211 * response control, if applicable. 212 * @param errorType The error type to use for this password policy 213 * response control, or <CODE>null</CODE> if there 214 * should not be an error flag. 215 * 216 * @return An ASN.1 octet string containing the encoded control value. 217 */ 218 private static ASN1OctetString encodeValue( 219 PasswordPolicyWarningType warningType, 220 int warningValue, 221 PasswordPolicyErrorType errorType) 222 { 223 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); 224 225 if (warningType != null) 226 { 227 ASN1Integer warningInteger = new ASN1Integer(warningType.getType(), 228 warningValue); 229 elements.add(new ASN1Element(TYPE_WARNING_ELEMENT, 230 warningInteger.encode())); 231 } 232 233 if (errorType != null) 234 { 235 elements.add(new ASN1Enumerated(TYPE_ERROR_ELEMENT, 236 errorType.intValue())); 237 } 238 239 ASN1Sequence valueSequence = new ASN1Sequence(elements); 240 return new ASN1OctetString(valueSequence.encode()); 241 } 242 243 244 245 /** 246 * Creates a new password policy response control from the contents of the 247 * provided control. 248 * 249 * @param control The generic control containing the information to use to 250 * create this password policy response control. 251 * 252 * @return The password policy response control decoded from the provided 253 * control. 254 * 255 * @throws LDAPException If this control cannot be decoded as a valid 256 * password policy response control. 257 */ 258 public static PasswordPolicyResponseControl decodeControl(Control control) 259 throws LDAPException 260 { 261 ASN1OctetString controlValue = control.getValue(); 262 if (controlValue == null) 263 { 264 // The response control must always have a value. 265 Message message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get(); 266 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 267 } 268 269 270 try 271 { 272 PasswordPolicyWarningType warningType = null; 273 PasswordPolicyErrorType errorType = null; 274 int warningValue = -1; 275 276 ASN1Sequence valueSequence = 277 ASN1Sequence.decodeAsSequence(controlValue.value()); 278 for (ASN1Element e : valueSequence.elements()) 279 { 280 switch (e.getType()) 281 { 282 case TYPE_WARNING_ELEMENT: 283 ASN1Integer integerElement = ASN1Integer.decodeAsInteger(e.value()); 284 warningValue = integerElement.intValue(); 285 warningType = 286 PasswordPolicyWarningType.valueOf(integerElement.getType()); 287 if (warningType == null) 288 { 289 Message message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get( 290 byteToHex(integerElement.getType())); 291 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 292 } 293 break; 294 295 case TYPE_ERROR_ELEMENT: 296 int errorValue = e.decodeAsEnumerated().intValue(); 297 errorType = PasswordPolicyErrorType.valueOf(errorValue); 298 if (errorType == null) 299 { 300 Message message = 301 ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue); 302 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 303 } 304 break; 305 306 default: 307 Message message = ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE.get( 308 byteToHex(e.getType())); 309 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 310 } 311 } 312 313 return new PasswordPolicyResponseControl(control.getOID(), 314 control.isCritical(), 315 warningType, warningValue, 316 errorType, controlValue); 317 } 318 catch (LDAPException le) 319 { 320 throw le; 321 } 322 catch (ASN1Exception ae) 323 { 324 if (debugEnabled()) 325 { 326 TRACER.debugCaught(DebugLogLevel.ERROR, ae); 327 } 328 329 Message message = ERR_PWPOLICYRES_DECODE_ERROR.get(ae.getMessage()); 330 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 331 } 332 catch (Exception e) 333 { 334 if (debugEnabled()) 335 { 336 TRACER.debugCaught(DebugLogLevel.ERROR, e); 337 } 338 339 Message message = 340 ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e)); 341 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 342 } 343 } 344 345 346 347 /** 348 * Retrieves the password policy warning type contained in this control. 349 * 350 * @return The password policy warning type contained in this control, or 351 * <CODE>null</CODE> if there is no warning type. 352 */ 353 public PasswordPolicyWarningType getWarningType() 354 { 355 return warningType; 356 } 357 358 359 360 /** 361 * Retrieves the password policy warning value for this control. The value is 362 * undefined if there is no warning type. 363 * 364 * @return The password policy warning value for this control. 365 */ 366 public int getWarningValue() 367 { 368 return warningValue; 369 } 370 371 372 373 /** 374 * Retrieves the password policy error type contained in this control. 375 * 376 * @return The password policy error type contained in this control, or 377 * <CODE>null</CODE> if there is no error type. 378 */ 379 public PasswordPolicyErrorType getErrorType() 380 { 381 return errorType; 382 } 383 384 385 386 /** 387 * Retrieves a string representation of this password policy response control. 388 * 389 * @return A string representation of this password policy response control. 390 */ 391 public String toString() 392 { 393 StringBuilder buffer = new StringBuilder(); 394 toString(buffer); 395 return buffer.toString(); 396 } 397 398 399 400 /** 401 * Appends a string representation of this password policy response control to 402 * the provided buffer. 403 * 404 * @param buffer The buffer to which the information should be appended. 405 */ 406 public void toString(StringBuilder buffer) 407 { 408 buffer.append("PasswordPolicyResponseControl("); 409 410 if (warningType != null) 411 { 412 buffer.append(warningType.toString()); 413 buffer.append("="); 414 buffer.append(warningValue); 415 416 if (errorType != null) 417 { 418 buffer.append(", "); 419 } 420 } 421 422 if (errorType != null) 423 { 424 buffer.append(errorType.toString()); 425 } 426 427 buffer.append(")"); 428 } 429 } 430