Network Working Group Rosanna Lee INTERNET-DRAFT Sun Microsystems Intended Category: Standards Track Rob Weltman November, 2000 The Java SASL Application Program Interface draft-weltman-java-sasl-04.txt Status of this Memo This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026. Internet-Drafts are working documents of the Internet Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. Abstract This document defines a client-side and a server-side Java language interface for using the Simple Authentication and Security Layer (SASL) mechanisms for adding authentication support to connection- based protocols. The interface promotes sharing of SASL mechanism drivers and security layers between applications using different protocols. It complements but does not replace [SASL], which defines and exemplifies use of the SASL protocol in a language-independent way. Expires May 2001 [Page 1] JAVA SASL API November, 2000 1. Introduction....................................................4 2. Overview of the SASL classes....................................6 2.1 Interfaces.....................................................6 2.2 Classes........................................................7 3. Overview of SASL API Use........................................7 4. The Java SASL classes...........................................8 4.1 public class Sasl..............................................9 4.1.1 createSaslClient...............................................9 4.1.2 setSaslClientFactory..........................................11 4.1.3 createSaslServer..............................................11 4.1.4 setSaslServerFactory..........................................13 4.1.5 getSaslClientFactories........................................13 4.1.6 getSaslServerFactories........................................13 4.1.7 Standard Properties...........................................13 4.2 public interface SaslClient...................................16 4.2.1 evaluateChallenge.............................................16 4.2.2 hasInitialResponse............................................16 4.2.3 isComplete....................................................16 4.2.4 getInputStream................................................17 4.2.5 getOutputStream...............................................17 4.2.6 getMechanismName..............................................18 4.2.7 getNegotiatedQop..............................................18 4.2.8 getNegotiatedStrength.........................................18 4.3 public interface SaslClientFactory............................18 4.3.1 createSaslClient..............................................19 4.3.2 getMechanismNames.............................................20 4.4 public interface SaslServer...................................20 4.4.1 evaluateResponse..............................................20 4.4.2 isComplete....................................................21 4.4.3 getInputStream................................................21 4.4.4 getOutputStream...............................................22 4.4.5 getMechanismName..............................................22 4.4.6 getAuthorizationID............................................22 4.4.7 getNegotiatedQop..............................................22 4.4.8 getNegotiatedStrength.........................................23 4.5 public interface SaslServerFactory............................23 4.5.1 createSaslServer..............................................23 4.5.2 getMechanismNames.............................................24 4.6 public class javax.security.sasl.AuthorizeCallback............24 4.6.1 Constructors..................................................25 4.6.2 getAuthenticationId...........................................25 4.6.3 getAuthorizationId............................................25 4.6.4 isAuthorized..................................................25 4.6.5 setAuthorized.................................................25 4.6.6 getAuthorizedId...............................................26 4.6.7 setAuthorizedId...............................................26 4.7 public class javax.security.sasl.RealmCallback................26 4.7.1 Constructors..................................................26 4.8 public class javax.security.sasl.RealmChoiceCallback..........27 4.8.1 Constructors..................................................27 4.9 public class SaslException extends IOException................27 4.9.1 Constructors..................................................27 Expires May 2001 [Page 2 JAVA SASL API November, 2000 4.9.2 getCause......................................................28 4.9.3 printStackTrace...............................................28 5. Security Considerations........................................29 6. Copyright......................................................29 7. Bibliography...................................................30 8. Authors' Addresses.............................................30 9. Acknowledgements...............................................30 10. Changes from draft-weltman-java-sasl-03.txt....................30 11. Changes from draft-weltman-java-sasl-02.txt....................31 12. Appendix A - Sample Java LDAP program using SASL...............33 Expires May 2001 [Page 3 JAVA SASL API November, 2000 1. Introduction See [SASL], section 3, for an introduction to and overview of the SASL framework for authentication and negotiation of a security layer. The following presents an outline of the concepts. --------------- ------------------- ----------------- | Application |-----| Protocol Driver |------| MD5 | --------------- ------------------- | ----------------- | | ----------------- |--| Kerberos v5 | | ----------------- | | ----------------- |--| PKCS-11 | | ----------------- | | | | - - - - - - - - - |--| xxxYYYxxx | - - - - - - - - - An application chooses a Protocol Driver specific to the protocol it wants to use, and specifies one or more acceptable mechanisms. The Protocol Driver controls the socket, and knows the format/packaging of bytes sent down and received from the socket, but does not know how to authenticate or to encrypt/ decrypt the bytes. It uses one of the Mechanism Drivers to help it perform authentication. The Protocol Driver examines each byte string received from the server during the authentication in a protocol-specific way to determine if the authentication process has been completed. If not, the byte string is passed to the Mechanism Driver to be interpreted as a server challenge; the Mechanism Driver returns an appropriate response, which the Protocol Driver can encode in a protocol-specific way and return to the server. If the Protocol Driver concludes from the byte string received from the server that authentication is complete, it may query the Mechanism Driver if it considers the authentication process complete, in order to thwart early completion messages inserted by an intruder. On completed authentication, the Protocol Driver may receive from the Mechanism Driver input and output streams that encapsulate the negotiated security layer. From this point on, any data exchanged through the socket is passed to these input and output streams. A complication here is that some authentication methods may require additional user/application input. That means that a Mechanism Driver may need to call up to an application during the authentication process. To satisfy this requirement, the application can supply a javax.security.auth.callback.CallbackHandler instance Expires May 2001 [Page 4 JAVA SASL API November, 2000 [JAAS] that can be used by the Mechanism Driver to prompt the user for additional input. Protocol Drivers are protocol-dependent, and may be built in to a protocol package or an application. There is a generalized framework for registering and finding Mechanism Drivers. The framework uses a factory to produce an appropriate Mechanism Driver. The factory may be preconfigured, explicitly specified by the caller, specified as a list of packages by the caller, or be identified based on a list of packages in the System properties. The Mechanism Drivers are protocol-independent, and don't deal directly with network connections, just byte arrays, so they can be implemented in a generalizable way for all protocols. The negotiated security layer is encapsulated in input and output streams, which typically inherit a state object from the Mechanism Driver, where parameters and resolutions reached during authentication have been stored. Different Mechanism Drivers may require different parameters to carry out the authentication process. This is handled by passing a java.util.Hashtable object as an argument to instantiation methods. In the following discussion, 'client' refers to the client-side protocol driver that is using the SASL mechanism while 'server' refers to the server-side protocol driver that is using the SASL mechanism. Expires May 2001 [Page 5 JAVA SASL API November, 2000 In the Java SASL environment, the SaslClient interface represents the client's view of the Mechanism Driver, while the SaslServer interface represents the server's view. --------------- --------------- | Application |--+ +--| Server | --------------- | | --------------- | | ------------------- ------------------- | Protocol Driver |--+ <- - - - -> +--| Protocol Driver | ------------------- | | ------------------- | | ------------------- ------------------- | SaslClient | | SaslServer | ------------------- ------------------- | | ----------------- | | ----------------- | MD5 |----| |---| MD5 | ----------------- | | ----------------- | | ----------------- | | ----------------- | Kerberos v5 |----| |---| Kerberos v5 | ----------------- | | ----------------- | | ----------------- | | ----------------- | PKCS-11 |----| |---| PKCS-11 | ----------------- | | ----------------- | | - - - - - - - - - | | - - - - - - - - - | xxxYYYxxx |----+ +---| xxxYYYxxx | - - - - - - - - - - - - - - - - - - A client using the Java SASL API may communicate with any server implementing the SASL protocol, and a server may use the API to process authentication requests from any client using the SASL protocol. It is not required that both sides use the same language bindings. 2. Overview of the SASL classes 2.1 Interfaces SaslClient Performs SASL authentication as a client. SaslClientFactory An interface for creating instances of SaslClient. It is not normally accessed directly by a client, which will use the Sasl static methods instead. However, a particular environment may provide and Expires May 2001 [Page 6 JAVA SASL API November, 2000 install a new or different SaslClientFactory. SaslServer Performs SASL authentication as a server. SaslServerFactory An interface for creating instances of SaslServer. It is not normally accessed directly by a server, which will use the Sasl static methods instead. However, a particular environment may provide and install a new or different SaslServerFactory. 2.2 Classes Sasl A static class for creating SASL clients and servers. It transparently locates and uses any available SaslClientFactory/SaslServerFactory instances. AuthorizeCallback This callback is used by SaslServer to determine whether one entity (identified by an authenticated authentication id) can act on behalf of another entity (identified by an authorization id). RealmCallback This callback is used by SaslClient and SaslServer to retrieve realm information. RealmChoiceCallback This callback is used by SaslClient and SaslServer to obtain one or more realms given a list of realm choices. SaslException Exception thrown on errors and failures in the authentication process. 3. Overview of SASL API Use An application generally uses the SASL API as follows: - Pass a list of acceptable or known Mechanisms to Sasl.createSaslClient. The method returns an object implementing SaslClient on success. - Create an object implementing the client authentication callback interfaces, which can provide credentials when required by the SaslClient. Expires May 2001 [Page 7 JAVA SASL API November, 2000 - Have the SaslClient object begin the authentication process by providing an initial server response, if the protocol supports an initial response. - Responses/challenges are exchanged with the server. If a response indicates authentication has completed, SaslClient is queried for validation, and input and output streams that encapsulate the negotiated security layer may be obtained from it. If not, the SaslClient is queried for an appropriate next response to the server. This continues until authentication has completed. - For the rest of the session, messages to the server are written to the output stream which encodes the data (if a security layer has been negotiated), and messages from the server are read from the input stream which decodes the data before processing in the application. A server generally uses the SASL API as follows: - It receives a request from the client requesting authentication for a particular SASL mechanism, accompanied by an optional initial response. - It processes the initial response and generates a challenge specific for the SASL mechanism to be sent back to the client if the response is processed successfully. If the response is not processed successfully, it sends an error to the client and terminates the authentication session. - Responses/challenges are exchanged with the client. If the server cannot successfully process a response, the server sends an error to the client and terminates the authentication. If the server has completed the authentication and has no more challenges to send, it sends a success indication to the client. - If the authentication has completed successfully, the server extracts the authorization ID of the client from the SaslServer instance (if appropriate) to be used for subsequent access control checks. - For the rest of the session, messages to and from the client are encoded and decoded using the input and output streams that encapsulate the negotiated security layer (if any). The following sections describe the SASL classes in more detail. 4. The Java SASL classes Expires May 2001 [Page 8 JAVA SASL API November, 2000 4.1 public class Sasl A class capable of providing a SaslClient or SaslServer. 4.1.1 createSaslClient public static SaslClient createSaslClient(String[] mechanisms, String authorizationID, String protocol, String serverName, Hashtable props, javax.security.auth.callback.CallbackHandler cbh) throws SaslException Creates a SaslClient using the parameters supplied. It returns null if no SaslClient can be created using the parameters supplied. Throws SaslException if it cannot create a SaslClient because of an error. The algorithm for selection is as follows: 1. If a factory has been installed via setSaslClientFactory(), invoke createSaslClient() on it. If the method invocation returns a non-null SaslClient instance, return the SaslClient instance; otherwise continue. 2. Create a list of fully qualified class names using the package names listed in the CLIENT_PKGS ("javax.security.sasl.client.pkgs") property in props and the class name ClientFactory. Each class name in this list identifies a SaslClientFactory implementation. Starting with the first class on the list, create an instance of SaslClientFactory using the class' public no-argument constructor and invoke createSaslClient() on it. If the method invocation returns a non- null SaslClient instance, return it; otherwise repeat using the next class on the list until a non-null SaslClient is produced or the list is exhausted. 3. Repeat the previous step using the CLIENT_PKGS ("javax.security.sasl.client.pkgs") System property instead of the property in props. 4. As per the Java 2 Standard Edition version 1.3 service provider guidelines, check for the existence of one of more files named META-INF/services/javax.security.sasl.SaslClientFactory in the classpath and installed JAR files. Each file lists the fully qualified class names of the factories (i.e. implementations of SaslClientFactory) found in the JAR files or classpath. Construct a merged list of class names using these files and repeat Step 2 using this list. If there is more than one of these files, the order in which they are processed is undefined. If no non-null SaslClient instance is produced, return null. Parameters are: Expires May 2001 [Page 9 JAVA SASL API November, 2000 mechanisms The non-null list of mechanism names to try. Each is the IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5"). authorizationID The possibly null protocol-dependent identification to be used for authorization, e.g. user name or distinguished name. When the SASL authentication completes successfully, the entity named by authorizationId is granted access. If null, access is granted to a protocol-dependent default (for example, in LDAP this is the DN in the bind request). protocol The non-null string name of the protocol for which the authentication is being performed, e.g "pop", "ldap". serverName The non-null fully qualified host name of the server to authenticate to. props The possibly null additional configuration properties for the session, e.g. Sasl.POLICY_NOPLAINTEXT If the property has the value "true", then the selected SASL mechanism must not be susceptible to simple plain passive attacks. In addition to the standard properties of this class, other, possibly mechanism-specific, properties can be included. Properties not relevant to the selected mechanism are ignored. See Standard Properties for a list of standard properties. cbh The possibly null callback handler to used by the SASL mechanisms to get further information from the application/library to complete the authentication. For example, a SASL mechanism might require the authentication ID, password and realm from the caller. The authentication ID is requested by using a NameCallback. The password is requested by using a PasswordCallback. The realm is requested by using a RealmChoiceCallback if there is a list of realms to choose from, and by using a RealmCallback if the realm must be entered. Expires May 2001 [Page 10 JAVA SASL API November, 2000 4.1.2 setSaslClientFactory public static void setSaslClientFactory(SaslClientFactory fac) Sets the default SaslClientFactory to use. This method sets fac to be the default factory. It can only be called with a non-null value once per VM. If a factory has been set already, this method throws IllegalStateException. The method throws java.lang.SecurityException if the caller does not have the necessary permission to set the factory. Parameters are: fac The possibly null factory to set. If null, it doesn't do anything. 4.1.3 createSaslServer public static SaslServer createSaslServer(String mechanism, String protocol, String serverName, Hashtable props, javax.security.auth.callback.CallbackHandler cbh) throws SaslException This method creates a SaslServer for the specified mechanism. It returns null if no SaslServer can be created for the specified mechanism. The algorithm for selection is as follows: 1. If a factory has been installed via setSaslServerFactory(), invoke createSaslServer() on it. If the method invocation returns a non-null SaslServer instance, return the SaslServer instance; otherwise continue. 2. Create a list of fully qualified class names using the package names listed in the SERVER_PKGS ("javax.security.sasl.server.pkgs") property in props and the class name ServerFactory. Each class name in this list identifies a SaslServerFactory implementation. Starting with the first class on the list, create an instance of SaslServerFactory using the class' public no-argument constructor and invoke createSaslServer() on it. If the method invocation returns a non- null SaslServer instance, return it; otherwise repeat using the next class on the list until a non-null SaslServer is produced or the list is exhausted. 3. Repeat the previous step using the SERVER_PKGS ("javax.security.sasl.server.pkgs") System property instead of the property in props. Expires May 2001 [Page 11 JAVA SASL API November, 2000 4. As per the Java 2 Standard Edition version 1.3 service provider guidelines, check for the existence of one of more files named META-INF/services/javax.security.sasl.SaslServerFactory in the classpath and installed JAR files. Each file lists the fully qualified class names of the factories (i.e. implementations of SaslServerFactory) found in the JAR files or classpath. Construct a merged list of class names using these files and repeat Step 2 using this list. If there is more than one of these files, the order in which they are processed is undefined. If no non-null SaslServer instance is produced, return null. 5. If no non-null answer produced, return null. Parameters are: mechanism A non-null IANA-registered name of a SASL mechanism (e.g. "GSSAPI", "CRAM-MD5"). protocol The non-null string name of the protocol for which the authentication is being performed, e.g "pop", "ldap". serverName The non-null fully qualified host name of the server. props The possibly null properties to be used by the SASL mechanism to configure the authentication exchange, e.g. Sasl.POLICY_NOPLAINTEXT If the property has the value "true", then the selected SASL mechanism must not be susceptible to simple plain passive attacks. In addition to the standard properties defined in this class, other, possibly mechanism-specific, properties can be included. Properties not relevant to the selected mechanism are ignored. See section 4.1.7 Standard Properties for a list of standard properties. cbh The possibly null callback handler to used by the SASL mechanism to get further information from the application/library to complete the authentication. For example, a SASL mechanism might require the authentication ID and password from the caller. The authentication ID may be requested with a NameCallback, and the password with a PasswordCallback. Expires May 2001 [Page 12 JAVA SASL API November, 2000 4.1.4 setSaslServerFactory public static void setSaslServerFactory(SaslServerFactory fac) Sets the default SaslServerFactory to use. This method sets fac to be the default factory. It can only be called with a non-null value once per VM. If a factory has been set already, this method throws IllegalStateException. The method throws java.lang.SecurityException if the caller does not have the necessary permission to set the factory. Parameters are: fac The possibly null factory to set. If null, it doesn't do anything. 4.1.5 getSaslClientFactories public java.util.Enumeration getSaslClientFactories(java.util.Hashtable props) Gets an enumeration of known factories for producing SaslClient. Parameters are: props A possibly null properties that may contain the property CLIENT_PKGS ("javax.security.sasl.client.pkgs") for specifying a list of SaslClientFactory implementation package names. 4.1.6 getSaslServerFactories public java.util.Enumeration getSaslServerFactories(java.util.Hashtable props) Gets an enumeration of known factories for producing SaslServer. Parameters are: props A possibly null properties that may contain the property SERVER_PKGS ("javax.security.sasl.server.pkgs") for specifying a list of SaslServerFactory implementation package names. 4.1.7 Standard Properties Expires May 2001 [Page 13 JAVA SASL API November, 2000 There are a number of properties that may be specified in a Hashtable parameter when creating a SASL client or server. The standard properties are as follows (with the Sasl constant name followed by the literal value in parentheses): QOP ("javax.security.sasl.qop") A comma-separated, ordered list of quality-of-protection values that the client or server is willing to support. A qop value is one of "auth" authentication only "auth-int" authentication plus integrity protection "auth-conf" authentication plus integrity and confidentiality protection The order of the list specifies the preference order of the client or server. If this property is absent, the default qop is "auth". STRENGTH ("javax.security.sasl.strength") A comma-separated, ordered list of cipher strength values that the client or server is willing to support. A strength value is one of "low" "medium" "high" The order of the list specifies the preference order of the client or server. An implementation SHOULD allow configuration of the meaning of these values. An application MAY use the Java Cryptography Extension (JCE) with JCE-aware mechanisms to control the selection of cipher suites that match the strength values. If this property is absent, the default strength is "high,medium,low". SERVER_AUTH ("javax.security.sasl.server.authentication") "true" if server must authenticate to client; default "false" MAX_BUFFER ("javax.security.sasl.maxbuffer") Expires May 2001 [Page 14 JAVA SASL API November, 2000 Maximum size of receive buffer in bytes of SaslClient/SaslServer; the default is defined by the mechanism CLIENT_PKGS ("javax.security.sasl.client.pkgs") A |-separated list of package names to use when locating a SaslClientFactory SERVER_PKGS ("javax.security.sasl.server.pkgs") A |-separated list of package names to use when locating a SaslServerFactory The following properties are for defining a security policy for a server or client. Absence of the property is interpreted as "false". POLICY_NOPLAINTEXT ("javax.security.sasl.policy.noplaintext") "true" if mechanisms susceptible to simple plain passive attacks (e.g. "PLAIN") are not permitted "false" if such mechanisms are permitted POLICY_NOACTIVE ("javax.security.sasl.policy.noactive") "true" if mechanisms susceptible to active (non-dictionary) attacks are not permitted "false" if such mechanisms are permitted. POLICY_NODICTIONARY ("javax.security.sasl.policy.nodictionary") "true" if mechanisms susceptible to dictionary attacks are not permitted "false" if such mechanisms are permitted POLICY_NOANONYMOUS ("javax.security.sasl.policy.noanonymous") "true" if mechanisms that accept anonymous login are not permitted "false" if such mechanisms are permitted POLICY_FORWARD_SECRECY ("javax.security.sasl.policy.forward") "true" if mechanisms that forward secrecy between sessions are required "false" if such mechanisms are not required Expires May 2001 [Page 15 JAVA SASL API November, 2000 POLICY_PASS_CREDENTIALS ("javax.security.sasl.policy.credentials") "true" if mechanisms that pass client credentials are required "false" if such mechanisms are not required 4.2 public interface SaslClient An object implementing this interface can negotiate authentication using one of the IANA-registered mechanisms. 4.2.1 evaluateChallenge public byte[] evaluateChallenge(byte[] challenge) throws SaslException If a challenge is received from the server during the authentication process, this method is called to prepare an appropriate next response to submit to the server. The response is null if the challenge accompanied a "SUCCESS" status and the challenge only contains data for the client to update its state and no response needs to be sent to the server. The response is a zero-length byte array if the client is to send a response with no data. A SaslException is thrown if an error occurred while processing the challenge or generating a response. The challenge array may have zero length. Parameters are: challenge The non-null challenge received from the server. 4.2.2 hasInitialResponse public boolean hasInitialResponse() Determines whether this mechanism has an optional initial response. If true, caller should call evaluateChallenge() with an empty array to get the initial response. 4.2.3 isComplete public boolean isComplete() Expires May 2001 [Page 16 JAVA SASL API November, 2000 This method may be called at any time to determine if the authentication process is finished. Typically, the protocol driver will not do this until it has received something from the server which indicates (in a protocol-specific manner) that the process has completed. 4.2.4 getInputStream public InputStream getInputStream(InputStream source) throws IOException Retrieves an input stream for the session. It may return the same stream that is passed in, if no processing is to be done by the client. This method can be called only after the authentication exchange has completed (i.e., when isComplete() returns true); otherwise, a SaslException is thrown. The octets from the resulting input stream must have already gone through any integrity checking or other processing applied to the data from "source," as negotiated through the authentication session. From the mechanism provider's perspective, if a security layer has been negotiated, 'source' is expected to contain SASL buffers, as defined in RFC 2222. Four octets in network byte order in the front of each buffer identify the length of the buffer. The provider is responsible for performing any integrity checking or other processing on the buffer before returning the data as a stream of octets. For example, the protocol driver's request for a single octet from the stream might result in an entire SASL buffer being read and processed before that single octet can be returned. Parameters are: source The original input stream for reading from the server. 4.2.5 getOutputStream public OutputStream getOutputStream(OutputStream dest) throws IOException Retrieves an output stream for the session. It may return the same stream that is passed in, if no processing is to be done by the client. This method can be called only after the authentication exchange has completed (i.e., when isComplete() returns true); otherwise, a SaslException is thrown. When writing octets to the resulting stream, if a security layer has been negotiated, each piece of data written (by a single invocation Expires May 2001 [Page 17 JAVA SASL API November, 2000 of write()) will be encapsulated as a SASL buffer, as defined in RFC 2222, and then written to the underlying 'dest' output stream. From the mechanism provider's perspective, the data from each invocation of write() should be processed separately, resulting in the transmission of a single SASL buffer whose first four octets in network byte order denote the length of the buffer to the underlying 'dest' output stream. Parameters are: dest The original output stream for writing to the server. 4.2.6 getMechanismName public String getMechanismName() Reports the IANA-registered name of the mechanism used by this client, e.g. "GSSAPI" or "CRAM-MD5". 4.2.7 getNegotiatedQop public String getNegotiatedQop() throws SaslException Retrieves the negotiated quality of protection. This method can be called only after the authentication exchange has completed (i.e., when isComplete()returns true); otherwise, a SaslException is thrown. The method returns one of: "auth", "auth-int", "auth-conf", or null. null means quality of protection is not applicable to this mechanism. 4.2.8 getNegotiatedStrength public String getNegotiatedStrength() throws SaslException Retrieves the negotiated security strength. This method can be called only after the authentication exchange has completed (i.e., when isComplete()returns true); otherwise, a SaslException is thrown. The method returns one of: "low", "medium", "high", or null. null means security strength is not applicable to this mechanism. 4.3 public interface SaslClientFactory An object implementing this interface can provide a SaslClient. The implementation must be thread-safe and handle multiple simultaneous requests. It must also have a public constructor that accepts no argument. Expires May 2001 [Page 18 JAVA SASL API November, 2000 4.3.1 createSaslClient public SaslClient createSaslClient(String[] mechanisms, String authorizationID, String protocol, String serverName, Hashtable props, javax.security.auth.callback.CallbackHandler cbh) throws SaslException Creates a SaslClient using the parameters supplied. It returns null if no SaslClient can be created using the parameters supplied. Throws SaslException if it cannot create a SaslClient because of an error. Parameters are: mechanisms The non-null list of mechanism names to try. Each is the IANA-registered name of a SASL mechanism (e.g. "GSSAPI", "CRAM-MD5"). authorizationID The possibly null protocol-dependent identification to be used for authorization, e.g. user name or distinguished name. When the SASL authentication completes successfully, the entity named by authorizationId is granted access. If null, access is granted to a protocol-dependent default (for example, in LDAP this is the DN in the bind request). protocol The non-null string name of the protocol for which the authentication is being performed, e.g "pop", "ldap". serverName The non-null fully qualified host name of the server to authenticate to. props The possibly null properties to be used by the SASL mechanisms to configure the authentication exchange. See the Sasl class for a list of standard properties. Other, possibly mechanism- specific, properties can be included. Properties not relevant to the selected mechanism are ignored. cbh The possibly null callback handler to used by the SASL mechanisms to get further information from the application/library to complete the authentication. For example, a SASL mechanism might require the authentication ID, password and Expires May 2001 [Page 19 JAVA SASL API November, 2000 realm from the caller. The authentication ID is requested by using a NameCallback. The password is requested by using a PasswordCallback. The realm is requested by using a RealmChoiceCallback if there is a list of realms to choose from, and by using a RealmCallback if the realm must be entered. 4.3.2 getMechanismNames public String[] getMechanismNames(Hashtable props) Returns a non-null array of names of mechanisms supported by this factory that match the specified mechanism selection policies. Parameters are: props The possibly null properties to specify the security policy of the SASL mechanisms. For example, if props contains the Sasl.POLICY_NOPLAINTEXT property with the value "true", then the factory must not return any SASL mechanisms that are susceptible to simple plain passive attacks. See the Sasl class for a complete list of policy properties. Non-policy related properties, if present in props, are ignored. 4.4 public interface SaslServer An object implementing this interface can negotiate authentication using one of the IANA-registered mechanisms. 4.4.1 evaluateResponse public byte[] evaluateResponse(byte[] response) throws SaslException If a response is received from the client during the authentication process, this method is called to prepare an appropriate next challenge to submit to the client. The challenge is null if the authentication has succeeded and no more challenge data is to be sent to the client. It is non-null if the authentication must be continued by sending a challenge to the client, or if the authentication has succeeded but challenge data needs to be processed by the client. A SaslException is thrown if an error occurred while processing the response or generating a challenge. isComplete() should be called Expires May 2001 [Page 20 JAVA SASL API November, 2000 after each call to evaluateResponse(),to determine if any further response is needed from the client. The protocol driver will send an indication (in a protocol-specific manner) as to whether the authentication has succeeded, failed, or should be continued, and any accompanying challenge data. Parameters are: response Non-null response received from client. 4.4.2 isComplete public boolean isComplete() This method may be called at any time to determine if the authentication process is finished. This method is typically called after each invocation of evaluateResponse() to determine whether the authentication has completed successfully or should be continued. 4.4.3 getInputStream public InputStream getInputStream(InputStream source) throws IOException Retrieves an input stream for the session. It may return the same stream that is passed in, if no processing is to be done by the server. This method can be called only after the authentication exchange has completed (i.e., when isComplete() returns true); otherwise, a SaslException is thrown. The octets from the resulting input stream must have already gone through any integrity checking or other processing applied to the data from "source," as negotiated through the authentication session. From the mechanism provider's perspective, if a security layer has been negotiated, 'source' is expected to contain SASL buffers, as defined in RFC 2222. Four octets in network byte order in the front of each buffer identify the length of the buffer. The provider is responsible for performing any integrity checking or other processing on the buffer before returning the data as a stream of octets. For example, the protocol driver's request for a single octet from the stream might result in an entire SASL buffer being read and processed before that single octet can be returned. Parameters are: source The original input stream for reading from the client. Expires May 2001 [Page 21 JAVA SASL API November, 2000 4.4.4 getOutputStream public OutputStream getOutputStream(OutputStream dest) throws IOException Retrieves an output stream for the session. It may return the same stream that is passed in, if no processing is to be done by the server. This method can be called only after the authentication exchange has completed (i.e., when isComplete() returns true); otherwise, a SaslException is thrown. When writing octets to the resulting stream, if a security layer has been negotiated, each piece of data written (by a single invocation of write()) will be encapsulated as a SASL buffer, as defined in RFC 2222, and then written to the underlying 'dest' output stream. From the mechanism provider's perspective, the data from each invocation of write() should be processed separately, resulting in the transmission of a single SASL buffer whose first four octets in network byte order denote the length of the buffer to the underlying 'dest' output stream. Parameters are: dest The original output stream for writing to the client. 4.4.5 getMechanismName public String getMechanismName() Returns the non-null IANA-registered name of the mechanism used by this server, e.g. "GSSAPI" or "CRAM-MD5". 4.4.6 getAuthorizationID public String getAuthorizationID() throws SaslException Reports the authorization ID in effect for the client of this session. If null, a protocol-dependent default is assumed. Can only be called if isComplete() returns true; throws SaslException if called before authentication completes. 4.4.7 getNegotiatedQop public String getNegotiatedQop() throws SaslException Expires May 2001 [Page 22 JAVA SASL API November, 2000 Retrieves the negotiated quality of protection. This method can be called only after the authentication exchange has completed (i.e., when isComplete()returns true); otherwise, a SaslException is thrown. The method returns one of: "auth", "auth-int", "auth-conf", or null. null means quality of protection is not applicable to this mechanism. 4.4.8 getNegotiatedStrength public String getNegotiatedStrength() throws SaslException Retrieves the negotiated security strength. This method can be called only after the authentication exchange has completed (i.e., when isComplete()returns true); otherwise, a SaslException is thrown. The method returns one of: "low", "medium", "high", or null. null means security strength is not applicable to this mechanism. 4.5 public interface SaslServerFactory An object implementing this interface can provide a SaslServer. The mplementation must be thread-safe and handle multiple simultaneous requests. It must also have a public constructor that accepts no argument. 4.5.1 createSaslServer public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Hashtable props, javax.security.auth.callback.CallbackHandler cbh) throws SaslException Creates a SaslServer using the mechanism supplied. It returns null if no SaslServer can be created using the parameters supplied. Throws SaslException if it cannot create a SaslServer because of an error. Returns a possibly null SaslServer which supports the specified mechanism. If null, this factory cannot produce a SaslServer for the specified mechanism. Parameters are: mechanism The non-null IANA-registered name of a SASL mechanism (e.g. "GSSAPI", "CRAM-MD5"). Expires May 2001 [Page 23 JAVA SASL API November, 2000 protocol The non-null string name of the protocol for which the authentication is being performed, e.g "pop", "ldap". serverName The non-null fully qualified host name of the server. props The possibly null properties to be used by the SASL mechanisms to configure the authentication exchange. See the Sasl class for a list of standard properties. Other, possibly mechanism-specific, properties can be included. Properties not relevant to the selected mechanism are ignored. cbh The possibly null callback handler to used by the SASL mechanisms to get further information from the application/library to complete the authentication. For example, a SASL mechanism might require the authentication ID, password and realm from the caller. The authentication ID is requested by using a NameCallback. The password is requested by using a PasswordCallback. The realm is requested by using a RealmChoiceCallback if there is a list of realms to choose from, and by using a RealmCallback if the realm must be entered. 4.5.2 getMechanismNames public String[] getMechanismNames(Hashtable props) Returns a non-null array of names of mechanisms supported by this factory that match the specified mechanism selection policies. Parameters are: props The possibly null properties to specify the security policy of the SASL mechanisms. For example, if props contains the Sasl.POLICY_NOPLAINTEXT property with the value "true", then the factory must not return any SASL mechanisms that are susceptible to simple plain passive attacks. See the Sasl class for a complete list of policy properties. Non-policy related properties, if present in props, are ignored. 4.6 public class javax.security.sasl.AuthorizeCallback implements javax.security.auth.callback.Callback Expires May 2001 [Page 24 JAVA SASL API November, 2000 This callback is used by SaslServer to determine whether one entity (identified by an authenticated authentication id) can act on behalf of another entity (identified by an authorization id). 4.6.1 Constructors public AuthorizeCallback(String authnId, String authzId) Parameters are : authnId The authentication id authzId The authorization id 4.6.2 getAuthenticationId public String getAuthenticationId() Returns the authentication id to check. 4.6.3 getAuthorizationId public String getAuthorizationId() Returns the authorization id to check. 4.6.4 isAuthorized public boolean isAuthorized() Returns true if authorization is allowed, false otherwise. 4.6.5 setAuthorized public void setAuthorized(boolean ok) Sets whether authorization is allowed or not. Parameters are: ok true if authorization is to be allowed, false otherwise Expires May 2001 [Page 25 JAVA SASL API November, 2000 4.6.6 getAuthorizedId public String getAuthorizedId() Returns the id of the authorized user. If null, this means the authorization failed. 4.6.7 setAuthorizedId public void setAuthorizedId(String id) Sets the id of the authorized entity. The method is called by the handler only if the id is different from that returned by getAuthorizationId(). For example, the id might need to be canonicalized for the environment in which it will be used. Parameters are: id The id of the authorized user 4.7 public class javax.security.sasl.RealmCallback extends javax.security.auth.callback.TextInputCallback This callback is used by SaslClient and SaslServer to retrieve realm information. 4.7.1 Constructors public RealmCallback (String prompt) Constructs a RealmCallback with a prompt. public RealmCallback (String prompt, String defaultRealm) Constructs a RealmCallback with a prompt and a default realm. IllegalArgumentException is thrown if prompt is null or the empty string, or if defaultRealm is empty or null. Parameters are : prompt The non-null prompt to use to request the realm information defaultRealm The non-null default realm to use Expires May 2001 [Page 26 JAVA SASL API November, 2000 4.8 public class javax.security.sasl.RealmChoiceCallback extends javax.security.auth.callback.ChoiceCallback This callback is used by SaslClient and SaslServer to obtain one or more realms given a list of realm choices. 4.8.1 Constructors public RealmChoiceCallback (String prompt, String[]choices, int defaultChoice, boolean multipleSelectionsAllowed) Constructs a RealmChoiceCallback with a prompt, a list of choices and a default choice. IllegalArgumentException is thrown if prompt is null or the empty string, or if defaultRealm is empty or null. Parameters are : prompt The non-null prompt to use to request the realm choices The non-null list of realms to choose from defaultChoice The choice to use as the default choice when the list of choices is displayed. It is as an index into the choices array. multipleSelectionsAllowed Specifies whether or not multiple selections can be made from the list of choices. 4.9 public class SaslException extends IOException Exception thrown on errors and failures in authentication. 4.9.1 Constructors public SaslException() Constructs a new instance of SaslException. The root exception and the detailed message are null. public SaslException(String message) Expires May 2001 [Page 27 JAVA SASL API November, 2000 Constructs a default exception with a detailed message and no root exception. public SaslException(String messag, Throwable ex) Constructs a new instance of SaslException with a detailed message and a root exception. For example, a SaslException might result from a problem with the callback handler, which might throw a NoSuchCallbackException if it does not support the requested callback, or throw an IOException if it had problems obtaining data for the callback. The SaslException's root exception would then be the exception thrown by the callback handler. Parameters are: message Possibly null additional detail about the exception. ex A possibly null root exception that caused this exception. 4.9.2 getCause public Throwable getCause() Returns the possibly null root exception that caused this exception. 4.9.3 printStackTrace public void printStackTrace() Prints this exception's stack trace to System.err. If this exception has a root exception, the stack trace of the root exception is also printed to System.err. public void printStackTrace(PrintStream ps) Prints this exception's stack trace to a print stream. If this exception has a root exception, the stack trace of the root exception is also printed to the print stream. public void printStackTrace(PrintWriter pw) Expires May 2001 [Page 28 JAVA SASL API November, 2000 Prints this exception's stack trace to a print writer. If this exception has a root exception, the stack trace of the root exception is also printed to the print writer. Parameters are: ps The non-null print stream to which to print. pw The non-null print writer to which to print. 5. Security Considerations When SASL authentication is performed over unsecured connections, it is possible for an active attacker to spoof the server's protocol- specific indication that authentication is complete. Clients should protect against this attack by verifying the completion of authentication with the mechanism driver by calling the driver's isComplete() method. Additional security considerations are discussed in [SASL]. 6. Copyright Copyright (C) The Internet Society (2000). All Rights Reserved. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Expires May 2001 [Page 29 JAVA SASL API November, 2000 7. Bibliography [JAAS] Java Software, Sun Microsystems, Inc., "Java Authentication and Authorization Service, "http://java.sun.com/products/jaas", Jan 2000. [SASL] J. Myers, "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997 8. Authors' Addresses Rob Weltman +1 650 949-5279 robw@worldspot.com Rosanna Lee Sun Microsystems Mail Stop UCUP02-206 901 San Antonio Road Palo Alto, CA 94303 USA Email: rosanna.lee@eng.sun.com 9. Acknowledgements Rob Earhart, then of Carnegie Mellon University, was a coauthor of an earlier draft. Scott Seligman of Sun Microsystems, Inc. contributed to the architecture and API proposed in this document. Joe Salowey of WRQ, Anthony J. Nadalin of IBM, Bob Naugle of Bluestone, and Timothy Martin of Carnegie Mellon University contributed to the contents of this revision of the draft through participation in the expert group for Java Specification Request 28 - http://java.sun.com/aboutJava/communityprocess/jsr/jsr_028_sasl.html. 10. Changes from draft-weltman-java-sasl-03.txt Sasl Added getClientFactories() and getServerFactories(). Updated the list of standard properties. Added the use of the J2SE version 1.3 service provider guidelines for locating SaslClientFactory and SaslServerFactory implementations. SaslClient Added getNegotiatedQop() and getNegotiatedStrength() Expires May 2001 [Page 30 JAVA SASL API November, 2000 SaslClientFactory and SaslServerFactory getMechanismNames() takes a properties Hashtable as argument. SaslServer Added getNegotiatedQop() and getNegotiatedStrength() AuthorizeCallback New class to allow SaslServer to determine if an identity may be authorized as another identity. RealmCallback and RealmChoiceCallback New classes for obtaining realm information. SaslException getRootException changed to getCause, in anticipation of a new standard Java API for nested exceptions. Also, printStackTrace prints both the current and the nested exception. 11. Changes from draft-weltman-java-sasl-02.txt SecurityLayer The SecurityLayer interface was removed. SaslClient createInitialResponse() was removed. evaluateChallenge() accepts an empty challenge and can return an initial response. hasInitialResponse() was added to determine if the mechanism allows for an initial client response. SaslClient and SaslServer getSecurityLayer() was replaced with getInputStream() and getOutputStream(). Package names are |-delimited, not space-delimited, in the pkgs properties. Expires May 2001 [Page 31 JAVA SASL API November, 2000 Expires May 2001 [Page 32 JAVA SASL API November, 2000 12. Appendix A - Sample Java LDAP program using SASL /**************************************************************** It might look like this in LDAP. The Protocol Driver is implemented as part of the authenticate method of LDAPConnection. ****************************************************************/ public void authenticate( String dn, String[] mechs, Hashtable props, CallbackHandler cbh ) throws SaslException { // Create SASL client to use for authentication SaslClient saslClnt = Sasl.createSaslClient( mechs, dn, "ldap", getHost(), props, cbh); if (saslClnt == null) { throw new SaslException("SASL client not available"); } String mechName = saslClnt.getMechanismName(); // Get initial response, if any byte[] response = (saslClnt.hasInitialResponse() ? saslClnt.evaluateChallenge(new byte[0]) : null); // Create a bind request message, including the initial // response (if any), and send it off writeRequest( new LDAPSASLBindRequest( dn, mechName, response ) ); // Get the server challenge LDAPSASLBindResponse msg = (LDAPSASLBindResponse)readResponse(); // Authentication done? while (!saslClnt.isComplete() && (msg.getStatus() == LDAP_SASL_BIND_IN_PROGRESS || msg.getStatus() == LDAP_SUCCESS)) { // No, process challenge to get an appropriate next // response byte[] challenge = msg.getChallenge(); response = saslClnt.evaluateChallenge( challenge ); // May be a success message with no further response if ( msg.getStatus() == LDAP_SUCCESS) { if ( response != null ) { // Protocol error; supposed to be done already Expires May 2001 [Page 33 JAVA SASL API November, 2000 throw new SaslException("Protocol error in " + "SASL session"); } break; // done } // Wrap the response in another bind request and send // it off writeRequest( new LDAPSASLBindRequest( dn, mechName, response ) ); msg = (LDAPSASLBindResponse)readResponse(); } // Make sure authentication REALLY is complete if ( !saslClnt.isComplete() ) { // Authentication session hijacked! throw new SaslException( "SASL session hijacked!" ); } // Get input and output stream processes, if any InputStream is = saslClnt.getInputStream(getInputStream()); OutputStream os = saslClnt.getOutputStream(getOutputStream()); } Expires May 2001 [Page 34