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    }