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 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.controls; 018 019import static org.opends.messages.ProtocolMessages.*; 020import static org.opends.server.util.ServerConstants.*; 021import static org.opends.server.util.StaticUtils.*; 022 023import java.io.IOException; 024 025import org.forgerock.i18n.LocalizableMessage; 026import org.forgerock.i18n.slf4j.LocalizedLogger; 027import org.forgerock.opendj.io.ASN1; 028import org.forgerock.opendj.io.ASN1Reader; 029import org.forgerock.opendj.io.ASN1Writer; 030import org.forgerock.opendj.ldap.ByteString; 031import org.forgerock.opendj.ldap.ResultCode; 032import org.opends.server.types.Control; 033import org.opends.server.types.DirectoryException; 034 035/** 036 * This class implements the account usable response control. This is a 037 * Sun-defined control with OID 1.3.6.1.4.1.42.2.27.9.5.8. The value of this 038 * control is composed according to the following BNF: 039 * <BR> 040 * <PRE> 041 * ACCOUNT_USABLE_RESPONSE ::= CHOICE { 042 * is_available [0] INTEGER, -- Seconds before expiration -- 043 * is_not_available [1] MORE_INFO } 044 * 045 * MORE_INFO ::= SEQUENCE { 046 * inactive [0] BOOLEAN DEFAULT FALSE, 047 * reset [1] BOOLEAN DEFAULT FALSE, 048 * expired [2] BOOLEAN DEFAULT_FALSE, 049 * remaining_grace [3] INTEGER OPTIONAL, 050 * seconds_before_unlock [4] INTEGER OPTIONAL } 051 * </PRE> 052 */ 053public class AccountUsableResponseControl 054 extends Control 055{ 056 /** ControlDecoder implementation to decode this control from a ByteString. */ 057 private static final class Decoder 058 implements ControlDecoder<AccountUsableResponseControl> 059 { 060 @Override 061 public AccountUsableResponseControl decode(boolean isCritical, 062 ByteString value) 063 throws DirectoryException 064 { 065 if (value == null) 066 { 067 // The response control must always have a value. 068 LocalizableMessage message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE.get(); 069 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 070 } 071 072 073 try 074 { 075 ASN1Reader reader = ASN1.getReader(value); 076 switch (reader.peekType()) 077 { 078 case TYPE_SECONDS_BEFORE_EXPIRATION: 079 int secondsBeforeExpiration = (int)reader.readInteger(); 080 return new AccountUsableResponseControl(isCritical, 081 secondsBeforeExpiration); 082 case TYPE_MORE_INFO: 083 boolean isInactive = false; 084 boolean isReset = false; 085 boolean isExpired = false; 086 boolean isLocked = false; 087 int remainingGraceLogins = -1; 088 int secondsBeforeUnlock = 0; 089 090 reader.readStartSequence(); 091 if(reader.hasNextElement() && 092 reader.peekType() == TYPE_INACTIVE) 093 { 094 isInactive = reader.readBoolean(); 095 } 096 if(reader.hasNextElement() && 097 reader.peekType() == TYPE_RESET) 098 { 099 isReset = reader.readBoolean(); 100 } 101 if(reader.hasNextElement() && 102 reader.peekType() == TYPE_EXPIRED) 103 { 104 isExpired = reader.readBoolean(); 105 } 106 if(reader.hasNextElement() && 107 reader.peekType() == TYPE_REMAINING_GRACE_LOGINS) 108 { 109 remainingGraceLogins = (int)reader.readInteger(); 110 } 111 if(reader.hasNextElement() && 112 reader.peekType() == TYPE_SECONDS_BEFORE_UNLOCK) 113 { 114 isLocked = true; 115 secondsBeforeUnlock = (int)reader.readInteger(); 116 } 117 reader.readEndSequence(); 118 119 return new AccountUsableResponseControl(isCritical, 120 isInactive, isReset, 121 isExpired, 122 remainingGraceLogins, 123 isLocked, 124 secondsBeforeUnlock); 125 126 default: 127 LocalizableMessage message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE.get( 128 byteToHex(reader.peekType())); 129 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 130 } 131 } 132 catch (DirectoryException de) 133 { 134 throw de; 135 } 136 catch (Exception e) 137 { 138 logger.traceException(e); 139 140 LocalizableMessage message = 141 ERR_ACCTUSABLERES_DECODE_ERROR.get(getExceptionMessage(e)); 142 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 143 } 144 } 145 146 @Override 147 public String getOID() 148 { 149 return OID_ACCOUNT_USABLE_CONTROL; 150 } 151 } 152 153 /** The Control Decoder that can be used to decode this control. */ 154 public static final ControlDecoder<AccountUsableResponseControl> DECODER = new Decoder(); 155 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 156 157 /** The BER type to use for the seconds before expiration when the account is available. */ 158 public static final byte TYPE_SECONDS_BEFORE_EXPIRATION = (byte) 0x80; 159 /** The BER type to use for the MORE_INFO sequence when the account is not available. */ 160 public static final byte TYPE_MORE_INFO = (byte) 0xA1; 161 /** 162 * The BER type to use for the MORE_INFO element that indicates that the 163 * account has been inactivated. 164 */ 165 public static final byte TYPE_INACTIVE = (byte) 0x80; 166 /** 167 * The BER type to use for the MORE_INFO element that indicates that the 168 * password has been administratively reset. 169 */ 170 public static final byte TYPE_RESET = (byte) 0x81; 171 /** 172 * The BER type to use for the MORE_INFO element that indicates that the 173 * user's password is expired. 174 */ 175 public static final byte TYPE_EXPIRED = (byte) 0x82; 176 /** 177 * The BER type to use for the MORE_INFO element that provides the number of 178 * remaining grace logins. 179 */ 180 public static final byte TYPE_REMAINING_GRACE_LOGINS = (byte) 0x83; 181 /** 182 * The BER type to use for the MORE_INFO element that indicates that the 183 * password has been administratively reset. 184 */ 185 public static final byte TYPE_SECONDS_BEFORE_UNLOCK = (byte) 0x84; 186 187 188 /** Indicates whether the user's account is usable. */ 189 private boolean isUsable; 190 /** Indicates whether the user's password is expired. */ 191 private boolean isExpired; 192 /** Indicates whether the user's account is inactive. */ 193 private boolean isInactive; 194 /** Indicates whether the user's account is currently locked. */ 195 private boolean isLocked; 196 /** 197 * Indicates whether the user's password has been reset and must be changed 198 * before anything else can be done. 199 */ 200 private boolean isReset; 201 202 /** The number of remaining grace logins, if available. */ 203 private int remainingGraceLogins; 204 /** The length of time in seconds before the user's password expires, if available. */ 205 private int secondsBeforeExpiration; 206 /** The length of time before the user's account is unlocked, if available. */ 207 private int secondsBeforeUnlock; 208 209 210 211 /** 212 * Creates a new account usability response control that may be used to 213 * indicate that the account is available and provide the number of seconds 214 * until expiration. It will use the default OID and criticality. 215 * 216 * @param secondsBeforeExpiration The length of time in seconds until the 217 * user's password expires, or -1 if the 218 * user's password will not expire or the 219 * expiration time is unknown. 220 */ 221 public AccountUsableResponseControl(int secondsBeforeExpiration) 222 { 223 this(false, secondsBeforeExpiration); 224 } 225 226 /** 227 * Creates a new account usability response control that may be used to 228 * indicate that the account is available and provide the number of seconds 229 * until expiration. It will use the default OID and criticality. 230 * 231 * @param isCritical Indicates whether this control should be 232 * considered critical in processing the 233 * request. 234 * @param secondsBeforeExpiration The length of time in seconds until the 235 * user's password expires, or -1 if the 236 * user's password will not expire or the 237 * expiration time is unknown. 238 */ 239 public AccountUsableResponseControl(boolean isCritical, 240 int secondsBeforeExpiration) 241 { 242 super(OID_ACCOUNT_USABLE_CONTROL, isCritical); 243 244 245 this.secondsBeforeExpiration = secondsBeforeExpiration; 246 247 isUsable = true; 248 isInactive = false; 249 isReset = false; 250 isExpired = false; 251 remainingGraceLogins = -1; 252 isLocked = false; 253 secondsBeforeUnlock = 0; 254 } 255 256 257 258 /** 259 * Creates a new account usability response control that may be used to 260 * indicate that the account is not available and provide information about 261 * the underlying reason. It will use the default OID and criticality. 262 * 263 * @param isCritical Indicates whether this control should be 264 * considered critical in processing the 265 * request. 266 * @param isInactive Indicates whether the user's account has been 267 * inactivated by an administrator. 268 * @param isReset Indicates whether the user's password has 269 * been reset by an administrator. 270 * @param isExpired Indicates whether the user's password is 271 * expired. 272 * @param remainingGraceLogins The number of grace logins remaining. A 273 * value of zero indicates that there are none 274 * remaining. A value of -1 indicates that 275 * grace login functionality is not enabled. 276 * @param isLocked Indicates whether the user's account is 277 * currently locked out. 278 * @param secondsBeforeUnlock The length of time in seconds until the 279 * account is unlocked. A value of -1 indicates 280 * that the account will not be automatically 281 * unlocked and must be reset by an 282 * administrator. 283 */ 284 public AccountUsableResponseControl(boolean isCritical, boolean isInactive, 285 boolean isReset, 286 boolean isExpired, 287 int remainingGraceLogins, 288 boolean isLocked, int secondsBeforeUnlock) 289 { 290 super(OID_ACCOUNT_USABLE_CONTROL, isCritical); 291 292 293 this.isInactive = isInactive; 294 this.isReset = isReset; 295 this.isExpired = isExpired; 296 this.remainingGraceLogins = remainingGraceLogins; 297 this.isLocked = isLocked; 298 this.secondsBeforeUnlock = secondsBeforeUnlock; 299 300 isUsable = false; 301 secondsBeforeExpiration = -1; 302 } 303 304 /** 305 * Creates a new account usability response control that may be used to 306 * indicate that the account is not available and provide information about 307 * the underlying reason. It will use the default OID and criticality. 308 * 309 * @param isInactive Indicates whether the user's account has been 310 * inactivated by an administrator. 311 * @param isReset Indicates whether the user's password has 312 * been reset by an administrator. 313 * @param isExpired Indicates whether the user's password is 314 * expired. 315 * @param remainingGraceLogins The number of grace logins remaining. A 316 * value of zero indicates that there are none 317 * remaining. A value of -1 indicates that 318 * grace login functionality is not enabled. 319 * @param isLocked Indicates whether the user's account is 320 * currently locked out. 321 * @param secondsBeforeUnlock The length of time in seconds until the 322 * account is unlocked. A value of -1 indicates 323 * that the account will not be automatically 324 * unlocked and must be reset by an 325 * administrator. 326 */ 327 public AccountUsableResponseControl(boolean isInactive, boolean isReset, 328 boolean isExpired, 329 int remainingGraceLogins, 330 boolean isLocked, int secondsBeforeUnlock) 331 { 332 this(false, isInactive, isReset, isExpired, remainingGraceLogins, 333 isLocked, secondsBeforeUnlock); 334 } 335 336 @Override 337 public void writeValue(ASN1Writer writer) throws IOException { 338 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 339 340 if(isUsable) 341 { 342 writer.writeInteger(TYPE_SECONDS_BEFORE_EXPIRATION, 343 secondsBeforeExpiration); 344 } 345 else 346 { 347 writer.writeStartSequence(TYPE_MORE_INFO); 348 if (isInactive) 349 { 350 writer.writeBoolean(TYPE_INACTIVE, true); 351 } 352 353 if (isReset) 354 { 355 writer.writeBoolean(TYPE_RESET, true); 356 } 357 358 if (isExpired) 359 { 360 writer.writeBoolean(TYPE_EXPIRED, true); 361 362 if (remainingGraceLogins >= 0) 363 { 364 writer.writeInteger(TYPE_REMAINING_GRACE_LOGINS, 365 remainingGraceLogins); 366 } 367 } 368 369 if (isLocked) 370 { 371 writer.writeInteger(TYPE_SECONDS_BEFORE_UNLOCK, 372 secondsBeforeUnlock); 373 } 374 writer.writeEndSequence(); 375 } 376 377 writer.writeEndSequence(); 378 } 379 380 381 382 383 /** 384 * Indicates whether the associated user account is available for use. 385 * 386 * @return <CODE>true</CODE> if the associated user account is available, or 387 * <CODE>false</CODE> if not. 388 */ 389 public boolean isUsable() 390 { 391 return isUsable; 392 } 393 394 395 396 /** 397 * Retrieves the length of time in seconds before the user's password expires. 398 * This value is unreliable if the account is not available. 399 * 400 * @return The length of time in seconds before the user's password expires, 401 * or -1 if it is unknown or password expiration is not enabled for 402 * the user. 403 */ 404 public int getSecondsBeforeExpiration() 405 { 406 return secondsBeforeExpiration; 407 } 408 409 410 411 /** 412 * Indicates whether the user's account has been inactivated by an 413 * administrator. 414 * 415 * @return <CODE>true</CODE> if the user's account has been inactivated by 416 * an administrator, or <CODE>false</CODE> if not. 417 */ 418 public boolean isInactive() 419 { 420 return isInactive; 421 } 422 423 424 425 /** 426 * Indicates whether the user's password has been administratively reset and 427 * the user must change that password before any other operations will be 428 * allowed. 429 * 430 * @return <CODE>true</CODE> if the user's password has been administratively 431 * reset, or <CODE>false</CODE> if not. 432 */ 433 public boolean isReset() 434 { 435 return isReset; 436 } 437 438 439 440 /** 441 * Indicates whether the user's password is expired. 442 * 443 * @return <CODE>true</CODE> if the user's password is expired, or 444 * <CODE>false</CODE> if not. 445 */ 446 public boolean isExpired() 447 { 448 return isExpired; 449 } 450 451 452 453 /** 454 * Retrieves the number of remaining grace logins for the user. This value is 455 * unreliable if the user's password is not expired. 456 * 457 * @return The number of remaining grace logins for the user, or -1 if the 458 * grace logins feature is not enabled for the user. 459 */ 460 public int getRemainingGraceLogins() 461 { 462 return remainingGraceLogins; 463 } 464 465 466 467 /** 468 * Indicates whether the user's account is locked for some reason. 469 * 470 * @return <CODE>true</CODE> if the user's account is locked, or 471 * <CODE>false</CODE> if it is not. 472 */ 473 public boolean isLocked() 474 { 475 return isLocked; 476 } 477 478 479 480 /** 481 * Retrieves the length of time in seconds before the user's account is 482 * automatically unlocked. This value is unreliable is the user's account is 483 * not locked. 484 * 485 * @return The length of time in seconds before the user's account is 486 * automatically unlocked, or -1 if it requires administrative action 487 * to unlock the account. 488 */ 489 public int getSecondsBeforeUnlock() 490 { 491 return secondsBeforeUnlock; 492 } 493 494 @Override 495 public void toString(StringBuilder buffer) 496 { 497 buffer.append("AccountUsableResponseControl(isUsable="); 498 buffer.append(isUsable); 499 500 if (isUsable) 501 { 502 buffer.append(",secondsBeforeExpiration="); 503 buffer.append(secondsBeforeExpiration); 504 } 505 else 506 { 507 buffer.append(",isInactive="); 508 buffer.append(isInactive); 509 buffer.append(",isReset="); 510 buffer.append(isReset); 511 buffer.append(",isExpired="); 512 buffer.append(isExpired); 513 buffer.append(",remainingGraceLogins="); 514 buffer.append(remainingGraceLogins); 515 buffer.append(",isLocked="); 516 buffer.append(isLocked); 517 buffer.append(",secondsBeforeUnlock="); 518 buffer.append(secondsBeforeUnlock); 519 } 520 521 buffer.append(")"); 522 } 523} 524