001/* 002 * Copyright 2016-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2016-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.extensions; 022 023 024 025import java.util.ArrayList; 026 027import com.unboundid.asn1.ASN1Element; 028import com.unboundid.asn1.ASN1OctetString; 029import com.unboundid.asn1.ASN1Sequence; 030import com.unboundid.ldap.sdk.Control; 031import com.unboundid.ldap.sdk.ExtendedRequest; 032import com.unboundid.ldap.sdk.LDAPException; 033import com.unboundid.ldap.sdk.ResultCode; 034import com.unboundid.util.Debug; 035import com.unboundid.util.NotMutable; 036import com.unboundid.util.StaticUtils; 037import com.unboundid.util.ThreadSafety; 038import com.unboundid.util.ThreadSafetyLevel; 039import com.unboundid.util.Validator; 040 041import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 042 043 044 045/** 046 * This class provides an implementation of an extended request that may be used 047 * to revoke one or all of the TOTP shared secrets for a user so that they may 048 * no longer be used to authenticate. 049 * <BR> 050 * <BLOCKQUOTE> 051 * <B>NOTE:</B> This class, and other classes within the 052 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 053 * supported for use against Ping Identity, UnboundID, and 054 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 055 * for proprietary functionality or for external specifications that are not 056 * considered stable or mature enough to be guaranteed to work in an 057 * interoperable way with other types of LDAP servers. 058 * </BLOCKQUOTE> 059 * <BR> 060 * This request may be invoked in one of following ways: 061 * <BR><BR> 062 * <UL> 063 * <LI> 064 * With a {@code null} authentication identity and a non-{@code null} 065 * TOTP shared secret. In this case, the authorization identity for the 066 * operation (typically the user as whom the underlying connection is 067 * authenticated, but possibly a different user if the request also includes 068 * a control like the proxied authorization or intermediate client request 069 * control that specifies and alternate authorization identity, or if the 070 * client authenticated with a SASL mechanism that included an alternate 071 * authorization identity) will be used as the authentication identity for 072 * this request, and only the specified TOTP shared secret will be removed 073 * from the user's entry while any other shared secrets that may be present 074 * in the user's entry will be preserved. If a static password is provided, 075 * then it will be verified, but if none is given then the provided TOTP 076 * shared secret will be considered sufficient proof of the user's identity. 077 * </LI> 078 * <LI> 079 * With a {@code null} authentication identity, a non-{@code null} static 080 * password, and a {@code null} TOTP shared secret. In this case, the 081 * authorization identity for the operation will be used as the 082 * authentication identity for this request, and, if the provided static 083 * password is valid, then all TOTP secrets contained in the user's entry 084 * will be revoked. 085 * </LI> 086 * <LI> 087 * With a non-{@code null} authentication identity and a non-{@code null} 088 * TOTP shared secret. In this case, only the provided TOTP shared secret 089 * will be removed from the specified user's account while any other shared 090 * secrets will be preserved. If a static password is provided, then it 091 * will be verified, but if none is given then the provided TOTP shared 092 * secret will be considered sufficient proof of the user's identity. 093 * </LI> 094 * <LI> 095 * With a non-{@code null} authentication identity a non-{@code null} 096 * static password, and a {@code null} TOTP shared secret. In this case, 097 * if the static password is valid for the specified user, then all TOTP 098 * shared secrets for that user will be revoked. 099 * </LI> 100 * <LI> 101 * With a non-{@code null} authentication identity a {@code null} static 102 * password, and a {@code null} TOTP shared secret. In this case, the 103 * authentication identity from the request must be different from the 104 * authorization identity for the operation, and the authorization identity 105 * must have the password-reset privilege. All TOTP shared secrets for 106 * the specified user will be revoked. 107 * </LI> 108 * </UL> 109 * <BR><BR> 110 * This extended request has an OID of 1.3.6.1.4.1.30221.2.6.58, and it must 111 * include a request value with the following encoding: 112 * <BR><BR> 113 * <PRE> 114 * RevokeTOTPSharedSecretRequest ::= SEQUENCE { 115 * authenticationID [0] OCTET STRING OPTIONAL, 116 * staticPassword [1] OCTET STRING OPTIONAL, 117 * totpSharedSecret [2] OCTET STRING OPTIONAL, 118 * ... } 119 * </PRE> 120 * 121 * 122 * @see GenerateTOTPSharedSecretExtendedRequest 123 */ 124@NotMutable() 125@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 126public final class RevokeTOTPSharedSecretExtendedRequest 127 extends ExtendedRequest 128{ 129 /** 130 * The OID (1.3.6.1.4.1.30221.2.6.58) for the revoke TOTP shared secret 131 * extended request. 132 */ 133 public static final String REVOKE_TOTP_SHARED_SECRET_REQUEST_OID = 134 "1.3.6.1.4.1.30221.2.6.58"; 135 136 137 138 /** 139 * The BER type for the authentication ID element of the request value 140 * sequence. 141 */ 142 private static final byte TYPE_AUTHENTICATION_ID = (byte) 0x80; 143 144 145 146 /** 147 * The BER type for the static password element of the request value sequence. 148 */ 149 private static final byte TYPE_STATIC_PASSWORD = (byte) 0x81; 150 151 152 153 /** 154 * The BER type for the TOTP shared secret element of the request value 155 * sequence. 156 */ 157 private static final byte TYPE_TOTP_SHARED_SECRET = (byte) 0x82; 158 159 160 161 /** 162 * The serial version UID for this serializable class. 163 */ 164 private static final long serialVersionUID = 1437768898568182738L; 165 166 167 168 // The static password for the request. 169 private final ASN1OctetString staticPassword; 170 171 // The authentication ID for the request. 172 private final String authenticationID; 173 174 // The base32-encoded representation of the TOTP shared secret to revoke. 175 private final String totpSharedSecret; 176 177 178 179 /** 180 * Creates a new revoke TOTP shared secret extended request with the provided 181 * information. 182 * 183 * @param authenticationID The authentication ID to use to identify the user 184 * for whom to revoke the TOTP shared secret. It 185 * should be a string in the form "dn:" followed by 186 * the DN of the target user, or "u:" followed by 187 * the username. It may be {@code null} if the 188 * authorization identity for the operation should 189 * be used as the authentication identity for this 190 * request. 191 * @param staticPassword The static password of the user for whom the TOTP 192 * shared secrets are to be revoked. It may be 193 * {@code null} if the provided 194 * {@code totpSharedSecret} is non-{@code null}, or 195 * if the {@code authenticationID} is 196 * non-{@code null} and the operation's 197 * authorization identity has the password-reset 198 * privilege. 199 * @param totpSharedSecret The base32-encoded representation of the TOTP 200 * shared secret to revoke. It may be {@code null} 201 * if all TOTP shared secrets should be purged from 202 * the target user's entry. If it is {@code null}, 203 * then either the {@code staticPassword} element 204 * must be non-{@code null}, or the 205 * {@code authenticationID} element must be 206 * non-{@code null}, must be different from the 207 * operation's authorization identity, and the 208 * authorization identity must have the 209 * password-reset privilege. 210 * @param controls The set of controls to include in the request. 211 * It may be {@code null} or empty if there should 212 * not be any request controls. 213 */ 214 public RevokeTOTPSharedSecretExtendedRequest(final String authenticationID, 215 final String staticPassword, 216 final String totpSharedSecret, 217 final Control... controls) 218 { 219 this(authenticationID, encodePassword(staticPassword), totpSharedSecret, 220 controls); 221 } 222 223 224 225 /** 226 * Creates a new revoke TOTP shared secret extended request with the provided 227 * information. 228 * 229 * @param authenticationID The authentication ID to use to identify the user 230 * for whom to revoke the TOTP shared secret. It 231 * should be a string in the form "dn:" followed by 232 * the DN of the target user, or "u:" followed by 233 * the username. It may be {@code null} if the 234 * authorization identity for the operation should 235 * be used as the authentication identity for this 236 * request. 237 * @param staticPassword The static password of the user for whom the TOTP 238 * shared secrets are to be revoked. It may be 239 * {@code null} if the provided 240 * {@code totpSharedSecret} is non-{@code null}, or 241 * if the {@code authenticationID} is 242 * non-{@code null} and the operation's 243 * authorization identity has the password-reset 244 * privilege. 245 * @param totpSharedSecret The base32-encoded representation of the TOTP 246 * shared secret to revoke. It may be {@code null} 247 * if all TOTP shared secrets should be purged from 248 * the target user's entry. If it is {@code null}, 249 * then either the {@code staticPassword} element 250 * must be non-{@code null}, or the 251 * {@code authenticationID} element must be 252 * non-{@code null}, must be different from the 253 * operation's authorization identity, and the 254 * authorization identity must have the 255 * password-reset privilege. 256 * @param controls The set of controls to include in the request. 257 * It may be {@code null} or empty if there should 258 * not be any request controls. 259 */ 260 public RevokeTOTPSharedSecretExtendedRequest(final String authenticationID, 261 final byte[] staticPassword, 262 final String totpSharedSecret, 263 final Control... controls) 264 { 265 this(authenticationID, encodePassword(staticPassword), totpSharedSecret, 266 controls); 267 } 268 269 270 271 /** 272 * Creates a new revoke TOTP shared secret extended request with the provided 273 * information. 274 * 275 * @param authenticationID The authentication ID to use to identify the user 276 * for whom to revoke the TOTP shared secret. It 277 * should be a string in the form "dn:" followed by 278 * the DN of the target user, or "u:" followed by 279 * the username. It may be {@code null} if the 280 * authorization identity for the operation should 281 * be used as the authentication identity for this 282 * request. 283 * @param staticPassword The static password of the user for whom the TOTP 284 * shared secrets are to be revoked. It may be 285 * {@code null} if the provided 286 * {@code totpSharedSecret} is non-{@code null}, or 287 * if the {@code authenticationID} is 288 * non-{@code null} and the operation's 289 * authorization identity has the password-reset 290 * privilege. 291 * @param totpSharedSecret The base32-encoded representation of the TOTP 292 * shared secret to revoke. It may be {@code null} 293 * if all TOTP shared secrets should be purged from 294 * the target user's entry. If it is {@code null}, 295 * then either the {@code staticPassword} element 296 * must be non-{@code null}, or the 297 * {@code authenticationID} element must be 298 * non-{@code null}, must be different from the 299 * operation's authorization identity, and the 300 * authorization identity must have the 301 * password-reset privilege. 302 * @param controls The set of controls to include in the request. 303 * It may be {@code null} or empty if there should 304 * not be any request controls. 305 */ 306 public RevokeTOTPSharedSecretExtendedRequest(final String authenticationID, 307 final ASN1OctetString staticPassword, 308 final String totpSharedSecret, final Control... controls) 309 { 310 super(REVOKE_TOTP_SHARED_SECRET_REQUEST_OID, 311 encodeValue(authenticationID, staticPassword, totpSharedSecret), 312 controls); 313 314 this.authenticationID = authenticationID; 315 this.staticPassword = staticPassword; 316 this.totpSharedSecret = totpSharedSecret; 317 } 318 319 320 321 /** 322 * Creates a new revoke TOTP shared secret extended request that is decoded 323 * from the provided generic extended request. 324 * 325 * @param request The generic extended request to decode as a revoke TOTP 326 * shared secret request. 327 * 328 * @throws LDAPException If a problem is encountered while attempting to 329 * decode the provided request. 330 */ 331 public RevokeTOTPSharedSecretExtendedRequest(final ExtendedRequest request) 332 throws LDAPException 333 { 334 super(request); 335 336 final ASN1OctetString value = request.getValue(); 337 if (value == null) 338 { 339 throw new LDAPException(ResultCode.DECODING_ERROR, 340 ERR_REVOKE_TOTP_SECRET_REQUEST_NO_VALUE.get()); 341 } 342 343 try 344 { 345 String authID = null; 346 ASN1OctetString staticPW = null; 347 String totpSecret = null; 348 for (final ASN1Element e : 349 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 350 { 351 switch (e.getType()) 352 { 353 case TYPE_AUTHENTICATION_ID: 354 authID = ASN1OctetString.decodeAsOctetString(e).stringValue(); 355 break; 356 case TYPE_STATIC_PASSWORD: 357 staticPW = ASN1OctetString.decodeAsOctetString(e); 358 break; 359 case TYPE_TOTP_SHARED_SECRET: 360 totpSecret = ASN1OctetString.decodeAsOctetString(e).stringValue(); 361 break; 362 default: 363 throw new LDAPException(ResultCode.DECODING_ERROR, 364 ERR_REVOKE_TOTP_SECRET_REQUEST_UNRECOGNIZED_TYPE.get( 365 StaticUtils.toHex(e.getType()))); 366 } 367 } 368 369 if ((authID == null) && (staticPW == null) && (totpSecret == null)) 370 { 371 throw new LDAPException(ResultCode.DECODING_ERROR, 372 ERR_REVOKE_TOTP_SECRET_REQUEST_NO_AUTHN_ID_OR_PW_OR_SECRET.get()); 373 } 374 375 authenticationID = authID; 376 staticPassword = staticPW; 377 totpSharedSecret = totpSecret; 378 } 379 catch (final LDAPException le) 380 { 381 Debug.debugException(le); 382 throw le; 383 } 384 catch (final Exception e) 385 { 386 Debug.debugException(e); 387 throw new LDAPException(ResultCode.DECODING_ERROR, 388 ERR_REVOKE_TOTP_SECRET_REQUEST_ERROR_DECODING_VALUE.get( 389 StaticUtils.getExceptionMessage(e)), 390 e); 391 } 392 } 393 394 395 396 /** 397 * Encodes the provided password as an ASN.1 octet string suitable for 398 * inclusion in the encoded request. 399 * 400 * @param password The password to be encoded. It may be {@code null} if 401 * no password should be included. If it is 402 * non-{@code null}, then it must be a string or a byte 403 * array. 404 * 405 * @return The encoded password, or {@code null} if no password was given. 406 */ 407 private static ASN1OctetString encodePassword(final Object password) 408 { 409 if (password == null) 410 { 411 return null; 412 } 413 else if (password instanceof byte[]) 414 { 415 return new ASN1OctetString(TYPE_STATIC_PASSWORD, (byte[]) password); 416 } 417 else 418 { 419 return new ASN1OctetString(TYPE_STATIC_PASSWORD, 420 String.valueOf(password)); 421 } 422 } 423 424 425 426 /** 427 * Encodes the provided information into an ASN.1 octet string suitable for 428 * use as the value of this extended request. 429 * 430 * @param authenticationID The authentication ID to use to identify the user 431 * for whom to revoke the TOTP shared secret. It 432 * should be a string in the form "dn:" followed by 433 * the DN of the target user, or "u:" followed by 434 * the username. It may be {@code null} if the 435 * authorization identity for the operation should 436 * be used as the authentication identity for this 437 * request. 438 * @param staticPassword The static password of the user for whom the TOTP 439 * shared secrets are to be revoked. It may be 440 * {@code null} if the provided 441 * {@code totpSharedSecret} is non-{@code null}, or 442 * if the {@code authenticationID} is 443 * non-{@code null} and the operation's 444 * authorization identity has the password-reset 445 * privilege. 446 * @param totpSharedSecret The TOTP shared secret to revoke. It may be 447 * {@code null} if all TOTP shared secrets should be 448 * purged from the target user's entry. If it is 449 * {@code null}, then either the 450 * {@code staticPassword} element must be 451 * non-{@code null}, or the {@code authenticationID} 452 * element must be non-{@code null}, must be 453 * different from the operation's authorization 454 * identity, and the authorization identity must 455 * have the password-reset privilege. 456 * 457 * @return The ASN.1 octet string containing the encoded request value. 458 */ 459 private static ASN1OctetString encodeValue(final String authenticationID, 460 final ASN1OctetString staticPassword, 461 final String totpSharedSecret) 462 { 463 if (totpSharedSecret == null) 464 { 465 Validator.ensureTrue( 466 ((authenticationID != null) || (staticPassword != null)), 467 "If the TOTP shared secret is null, then at least one of the " + 468 "authentication ID and static password must be non-null."); 469 } 470 471 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 472 473 if (authenticationID != null) 474 { 475 elements.add( 476 new ASN1OctetString(TYPE_AUTHENTICATION_ID, authenticationID)); 477 } 478 479 if (staticPassword != null) 480 { 481 elements.add(staticPassword); 482 } 483 484 if (totpSharedSecret != null) 485 { 486 elements.add( 487 new ASN1OctetString(TYPE_TOTP_SHARED_SECRET, totpSharedSecret)); 488 } 489 490 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 491 } 492 493 494 495 /** 496 * Retrieves the authentication ID that identifies the user for whom to revoke 497 * the TOTP shared secrets, if provided. 498 * 499 * @return The authentication ID that identifies the target user, or 500 * {@code null} if the shared secrets are to be revoked for the 501 * operation's authorization identity. 502 */ 503 public String getAuthenticationID() 504 { 505 return authenticationID; 506 } 507 508 509 510 /** 511 * Retrieves the string representation of the static password for the target 512 * user, if provided. 513 * 514 * @return The string representation of the static password for the target 515 * user, or {@code null} if no static password was provided. 516 */ 517 public String getStaticPasswordString() 518 { 519 if (staticPassword == null) 520 { 521 return null; 522 } 523 else 524 { 525 return staticPassword.stringValue(); 526 } 527 } 528 529 530 531 /** 532 * Retrieves the bytes that comprise the static password for the target user, 533 * if provided. 534 * 535 * @return The bytes that comprise the static password for the target user, 536 * or {@code null} if no static password was provided. 537 */ 538 public byte[] getStaticPasswordBytes() 539 { 540 if (staticPassword == null) 541 { 542 return null; 543 } 544 else 545 { 546 return staticPassword.getValue(); 547 } 548 } 549 550 551 552 /** 553 * Retrieves the base32-encoded representation of the TOTP shared secret to be 554 * revoked, if provided. 555 * 556 * @return The base32-encoded representation of the TOTP shared secret to be 557 * revoked, or {@code null} if all of the user's TOTP shared secrets 558 * should be revoked. 559 */ 560 public String getTOTPSharedSecret() 561 { 562 return totpSharedSecret; 563 } 564 565 566 567 /** 568 * {@inheritDoc} 569 */ 570 @Override() 571 public RevokeTOTPSharedSecretExtendedRequest duplicate() 572 { 573 return duplicate(getControls()); 574 } 575 576 577 578 /** 579 * {@inheritDoc} 580 */ 581 @Override() 582 public RevokeTOTPSharedSecretExtendedRequest duplicate( 583 final Control[] controls) 584 { 585 final RevokeTOTPSharedSecretExtendedRequest r = 586 new RevokeTOTPSharedSecretExtendedRequest(authenticationID, 587 staticPassword, totpSharedSecret, controls); 588 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 589 return r; 590 } 591 592 593 594 /** 595 * {@inheritDoc} 596 */ 597 @Override() 598 public String getExtendedRequestName() 599 { 600 return INFO_REVOKE_TOTP_SECRET_REQUEST_NAME.get(); 601 } 602 603 604 605 /** 606 * {@inheritDoc} 607 */ 608 @Override() 609 public void toString(final StringBuilder buffer) 610 { 611 buffer.append("RevokeTOTPSharedSecretExtendedRequest("); 612 613 if (authenticationID != null) 614 { 615 buffer.append("authenticationID='"); 616 buffer.append(authenticationID); 617 buffer.append("', "); 618 } 619 620 buffer.append("staticPasswordProvided="); 621 buffer.append(staticPassword != null); 622 buffer.append(", totpSharedSecretProvided="); 623 buffer.append(totpSharedSecret != null); 624 625 final Control[] controls = getControls(); 626 if (controls.length > 0) 627 { 628 buffer.append(", controls={"); 629 for (int i=0; i < controls.length; i++) 630 { 631 if (i > 0) 632 { 633 buffer.append(", "); 634 } 635 636 buffer.append(controls[i]); 637 } 638 buffer.append('}'); 639 } 640 641 buffer.append(')'); 642 } 643}