001 /* 002 * Copyright 2012-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2015 UnboundID Corp. 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 */ 021 package com.unboundid.ldap.sdk.unboundidds; 022 023 024 025 import com.unboundid.asn1.ASN1Element; 026 import com.unboundid.asn1.ASN1OctetString; 027 import com.unboundid.asn1.ASN1Sequence; 028 import com.unboundid.ldap.sdk.Control; 029 import com.unboundid.ldap.sdk.LDAPException; 030 import com.unboundid.ldap.sdk.ResultCode; 031 import com.unboundid.util.Debug; 032 import com.unboundid.util.NotMutable; 033 import com.unboundid.util.StaticUtils; 034 import com.unboundid.util.ThreadSafety; 035 import com.unboundid.util.ThreadSafetyLevel; 036 import com.unboundid.util.Validator; 037 038 import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*; 039 040 041 042 /** 043 * <BLOCKQUOTE> 044 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 045 * LDAP SDK for Java. It is not available for use in applications that 046 * include only the Standard Edition of the LDAP SDK, and is not supported for 047 * use in conjunction with non-UnboundID products. 048 * </BLOCKQUOTE> 049 * This class provides an implementation of the UNBOUNDID-TOTP SASL bind request 050 * that contains a point-in-time version of the one-time password and can be 051 * used for a single bind but is not suitable for repeated use. This version of 052 * the bind request should be used for authentication in which the one-time 053 * password is provided by an external source rather than being generated by 054 * the LDAP SDK. 055 * <BR><BR> 056 * Because the one-time password is provided rather than generated, this version 057 * of the bind request is not suitable for cases in which the authentication 058 * process may need to be repeated (e.g., for use in a connection pool, 059 * following referrals, or if the auto-reconnect feature is enabled), then the 060 * reusable variant (supported by the {@link ReusableTOTPBindRequest} class) 061 * which generates the one-time password should be used instead. 062 */ 063 @NotMutable() 064 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 065 public final class SingleUseTOTPBindRequest 066 extends UnboundIDTOTPBindRequest 067 { 068 /** 069 * The serial version UID for this serializable class. 070 */ 071 private static final long serialVersionUID = -4429898810534930296L; 072 073 074 075 // The hard-coded TOTP password to include in the bind request. 076 private final String totpPassword; 077 078 079 080 /** 081 * Creates a new SASL TOTP bind request with the provided information. 082 * 083 * @param authenticationID The authentication identity for the bind request. 084 * It must not be {@code null}, and must be in the 085 * form "u:" followed by a username, or "dn:" 086 * followed by a DN. 087 * @param authorizationID The authorization identity for the bind request. 088 * It may be {@code null} if the authorization 089 * identity should be the same as the authentication 090 * identity. If an authorization identity is 091 * specified, it must be in the form "u:" followed 092 * by a username, or "dn:" followed by a DN. The 093 * value "dn:" may indicate an authorization 094 * identity of the anonymous user. 095 * @param totpPassword The hard-coded TOTP password to include in the 096 * bind request. It must not be {@code null}. 097 * @param staticPassword The static password for the target user. It may 098 * be {@code null} if only the one-time password is 099 * to be used for authentication (which may or may 100 * not be allowed by the server). 101 * @param controls The set of controls to include in the bind 102 * request. 103 */ 104 public SingleUseTOTPBindRequest(final String authenticationID, 105 final String authorizationID, 106 final String totpPassword, 107 final String staticPassword, 108 final Control... controls) 109 { 110 super(authenticationID, authorizationID, staticPassword, controls); 111 112 Validator.ensureNotNull(totpPassword); 113 this.totpPassword = totpPassword; 114 } 115 116 117 118 /** 119 * Creates a new SASL TOTP bind request with the provided information. 120 * 121 * @param authenticationID The authentication identity for the bind request. 122 * It must not be {@code null}, and must be in the 123 * form "u:" followed by a username, or "dn:" 124 * followed by a DN. 125 * @param authorizationID The authorization identity for the bind request. 126 * It may be {@code null} if the authorization 127 * identity should be the same as the authentication 128 * identity. If an authorization identity is 129 * specified, it must be in the form "u:" followed 130 * by a username, or "dn:" followed by a DN. The 131 * value "dn:" may indicate an authorization 132 * identity of the anonymous user. 133 * @param totpPassword The hard-coded TOTP password to include in the 134 * bind request. It must not be {@code null}. 135 * @param staticPassword The static password for the target user. It may 136 * be {@code null} if only the one-time password is 137 * to be used for authentication (which may or may 138 * not be allowed by the server). 139 * @param controls The set of controls to include in the bind 140 * request. 141 */ 142 public SingleUseTOTPBindRequest(final String authenticationID, 143 final String authorizationID, 144 final String totpPassword, 145 final byte[] staticPassword, 146 final Control... controls) 147 { 148 super(authenticationID, authorizationID, staticPassword, controls); 149 150 Validator.ensureNotNull(totpPassword); 151 this.totpPassword = totpPassword; 152 } 153 154 155 156 /** 157 * Creates a new SASL TOTP bind request with the provided information. 158 * 159 * @param authenticationID The authentication identity for the bind request. 160 * It must not be {@code null}, and must be in the 161 * form "u:" followed by a username, or "dn:" 162 * followed by a DN. 163 * @param authorizationID The authorization identity for the bind request. 164 * It may be {@code null} if the authorization 165 * identity should be the same as the authentication 166 * identity. If an authorization identity is 167 * specified, it must be in the form "u:" followed 168 * by a username, or "dn:" followed by a DN. The 169 * value "dn:" may indicate an authorization 170 * identity of the anonymous user. 171 * @param totpPassword The hard-coded TOTP password to include in the 172 * bind request. It must not be {@code null}. 173 * @param staticPassword The static password for the target user. It may 174 * be {@code null} if only the one-time password is 175 * to be used for authentication (which may or may 176 * not be allowed by the server). 177 * @param controls The set of controls to include in the bind 178 * request. 179 */ 180 private SingleUseTOTPBindRequest(final String authenticationID, 181 final String authorizationID, 182 final String totpPassword, 183 final ASN1OctetString staticPassword, 184 final Control... controls) 185 { 186 super(authenticationID, authorizationID, staticPassword, controls); 187 188 Validator.ensureNotNull(totpPassword); 189 this.totpPassword = totpPassword; 190 } 191 192 193 194 /** 195 * Creates a new single-use TOTP bind request from the information contained 196 * in the provided encoded SASL credentials. 197 * 198 * @param saslCredentials The encoded SASL credentials to be decoded in 199 * order to create this single-use TOTP bind request. 200 * It must not be {@code null}. 201 * @param controls The set of controls to include in the bind 202 * request. 203 * 204 * @return The single-use TOTP bind request decoded from the provided 205 * credentials. 206 * 207 * @throws LDAPException If the provided credentials are not valid for an 208 * UNBOUNDID-TOTP bind request. 209 */ 210 public static SingleUseTOTPBindRequest 211 decodeSASLCredentials(final ASN1OctetString saslCredentials, 212 final Control... controls) 213 throws LDAPException 214 { 215 try 216 { 217 String authenticationID = null; 218 String authorizationID = null; 219 String totpPassword = null; 220 ASN1OctetString staticPassword = null; 221 222 final ASN1Sequence s = 223 ASN1Sequence.decodeAsSequence(saslCredentials.getValue()); 224 for (final ASN1Element e : s.elements()) 225 { 226 switch (e.getType()) 227 { 228 case TYPE_AUTHENTICATION_ID: 229 authenticationID = e.decodeAsOctetString().stringValue(); 230 break; 231 case TYPE_AUTHORIZATION_ID: 232 authorizationID = e.decodeAsOctetString().stringValue(); 233 break; 234 case TYPE_TOTP_PASSWORD: 235 totpPassword = e.decodeAsOctetString().stringValue(); 236 break; 237 case TYPE_STATIC_PASSWORD: 238 staticPassword = e.decodeAsOctetString(); 239 break; 240 default: 241 throw new LDAPException(ResultCode.DECODING_ERROR, 242 ERR_SINGLE_USE_TOTP_DECODE_INVALID_ELEMENT_TYPE.get( 243 StaticUtils.toHex(e.getType()))); 244 } 245 } 246 247 if (authenticationID == null) 248 { 249 throw new LDAPException(ResultCode.DECODING_ERROR, 250 ERR_SINGLE_USE_TOTP_DECODE_MISSING_AUTHN_ID.get()); 251 } 252 253 if (totpPassword == null) 254 { 255 throw new LDAPException(ResultCode.DECODING_ERROR, 256 ERR_SINGLE_USE_TOTP_DECODE_MISSING_TOTP_PW.get()); 257 } 258 259 return new SingleUseTOTPBindRequest(authenticationID, authorizationID, 260 totpPassword, staticPassword, controls); 261 } 262 catch (final Exception e) 263 { 264 Debug.debugException(e); 265 throw new LDAPException(ResultCode.DECODING_ERROR, 266 ERR_SINGLE_USE_TOTP_DECODE_ERROR.get( 267 StaticUtils.getExceptionMessage(e)), 268 e); 269 } 270 } 271 272 273 274 /** 275 * Retrieves the hard-coded TOTP password to include in the bind request. 276 * 277 * @return The hard-coded TOTP password to include in the bind request. 278 */ 279 public String getTOTPPassword() 280 { 281 return totpPassword; 282 } 283 284 285 286 /** 287 * {@inheritDoc} 288 */ 289 @Override() 290 protected ASN1OctetString getSASLCredentials() 291 { 292 return encodeCredentials(getAuthenticationID(), getAuthorizationID(), 293 totpPassword, getStaticPassword()); 294 } 295 296 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override() 302 public SingleUseTOTPBindRequest getRebindRequest(final String host, 303 final int port) 304 { 305 // Automatic rebinding is not supported for single-use TOTP binds. 306 return null; 307 } 308 309 310 311 /** 312 * {@inheritDoc} 313 */ 314 @Override() 315 public SingleUseTOTPBindRequest duplicate() 316 { 317 return duplicate(getControls()); 318 } 319 320 321 322 /** 323 * {@inheritDoc} 324 */ 325 @Override() 326 public SingleUseTOTPBindRequest duplicate(final Control[] controls) 327 { 328 final SingleUseTOTPBindRequest bindRequest = 329 new SingleUseTOTPBindRequest(getAuthenticationID(), 330 getAuthorizationID(), totpPassword, getStaticPassword(), 331 controls); 332 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 333 return bindRequest; 334 } 335 }