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 }