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 register a YubiKey OTP device with the Directory Server so that it may be 048 * used to authenticate using the UNBOUNDID-YUBIKEY-OTP SASL mechanism. 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 extended request has an OID of 1.3.6.1.4.1.30221.2.6.54, and it must 061 * include a request value with the following encoding: 062 * <BR><BR> 063 * <PRE> 064 * RegisterYubiKeyOTPDeviceRequest ::= SEQUENCE { 065 * authenticationID [0] OCTET STRING OPTIONAL, 066 * staticPassword [1] OCTET STRING OPTIONAL, 067 * yubiKeyOTP [2] OCTET STRING, 068 * ... } 069 * </PRE> 070 * 071 * 072 * @see DeregisterYubiKeyOTPDeviceExtendedRequest 073 * @see com.unboundid.ldap.sdk.unboundidds.UnboundIDYubiKeyOTPBindRequest 074 * @see com.unboundid.ldap.sdk.unboundidds.RegisterYubiKeyOTPDevice 075 */ 076@NotMutable() 077@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 078public final class RegisterYubiKeyOTPDeviceExtendedRequest 079 extends ExtendedRequest 080{ 081 /** 082 * The OID (1.3.6.1.4.1.30221.2.6.54) for the register YubiKey OTP device 083 * extended request. 084 */ 085 public static final String REGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID = 086 "1.3.6.1.4.1.30221.2.6.54"; 087 088 089 090 /** 091 * The BER type for the authentication ID element of the request value 092 * sequence. 093 */ 094 private static final byte TYPE_AUTHENTICATION_ID = (byte) 0x80; 095 096 097 098 /** 099 * The BER type for the static password element of the request value sequence. 100 */ 101 private static final byte TYPE_STATIC_PASSWORD = (byte) 0x81; 102 103 104 105 /** 106 * The BER type for the YubiKey OTP element of the request value sequence. 107 */ 108 private static final byte TYPE_YUBIKEY_OTP = (byte) 0x82; 109 110 111 112 /** 113 * The serial version UID for this serializable class. 114 */ 115 private static final long serialVersionUID = 4833523148133015294L; 116 117 118 119 // The static password for the request. 120 private final ASN1OctetString staticPassword; 121 122 // The authentication ID for the request. 123 private final String authenticationID; 124 125 // The YubiKey OTP for the request. 126 private final String yubiKeyOTP; 127 128 129 130 /** 131 * Creates a new register YubiKey OTP device extended request that will be 132 * used to register a new device for the user as whom the underlying 133 * connection is authenticated. 134 * 135 * @param yubiKeyOTP A one-time password generated by the YubiKey device to 136 * be registered. It must not be {@code null}. 137 * @param controls The set of controls to include in the request. It may 138 * be {@code null} or empty if there should not be any 139 * request controls. 140 */ 141 public RegisterYubiKeyOTPDeviceExtendedRequest(final String yubiKeyOTP, 142 final Control... controls) 143 { 144 this(null, (ASN1OctetString) null, yubiKeyOTP, controls); 145 } 146 147 148 149 /** 150 * Creates a new register YubiKey OTP device extended request with the 151 * provided information. 152 * 153 * @param authenticationID The authentication ID that identifies the user 154 * for whom the YubiKey OTP device is to be 155 * registered. It may be {@code null} if the device 156 * is to be registered for the user as whom the 157 * underlying connection is authenticated. 158 * @param staticPassword The static password of the user for whom the 159 * device is to be registered. It may be 160 * {@code null} if the device is to be registered 161 * for a user other than the user authenticated on 162 * the underlying connection and the server is 163 * configured to not require the target user's 164 * static password in this case. 165 * @param yubiKeyOTP A one-time password generated by the YubiKey 166 * device to be registered. It must not be 167 * {@code null}. 168 * @param controls The set of controls to include in the request. 169 * It may be {@code null} or empty if there should 170 * not be any request controls. 171 */ 172 public RegisterYubiKeyOTPDeviceExtendedRequest(final String authenticationID, 173 final String staticPassword, 174 final String yubiKeyOTP, 175 final Control... controls) 176 { 177 this(authenticationID, encodePassword(staticPassword), yubiKeyOTP, 178 controls); 179 } 180 181 182 183 /** 184 * Creates a new register YubiKey OTP device extended request with the 185 * provided information. 186 * 187 * @param authenticationID The authentication ID that identifies the user 188 * for whom the YubiKey OTP device is to be 189 * registered. It may be {@code null} if the device 190 * is to be registered for the user as whom the 191 * underlying connection is authenticated. 192 * @param staticPassword The static password of the user for whom the 193 * device is to be registered. It may be 194 * {@code null} if the device is to be registered 195 * for a user other than the user authenticated on 196 * the underlying connection and the server is 197 * configured to not require the target user's 198 * static password in this case. 199 * @param yubiKeyOTP A one-time password generated by the YubiKey 200 * device to be registered. It must not be 201 * {@code null}. 202 * @param controls The set of controls to include in the request. 203 * It may be {@code null} or empty if there should 204 * not be any request controls. 205 */ 206 public RegisterYubiKeyOTPDeviceExtendedRequest(final String authenticationID, 207 final byte[] staticPassword, 208 final String yubiKeyOTP, 209 final Control... controls) 210 { 211 this(authenticationID, encodePassword(staticPassword), yubiKeyOTP, 212 controls); 213 } 214 215 216 217 /** 218 * Creates a new register YubiKey OTP device extended request with the 219 * provided information. 220 * 221 * @param authenticationID The authentication ID that identifies the user 222 * for whom the YubiKey OTP device is to be 223 * registered. It may be {@code null} if the device 224 * is to be registered for the user as whom the 225 * underlying connection is authenticated. 226 * @param staticPassword The static password of the user for whom the 227 * device is to be registered. It may be 228 * {@code null} if the device is to be registered 229 * for a user other than the user authenticated on 230 * the underlying connection and the server is 231 * configured to not require the target user's 232 * static password in this case. 233 * @param yubiKeyOTP A one-time password generated by the YubiKey 234 * device to be registered. It must not be 235 * {@code null}. 236 * @param controls The set of controls to include in the request. 237 * It may be {@code null} or empty if there should 238 * not be any request controls. 239 */ 240 private RegisterYubiKeyOTPDeviceExtendedRequest(final String authenticationID, 241 final ASN1OctetString staticPassword, final String yubiKeyOTP, 242 final Control... controls) 243 { 244 super(REGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID, 245 encodeValue(authenticationID, staticPassword, yubiKeyOTP), controls); 246 247 this.authenticationID = authenticationID; 248 this.staticPassword = staticPassword; 249 this.yubiKeyOTP = yubiKeyOTP; 250 } 251 252 253 254 /** 255 * Creates a new register YubiKey OTP device extended request that is decoded 256 * from the provided generic extended request. 257 * 258 * @param request The generic extended request to decode as a register 259 * YubiKey OTP device request. 260 * 261 * @throws LDAPException If a problem is encountered while attempting to 262 * decode the provided request. 263 */ 264 public RegisterYubiKeyOTPDeviceExtendedRequest(final ExtendedRequest request) 265 throws LDAPException 266 { 267 super(request); 268 269 final ASN1OctetString value = request.getValue(); 270 if (value == null) 271 { 272 throw new LDAPException(ResultCode.DECODING_ERROR, 273 ERR_REGISTER_YUBIKEY_OTP_REQUEST_NO_VALUE.get()); 274 } 275 276 try 277 { 278 String authID = null; 279 ASN1OctetString staticPW = null; 280 String otp = null; 281 for (final ASN1Element e : 282 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 283 { 284 switch (e.getType()) 285 { 286 case TYPE_AUTHENTICATION_ID: 287 authID = ASN1OctetString.decodeAsOctetString(e).stringValue(); 288 break; 289 case TYPE_STATIC_PASSWORD: 290 staticPW = ASN1OctetString.decodeAsOctetString(e); 291 break; 292 case TYPE_YUBIKEY_OTP: 293 otp = ASN1OctetString.decodeAsOctetString(e).stringValue(); 294 break; 295 default: 296 throw new LDAPException(ResultCode.DECODING_ERROR, 297 ERR_REGISTER_YUBIKEY_OTP_REQUEST_UNRECOGNIZED_TYPE.get( 298 StaticUtils.toHex(e.getType()))); 299 } 300 } 301 302 if (otp == null) 303 { 304 throw new LDAPException(ResultCode.DECODING_ERROR, 305 ERR_REGISTER_YUBIKEY_OTP_REQUEST_MISSING_OTP.get()); 306 } 307 308 authenticationID = authID; 309 staticPassword = staticPW; 310 yubiKeyOTP = otp; 311 } 312 catch (final LDAPException le) 313 { 314 Debug.debugException(le); 315 throw le; 316 } 317 catch (final Exception e) 318 { 319 Debug.debugException(e); 320 throw new LDAPException(ResultCode.DECODING_ERROR, 321 ERR_REGISTER_YUBIKEY_OTP_REQUEST_ERROR_DECODING_VALUE.get( 322 StaticUtils.getExceptionMessage(e)), 323 e); 324 } 325 } 326 327 328 329 /** 330 * Encodes the provided password as an ASN.1 octet string suitable for 331 * inclusion in the encoded request. 332 * 333 * @param password The password to be encoded. It may be {@code null} if 334 * no password should be included. If it is 335 * non-{@code null}, then it must be a string or a byte 336 * array. 337 * 338 * @return The encoded password, or {@code null} if no password was given. 339 */ 340 static ASN1OctetString encodePassword(final Object password) 341 { 342 if (password == null) 343 { 344 return null; 345 } 346 else if (password instanceof byte[]) 347 { 348 return new ASN1OctetString(TYPE_STATIC_PASSWORD, (byte[]) password); 349 } 350 else 351 { 352 return new ASN1OctetString(TYPE_STATIC_PASSWORD, 353 String.valueOf(password)); 354 } 355 } 356 357 358 359 /** 360 * Encodes the provided information into an ASN.1 octet string suitable for 361 * use as the value of this extended request. 362 * 363 * @param authenticationID The authentication ID that identifies the user 364 * for whom the YubiKey OTP device is to be 365 * registered. It may be {@code null} if the device 366 * is to be registered for the user as whom the 367 * underlying connection is authenticated. 368 * @param staticPassword The static password of the user for whom the 369 * device is to be registered. It may be 370 * {@code null} if the device is to be registered 371 * for a user other than the user authenticated on 372 * the underlying connection and the server is 373 * configured to not require the target user's 374 * static password in this case. 375 * @param yubiKeyOTP A one-time password generated by the YubiKey 376 * device to be registered. It must not be 377 * {@code null}. 378 * 379 * @return The ASN.1 octet string containing the encoded request value. 380 */ 381 private static ASN1OctetString encodeValue(final String authenticationID, 382 final ASN1OctetString staticPassword, 383 final String yubiKeyOTP) 384 { 385 Validator.ensureNotNull(yubiKeyOTP); 386 387 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 388 389 if (authenticationID != null) 390 { 391 elements.add( 392 new ASN1OctetString(TYPE_AUTHENTICATION_ID, authenticationID)); 393 } 394 395 if (staticPassword != null) 396 { 397 elements.add(staticPassword); 398 } 399 400 elements.add(new ASN1OctetString(TYPE_YUBIKEY_OTP, yubiKeyOTP)); 401 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 402 } 403 404 405 406 /** 407 * Retrieves the authentication ID that identifies the user for whom the 408 * YubiKey OTP device is to be registered, if provided. 409 * 410 * @return The authentication ID that identifies the target user, or 411 * {@code null} if the device is to be registered as the user as 412 * whom the underlying connection is authenticated. 413 */ 414 public String getAuthenticationID() 415 { 416 return authenticationID; 417 } 418 419 420 421 /** 422 * Retrieves the string representation of the static password for the target 423 * user, if provided. 424 * 425 * @return The string representation of the static password for the target 426 * user, or {@code null} if no static password was provided. 427 */ 428 public String getStaticPasswordString() 429 { 430 if (staticPassword == null) 431 { 432 return null; 433 } 434 else 435 { 436 return staticPassword.stringValue(); 437 } 438 } 439 440 441 442 /** 443 * Retrieves the bytes that comprise the static password for the target user, 444 * if provided. 445 * 446 * @return The bytes that comprise the static password for the target user, 447 * or {@code null} if no static password was provided. 448 */ 449 public byte[] getStaticPasswordBytes() 450 { 451 if (staticPassword == null) 452 { 453 return null; 454 } 455 else 456 { 457 return staticPassword.getValue(); 458 } 459 } 460 461 462 463 /** 464 * Retrieves a one-time password generated by the YubiKey device to be 465 * registered. 466 * 467 * @return A one-time password generated by the YubiKey device to be 468 * registered. 469 */ 470 public String getYubiKeyOTP() 471 { 472 return yubiKeyOTP; 473 } 474 475 476 477 /** 478 * {@inheritDoc} 479 */ 480 @Override() 481 public RegisterYubiKeyOTPDeviceExtendedRequest duplicate() 482 { 483 return duplicate(getControls()); 484 } 485 486 487 488 /** 489 * {@inheritDoc} 490 */ 491 @Override() 492 public RegisterYubiKeyOTPDeviceExtendedRequest duplicate( 493 final Control[] controls) 494 { 495 final RegisterYubiKeyOTPDeviceExtendedRequest r = 496 new RegisterYubiKeyOTPDeviceExtendedRequest(authenticationID, 497 staticPassword, yubiKeyOTP, controls); 498 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 499 return r; 500 } 501 502 503 504 /** 505 * {@inheritDoc} 506 */ 507 @Override() 508 public String getExtendedRequestName() 509 { 510 return INFO_REGISTER_YUBIKEY_OTP_REQUEST_NAME.get(); 511 } 512 513 514 515 /** 516 * {@inheritDoc} 517 */ 518 @Override() 519 public void toString(final StringBuilder buffer) 520 { 521 buffer.append("RegisterYubiKeyOTPDeviceExtendedRequest("); 522 523 if (authenticationID != null) 524 { 525 buffer.append("authenticationID='"); 526 buffer.append(authenticationID); 527 buffer.append("', "); 528 } 529 530 buffer.append("staticPasswordProvided="); 531 buffer.append(staticPassword != null); 532 533 final Control[] controls = getControls(); 534 if (controls.length > 0) 535 { 536 buffer.append(", controls={"); 537 for (int i=0; i < controls.length; i++) 538 { 539 if (i > 0) 540 { 541 buffer.append(", "); 542 } 543 544 buffer.append(controls[i]); 545 } 546 buffer.append('}'); 547 } 548 549 buffer.append(')'); 550 } 551}