1 /*
   2  * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.security.sasl;
  27 
  28 /**
  29  * Performs SASL authentication as a client.
  30  *<p>
  31  * A protocol library such as one for LDAP gets an instance of this
  32  * class in order to perform authentication defined by a specific SASL
  33  * mechanism. Invoking methods on the <tt>SaslClient</tt> instance
  34  * process challenges and create responses according to the SASL
  35  * mechanism implemented by the <tt>SaslClient</tt>.
  36  * As the authentication proceeds, the instance
  37  * encapsulates the state of a SASL client's authentication exchange.
  38  *<p>
  39  * Here's an example of how an LDAP library might use a <tt>SaslClient</tt>.
  40  * It first gets an instance of a <tt>SaslClient</tt>:
  41  *<blockquote><pre>{@code
  42  * SaslClient sc = Sasl.createSaslClient(mechanisms,
  43  *     authorizationId, protocol, serverName, props, callbackHandler);
  44  *}</pre></blockquote>
  45  * It can then proceed to use the client for authentication.
  46  * For example, an LDAP library might use the client as follows:
  47  *<blockquote><pre>{@code
  48  * // Get initial response and send to server
  49  * byte[] response = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[0]) :
  50  *     null);
  51  * LdapResult res = ldap.sendBindRequest(dn, sc.getName(), response);
  52  * while (!sc.isComplete() &&
  53  *     (res.status == SASL_BIND_IN_PROGRESS || res.status == SUCCESS)) {
  54  *     response = sc.evaluateChallenge(res.getBytes());
  55  *     if (res.status == SUCCESS) {
  56  *         // we're done; don't expect to send another BIND
  57  *         if (response != null) {
  58  *             throw new SaslException(
  59  *                 "Protocol error: attempting to send response after completion");
  60  *         }
  61  *         break;
  62  *     }
  63  *     res = ldap.sendBindRequest(dn, sc.getName(), response);
  64  * }
  65  * if (sc.isComplete() && res.status == SUCCESS) {
  66  *    String qop = (String) sc.getNegotiatedProperty(Sasl.QOP);
  67  *    if (qop != null
  68  *        && (qop.equalsIgnoreCase("auth-int")
  69  *            || qop.equalsIgnoreCase("auth-conf"))) {
  70  *
  71  *      // Use SaslClient.wrap() and SaslClient.unwrap() for future
  72  *      // communication with server
  73  *      ldap.in = new SecureInputStream(sc, ldap.in);
  74  *      ldap.out = new SecureOutputStream(sc, ldap.out);
  75  *    }
  76  * }
  77  *}</pre></blockquote>
  78  *
  79  * If the mechanism has an initial response, the library invokes
  80  * <tt>evaluateChallenge()</tt> with an empty
  81  * challenge and to get initial response.
  82  * Protocols such as IMAP4, which do not include an initial response with
  83  * their first authentication command to the server, initiates the
  84  * authentication without first calling <tt>hasInitialResponse()</tt>
  85  * or <tt>evaluateChallenge()</tt>.
  86  * When the server responds to the command, it sends an initial challenge.
  87  * For a SASL mechanism in which the client sends data first, the server should
  88  * have issued a challenge with no data. This will then result in a call
  89  * (on the client) to <tt>evaluateChallenge()</tt> with an empty challenge.
  90  *
  91  * @since 1.5
  92  *
  93  * @see Sasl
  94  * @see SaslClientFactory
  95  *
  96  * @author Rosanna Lee
  97  * @author Rob Weltman
  98  */
  99 public abstract interface SaslClient {
 100 
 101     /**
 102      * Returns the IANA-registered mechanism name of this SASL client.
 103      * (e.g. "CRAM-MD5", "GSSAPI").
 104      * @return A non-null string representing the IANA-registered mechanism name.
 105      */
 106     public abstract String getMechanismName();
 107 
 108     /**
 109      * Determines whether this mechanism has an optional initial response.
 110      * If true, caller should call <tt>evaluateChallenge()</tt> with an
 111      * empty array to get the initial response.
 112      *
 113      * @return true if this mechanism has an initial response.
 114      */
 115     public abstract boolean hasInitialResponse();
 116 
 117     /**
 118      * Evaluates the challenge data and generates a response.
 119      * If a challenge is received from the server during the authentication
 120      * process, this method is called to prepare an appropriate next
 121      * response to submit to the server.
 122      *
 123      * @param challenge The non-null challenge sent from the server.
 124      * The challenge array may have zero length.
 125      *
 126      * @return The possibly null reponse to send to the server.
 127      * It is null if the challenge accompanied a "SUCCESS" status and the challenge
 128      * only contains data for the client to update its state and no response
 129      * needs to be sent to the server. The response is a zero-length byte
 130      * array if the client is to send a response with no data.
 131      * @exception SaslException If an error occurred while processing
 132      * the challenge or generating a response.
 133      */
 134     public abstract byte[] evaluateChallenge(byte[] challenge)
 135         throws SaslException;
 136 
 137     /**
 138       * Determines whether the authentication exchange has completed.
 139       * This method may be called at any time, but typically, it
 140       * will not be called until the caller has received indication
 141       * from the server
 142       * (in a protocol-specific manner) that the exchange has completed.
 143       *
 144       * @return true if the authentication exchange has completed; false otherwise.
 145       */
 146     public abstract boolean isComplete();
 147 
 148     /**
 149      * Unwraps a byte array received from the server.
 150      * This method can be called only after the authentication exchange has
 151      * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
 152      * the authentication exchange has negotiated integrity and/or privacy
 153      * as the quality of protection; otherwise, an
 154      * <tt>IllegalStateException</tt> is thrown.
 155      *<p>
 156      * <tt>incoming</tt> is the contents of the SASL buffer as defined in RFC 2222
 157      * without the leading four octet field that represents the length.
 158      * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>incoming</tt>
 159      * to use.
 160      *
 161      * @param incoming A non-null byte array containing the encoded bytes
 162      *                from the server.
 163      * @param offset The starting position at <tt>incoming</tt> of the bytes to use.
 164      * @param len The number of bytes from <tt>incoming</tt> to use.
 165      * @return A non-null byte array containing the decoded bytes.
 166      * @exception SaslException if <tt>incoming</tt> cannot be successfully
 167      * unwrapped.
 168      * @exception IllegalStateException if the authentication exchange has
 169      * not completed, or  if the negotiated quality of protection
 170      * has neither integrity nor privacy.
 171      */
 172     public abstract byte[] unwrap(byte[] incoming, int offset, int len)
 173         throws SaslException;
 174 
 175     /**
 176      * Wraps a byte array to be sent to the server.
 177      * This method can be called only after the authentication exchange has
 178      * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
 179      * the authentication exchange has negotiated integrity and/or privacy
 180      * as the quality of protection; otherwise, an
 181      * <tt>IllegalStateException</tt> is thrown.
 182      *<p>
 183      * The result of this method will make up the contents of the SASL buffer
 184      * as defined in RFC 2222 without the leading four octet field that
 185      * represents the length.
 186      * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>outgoing</tt>
 187      * to use.
 188      *
 189      * @param outgoing A non-null byte array containing the bytes to encode.
 190      * @param offset The starting position at <tt>outgoing</tt> of the bytes to use.
 191      * @param len The number of bytes from <tt>outgoing</tt> to use.
 192      * @return A non-null byte array containing the encoded bytes.
 193      * @exception SaslException if <tt>outgoing</tt> cannot be successfully
 194      * wrapped.
 195      * @exception IllegalStateException if the authentication exchange has
 196      * not completed, or if the negotiated quality of protection
 197      * has neither integrity nor privacy.
 198      */
 199     public abstract byte[] wrap(byte[] outgoing, int offset, int len)
 200         throws SaslException;
 201 
 202     /**
 203      * Retrieves the negotiated property.
 204      * This method can be called only after the authentication exchange has
 205      * completed (i.e., when <tt>isComplete()</tt> returns true); otherwise, an
 206      * <tt>IllegalStateException</tt> is thrown.
 207      *
 208      * @param propName The non-null property name.
 209      * @return The value of the negotiated property. If null, the property was
 210      * not negotiated or is not applicable to this mechanism.
 211      * @exception IllegalStateException if this authentication exchange
 212      * has not completed
 213      */
 214 
 215     public abstract Object getNegotiatedProperty(String propName);
 216 
 217      /**
 218       * Disposes of any system resources or security-sensitive information
 219       * the SaslClient might be using. Invoking this method invalidates
 220       * the SaslClient instance. This method is idempotent.
 221       * @throws SaslException If a problem was encountered while disposing
 222       * the resources.
 223       */
 224     public abstract void dispose() throws SaslException;
 225 }