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.ASN1Boolean; 035 import org.opends.server.protocols.asn1.ASN1Element; 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.DebugLogLevel; 043 import org.opends.server.types.LDAPException; 044 045 import static org.opends.server.loggers.debug.DebugLogger.*; 046 import org.opends.server.loggers.debug.DebugTracer; 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 account usable response control. This is a 055 * Sun-defined control with OID 1.3.6.1.4.1.42.2.27.9.5.8. The value of this 056 * control is composed according to the following BNF: 057 * <BR> 058 * <PRE> 059 * ACCOUNT_USABLE_RESPONSE ::= CHOICE { 060 * is_available [0] INTEGER, -- Seconds before expiration -- 061 * is_not_available [1] MORE_INFO } 062 * 063 * MORE_INFO ::= SEQUENCE { 064 * inactive [0] BOOLEAN DEFAULT FALSE, 065 * reset [1] BOOLEAN DEFAULT FALSE, 066 * expired [2] BOOLEAN DEFAULT_FALSE, 067 * remaining_grace [3] INTEGER OPTIONAL, 068 * seconds_before_unlock [4] INTEGER OPTIONAL } 069 * </PRE> 070 */ 071 public class AccountUsableResponseControl 072 extends Control 073 { 074 /** 075 * The tracer object for the debug logger. 076 */ 077 private static final DebugTracer TRACER = getTracer(); 078 079 080 081 082 /** 083 * The BER type to use for the seconds before expiration when the account is 084 * available. 085 */ 086 public static final byte TYPE_SECONDS_BEFORE_EXPIRATION = (byte) 0x80; 087 088 089 090 /** 091 * The BER type to use for the MORE_INFO sequence when the account is not 092 * available. 093 */ 094 public static final byte TYPE_MORE_INFO = (byte) 0xA1; 095 096 097 098 /** 099 * The BER type to use for the MORE_INFO element that indicates that the 100 * account has been inactivated. 101 */ 102 public static final byte TYPE_INACTIVE = (byte) 0x80; 103 104 105 106 /** 107 * The BER type to use for the MORE_INFO element that indicates that the 108 * password has been administratively reset. 109 */ 110 public static final byte TYPE_RESET = (byte) 0x81; 111 112 113 114 /** 115 * The BER type to use for the MORE_INFO element that indicates that the 116 * user's password is expired. 117 */ 118 public static final byte TYPE_EXPIRED = (byte) 0x82; 119 120 121 122 /** 123 * The BER type to use for the MORE_INFO element that provides the number of 124 * remaining grace logins. 125 */ 126 public static final byte TYPE_REMAINING_GRACE_LOGINS = (byte) 0x83; 127 128 129 130 /** 131 * The BER type to use for the MORE_INFO element that indicates that the 132 * password has been administratively reset. 133 */ 134 public static final byte TYPE_SECONDS_BEFORE_UNLOCK = (byte) 0x84; 135 136 137 138 // Indicates whether the user's account is usable. 139 private boolean isUsable; 140 141 // Indicates whether the user's password is expired. 142 private boolean isExpired; 143 144 // Indicates whether the user's account is inactive. 145 private boolean isInactive; 146 147 // Indicates whether the user's account is currently locked. 148 private boolean isLocked; 149 150 // Indicates whether the user's password has been reset and must be changed 151 // before anything else can be done. 152 private boolean isReset; 153 154 // The number of remaining grace logins, if available. 155 private int remainingGraceLogins; 156 157 // The length of time in seconds before the user's password expires, if 158 // available. 159 private int secondsBeforeExpiration; 160 161 // The length of time before the user's account is unlocked, if available. 162 private int secondsBeforeUnlock; 163 164 165 166 /** 167 * Creates a new account usability response control that may be used to 168 * indicate that the account is available and provide the number of seconds 169 * until expiration. It will use the default OID and criticality. 170 * 171 * @param secondsBeforeExpiration The length of time in seconds until the 172 * user's password expires, or -1 if the 173 * user's password will not expire or the 174 * expiration time is unknown. 175 */ 176 public AccountUsableResponseControl(int secondsBeforeExpiration) 177 { 178 super(OID_ACCOUNT_USABLE_CONTROL, false, 179 encodeValue(secondsBeforeExpiration)); 180 181 182 this.secondsBeforeExpiration = secondsBeforeExpiration; 183 184 isUsable = true; 185 isInactive = false; 186 isReset = false; 187 isExpired = false; 188 remainingGraceLogins = -1; 189 isLocked = false; 190 secondsBeforeUnlock = 0; 191 } 192 193 194 195 /** 196 * Creates a new account usability response control that may be used to 197 * indicate that the account is available and provide the number of seconds 198 * until expiration. 199 * 200 * @param oid The OID for this account usability 201 * response control. 202 * @param isCritical Indicates whether this control should be 203 * marked critical. 204 * @param secondsBeforeExpiration The length of time in seconds until the 205 * user's password expires, or -1 if the 206 * user's password will not expire or the 207 * expiration time is unknown. 208 */ 209 public AccountUsableResponseControl(String oid, boolean isCritical, 210 int secondsBeforeExpiration) 211 { 212 super(oid, isCritical, encodeValue(secondsBeforeExpiration)); 213 214 215 this.secondsBeforeExpiration = secondsBeforeExpiration; 216 217 isUsable = true; 218 isInactive = false; 219 isReset = false; 220 isExpired = false; 221 remainingGraceLogins = -1; 222 isLocked = false; 223 secondsBeforeUnlock = 0; 224 } 225 226 227 228 /** 229 * Creates a new account usability response control that may be used to 230 * indicate that the account is not available and provide information about 231 * the underlying reason. It will use the default OID and criticality. 232 * 233 * @param isInactive Indicates whether the user's account has been 234 * inactivated by an administrator. 235 * @param isReset Indicates whether the user's password has 236 * been reset by an administrator. 237 * @param isExpired Indicates whether the user's password is 238 * expired. 239 * @param remainingGraceLogins The number of grace logins remaining. A 240 * value of zero indicates that there are none 241 * remaining. A value of -1 indicates that 242 * grace login functionality is not enabled. 243 * @param isLocked Indicates whether the user's account is 244 * currently locked out. 245 * @param secondsBeforeUnlock The length of time in seconds until the 246 * account is unlocked. A value of -1 indicates 247 * that the account will not be automatically 248 * unlocked and must be reset by an 249 * administrator. 250 */ 251 public AccountUsableResponseControl(boolean isInactive, boolean isReset, 252 boolean isExpired, 253 int remainingGraceLogins, 254 boolean isLocked, int secondsBeforeUnlock) 255 { 256 super(OID_ACCOUNT_USABLE_CONTROL, false, 257 encodeValue(isInactive, isReset, isExpired, remainingGraceLogins, 258 isLocked, secondsBeforeUnlock)); 259 260 261 this.isInactive = isInactive; 262 this.isReset = isReset; 263 this.isExpired = isExpired; 264 this.remainingGraceLogins = remainingGraceLogins; 265 this.isLocked = isLocked; 266 this.secondsBeforeUnlock = secondsBeforeUnlock; 267 268 isUsable = false; 269 secondsBeforeExpiration = -1; 270 } 271 272 273 274 /** 275 * Creates a new account usability response control that may be used to 276 * indicate that the account is not available and provide information about 277 * the underlying reason. 278 * 279 * @param oid The OID for this account usability response 280 * control. 281 * @param isCritical Indicates whether this control should be 282 * marked critical. 283 * @param isInactive Indicates whether the user's account has been 284 * inactivated by an administrator. 285 * @param isReset Indicates whether the user's password has 286 * been reset by an administrator. 287 * @param isExpired Indicates whether the user's password is 288 * expired. 289 * @param remainingGraceLogins The number of grace logins remaining. A 290 * value of zero indicates that there are none 291 * remaining. A value of -1 indicates that 292 * grace login functionality is not enabled. 293 * @param isLocked Indicates whether the user's account is 294 * currently locked out. 295 * @param secondsBeforeUnlock The length of time in seconds until the 296 * account is unlocked. A value of -1 indicates 297 * that the account will not be automatically 298 * unlocked and must be reset by an 299 * administrator. 300 */ 301 public AccountUsableResponseControl(String oid, boolean isCritical, 302 boolean isInactive, boolean isReset, 303 boolean isExpired, 304 int remainingGraceLogins, 305 boolean isLocked, int secondsBeforeUnlock) 306 { 307 super(oid, isCritical, 308 encodeValue(isInactive, isReset, isExpired, remainingGraceLogins, 309 isLocked, secondsBeforeUnlock)); 310 311 312 this.isInactive = isInactive; 313 this.isReset = isReset; 314 this.isExpired = isExpired; 315 this.remainingGraceLogins = remainingGraceLogins; 316 this.isLocked = isLocked; 317 this.secondsBeforeUnlock = secondsBeforeUnlock; 318 319 isUsable = false; 320 secondsBeforeExpiration = -1; 321 } 322 323 324 325 /** 326 * Creates a new account usability response control using the provided 327 * information. This version of the constructor is only intended for internal 328 * use. 329 * 330 * @param oid The OID for this account usability 331 * response control. 332 * @param isCritical Indicates whether this control should be 333 * marked critical. 334 * @param isAvailable Indicates whether the user's account is 335 * available for use. 336 * @param secondsBeforeExpiration The length of time in seconds until the 337 * user's password expires, or -1 if the 338 * user's password will not expire or the 339 * expiration time is unknown. 340 * @param isInactive Indicates whether the user's account has 341 * been inactivated by an administrator. 342 * @param isReset Indicates whether the user's password has 343 * been reset by an administrator. 344 * @param isExpired Indicates whether the user's password is 345 * expired. 346 * @param remainingGraceLogins The number of grace logins remaining. A 347 * value of zero indicates that there are 348 * none remaining. A value of -1 indicates 349 * that grace login functionality is not 350 * enabled. 351 * @param isLocked Indicates whether the user's account is 352 * currently locked out. 353 * @param secondsBeforeUnlock The length of time in seconds until the 354 * account is unlocked. A value of -1 355 * indicates that the account will not be 356 * automatically unlocked and must be reset 357 * by an administrator. 358 * @param encodedValue The pre-encoded value for this account 359 * usable response control. 360 */ 361 private AccountUsableResponseControl(String oid, boolean isCritical, 362 boolean isAvailable, 363 int secondsBeforeExpiration, 364 boolean isInactive, 365 boolean isReset, boolean isExpired, 366 int remainingGraceLogins, 367 boolean isLocked, 368 int secondsBeforeUnlock, 369 ASN1OctetString encodedValue) 370 { 371 super(oid, isCritical, encodedValue); 372 373 374 this.isUsable = isAvailable; 375 this.secondsBeforeExpiration = secondsBeforeExpiration; 376 this.isInactive = isInactive; 377 this.isReset = isReset; 378 this.isExpired = isExpired; 379 this.remainingGraceLogins = remainingGraceLogins; 380 this.isLocked = isLocked; 381 this.secondsBeforeUnlock = secondsBeforeUnlock; 382 } 383 384 385 386 /** 387 * Encodes the provided information into an ASN.1 octet string suitable for 388 * use as the value for an account usable response control in which the use's 389 * account is available. 390 * 391 * @param secondsBeforeExpiration The length of time in seconds until the 392 * user's password expires, or -1 if the 393 * user's password will not expire or the 394 * expiration time is unknown. 395 * 396 * @return An ASN.1 octet string containing the encoded control value. 397 */ 398 private static ASN1OctetString encodeValue(int secondsBeforeExpiration) 399 { 400 ASN1Integer sbeInteger = new ASN1Integer(TYPE_SECONDS_BEFORE_EXPIRATION, 401 secondsBeforeExpiration); 402 403 return new ASN1OctetString(sbeInteger.encode()); 404 } 405 406 407 408 /** 409 * Encodes the provided information into an ASN.1 octet string suitable for 410 * use as the value for an account usable response control in which the user's 411 * account is not available. 412 * 413 * 414 * @param isInactive Indicates whether the user's account has been 415 * inactivated by an administrator. 416 * @param isReset Indicates whether the user's password has 417 * been reset by an administrator. 418 * @param isExpired Indicates whether the user's password is 419 * expired. 420 * @param remainingGraceLogins The number of grace logins remaining. A 421 * value of zero indicates that there are none 422 * remaining. A value of -1 indicates that 423 * grace login functionality is not enabled. 424 * @param isLocked Indicates whether the user's account is 425 * currently locked out. 426 * @param secondsBeforeUnlock The length of time in seconds until the 427 * account is unlocked. A value of -1 indicates 428 * that the account will not be automatically 429 * unlocked and must be reset by an 430 * administrator. 431 * 432 * @return An ASN.1 octet string containing the encoded control value. 433 */ 434 private static ASN1OctetString encodeValue(boolean isInactive, 435 boolean isReset, boolean isExpired, 436 int remainingGraceLogins, 437 boolean isLocked, 438 int secondsBeforeUnlock) 439 { 440 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(5); 441 442 if (isInactive) 443 { 444 elements.add(new ASN1Boolean(TYPE_INACTIVE, true)); 445 } 446 447 if (isReset) 448 { 449 elements.add(new ASN1Boolean(TYPE_RESET, true)); 450 } 451 452 if (isExpired) 453 { 454 elements.add(new ASN1Boolean(TYPE_EXPIRED, true)); 455 456 if (remainingGraceLogins >= 0) 457 { 458 elements.add(new ASN1Integer(TYPE_REMAINING_GRACE_LOGINS, 459 remainingGraceLogins)); 460 } 461 } 462 463 if (isLocked) 464 { 465 elements.add(new ASN1Integer(TYPE_SECONDS_BEFORE_UNLOCK, 466 secondsBeforeUnlock)); 467 } 468 469 ASN1Sequence moreInfoSequence = new ASN1Sequence(TYPE_MORE_INFO, 470 elements); 471 return new ASN1OctetString(moreInfoSequence.encode()); 472 } 473 474 475 476 /** 477 * Creates a new account usable response control from the contents of the 478 * provided control. 479 * 480 * @param control The generic control containing the information to use to 481 * create this account usable response control. 482 * 483 * @return The account usable response control decoded from the provided 484 * control. 485 * 486 * @throws LDAPException If this control cannot be decoded as a valid 487 * account usable response control. 488 */ 489 public static AccountUsableResponseControl decodeControl(Control control) 490 throws LDAPException 491 { 492 ASN1OctetString controlValue = control.getValue(); 493 if (controlValue == null) 494 { 495 // The response control must always have a value. 496 Message message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE.get(); 497 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 498 } 499 500 501 try 502 { 503 ASN1Element valueElement = ASN1Element.decode(controlValue.value()); 504 switch (valueElement.getType()) 505 { 506 case TYPE_SECONDS_BEFORE_EXPIRATION: 507 int secondsBeforeExpiration = 508 valueElement.decodeAsInteger().intValue(); 509 return new AccountUsableResponseControl(control.getOID(), 510 control.isCritical(), true, 511 secondsBeforeExpiration, 512 false, false, false, -1, 513 false, 0, controlValue); 514 case TYPE_MORE_INFO: 515 boolean isInactive = false; 516 boolean isReset = false; 517 boolean isExpired = false; 518 boolean isLocked = false; 519 int remainingGraceLogins = -1; 520 int secondsBeforeUnlock = 0; 521 522 for (ASN1Element e : valueElement.decodeAsSequence().elements()) 523 { 524 switch (e.getType()) 525 { 526 case TYPE_INACTIVE: 527 isInactive = e.decodeAsBoolean().booleanValue(); 528 break; 529 case TYPE_RESET: 530 isReset = e.decodeAsBoolean().booleanValue(); 531 break; 532 case TYPE_EXPIRED: 533 isExpired = e.decodeAsBoolean().booleanValue(); 534 break; 535 case TYPE_REMAINING_GRACE_LOGINS: 536 remainingGraceLogins = e.decodeAsInteger().intValue(); 537 break; 538 case TYPE_SECONDS_BEFORE_UNLOCK: 539 isLocked = true; 540 secondsBeforeUnlock = e.decodeAsInteger().intValue(); 541 break; 542 default: 543 Message message = ERR_ACCTUSABLERES_UNKNOWN_UNAVAILABLE_TYPE. 544 get(byteToHex(e.getType())); 545 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 546 } 547 } 548 549 return new AccountUsableResponseControl(control.getOID(), 550 control.isCritical(), false, 551 -1, isInactive, isReset, 552 isExpired, 553 remainingGraceLogins, 554 isLocked, secondsBeforeUnlock, 555 controlValue); 556 557 default: 558 Message message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE.get( 559 byteToHex(valueElement.getType())); 560 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 561 } 562 } 563 catch (LDAPException le) 564 { 565 throw le; 566 } 567 catch (ASN1Exception ae) 568 { 569 if (debugEnabled()) 570 { 571 TRACER.debugCaught(DebugLogLevel.ERROR, ae); 572 } 573 574 Message message = ERR_ACCTUSABLERES_DECODE_ERROR.get(ae.getMessage()); 575 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 576 } 577 catch (Exception e) 578 { 579 if (debugEnabled()) 580 { 581 TRACER.debugCaught(DebugLogLevel.ERROR, e); 582 } 583 584 Message message = 585 ERR_ACCTUSABLERES_DECODE_ERROR.get(getExceptionMessage(e)); 586 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 587 } 588 } 589 590 591 592 /** 593 * Indicates whether the associated user account is available for use. 594 * 595 * @return <CODE>true</CODE> if the associated user account is available, or 596 * <CODE>false</CODE> if not. 597 */ 598 public boolean isUsable() 599 { 600 return isUsable; 601 } 602 603 604 605 /** 606 * Retrieves the length of time in seconds before the user's password expires. 607 * This value is unreliable if the account is not available. 608 * 609 * @return The length of time in seconds before the user's password expires, 610 * or -1 if it is unknown or password expiration is not enabled for 611 * the user. 612 */ 613 public int getSecondsBeforeExpiration() 614 { 615 return secondsBeforeExpiration; 616 } 617 618 619 620 /** 621 * Indicates whether the user's account has been inactivated by an 622 * administrator. 623 * 624 * @return <CODE>true</CODE> if the user's account has been inactivated by 625 * an administrator, or <CODE>false</CODE> if not. 626 */ 627 public boolean isInactive() 628 { 629 return isInactive; 630 } 631 632 633 634 /** 635 * Indicates whether the user's password has been administratively reset and 636 * the user must change that password before any other operations will be 637 * allowed. 638 * 639 * @return <CODE>true</CODE> if the user's password has been administratively 640 * reset, or <CODE>false</CODE> if not. 641 */ 642 public boolean isReset() 643 { 644 return isReset; 645 } 646 647 648 649 /** 650 * Indicates whether the user's password is expired. 651 * 652 * @return <CODE>true</CODE> if the user's password is expired, or 653 * <CODE>false</CODE> if not. 654 */ 655 public boolean isExpired() 656 { 657 return isExpired; 658 } 659 660 661 662 /** 663 * Retrieves the number of remaining grace logins for the user. This value is 664 * unreliable if the user's password is not expired. 665 * 666 * @return The number of remaining grace logins for the user, or -1 if the 667 * grace logins feature is not enabled for the user. 668 */ 669 public int getRemainingGraceLogins() 670 { 671 return remainingGraceLogins; 672 } 673 674 675 676 /** 677 * Indicates whether the user's account is locked for some reason. 678 * 679 * @return <CODE>true</CODE> if the user's account is locked, or 680 * <CODE>false</CODE> if it is not. 681 */ 682 public boolean isLocked() 683 { 684 return isLocked; 685 } 686 687 688 689 /** 690 * Retrieves the length of time in seconds before the user's account is 691 * automatically unlocked. This value is unreliable is the user's account is 692 * not locked. 693 * 694 * @return The length of time in seconds before the user's account is 695 * automatically unlocked, or -1 if it requires administrative action 696 * to unlock the account. 697 */ 698 public int getSecondsBeforeUnlock() 699 { 700 return secondsBeforeUnlock; 701 } 702 703 704 705 /** 706 * Retrieves a string representation of this password policy response control. 707 * 708 * @return A string representation of this password policy response control. 709 */ 710 public String toString() 711 { 712 StringBuilder buffer = new StringBuilder(); 713 toString(buffer); 714 return buffer.toString(); 715 } 716 717 718 719 /** 720 * Appends a string representation of this password policy response control to 721 * the provided buffer. 722 * 723 * @param buffer The buffer to which the information should be appended. 724 */ 725 public void toString(StringBuilder buffer) 726 { 727 buffer.append("AccountUsableResponseControl(isUsable="); 728 buffer.append(isUsable); 729 730 if (isUsable) 731 { 732 buffer.append(",secondsBeforeExpiration="); 733 buffer.append(secondsBeforeExpiration); 734 } 735 else 736 { 737 buffer.append(",isInactive="); 738 buffer.append(isInactive); 739 buffer.append(",isReset="); 740 buffer.append(isReset); 741 buffer.append(",isExpired="); 742 buffer.append(isExpired); 743 buffer.append(",remainingGraceLogins="); 744 buffer.append(remainingGraceLogins); 745 buffer.append(",isLocked="); 746 buffer.append(isLocked); 747 buffer.append(",secondsBeforeUnlock="); 748 buffer.append(secondsBeforeUnlock); 749 } 750 751 buffer.append(")"); 752 } 753 } 754