Security

 


Callbacks for SASL Mechanisms

A SASL mechanism is always given the authorization id (that specified by the "java.naming.security.sasl.authorizationId") environment property. All other input is supplied on-demand, that is, on request of the mechanism.

By default, the LDAP provider supplies the authentication id and credentials by using, respectively, the Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS environment properties. If a SASL mechanism requires input other than these, or if you prefer to supply the input through a different means, then you can define a callback handler object for the mechanism to use. To do this, you set the "java.naming.security.sasl.callback" environment property to the callback handler object, as explained next.

 

 

Callback Handler

The LDAP provider uses the javax.security.auth.callback package from the Java Authentication and Authorization Service. The object contained in the "java.naming.security.sasl.callback" environment property must be of type javax.security.auth.callback.CallbackHandler . When a SASL mechanism requires input, it invokes javax.security.auth.callback.CallbackHandler.handle(), and supplies the list of callbacks that it needs in order to get that input. A mechanism must use the javax.security.auth.callback.NameCallback when asking for the authentication id and use the javax.security.auth.callback.PasswordCallback when asking for the authentication credentials. To obtain other input, the mechanism will use one of the callbacks defined in the javax.security.auth.callback package or any other callback that implements the javax.security.auth.callback.Callbackinterface.

The callback handler must be able to handle the type of callback requested by a mechanism, so the application that creates/uses the callback handler must have some knowledge about what the mechanism requires. For example, in addition to the NameCallback and PasswordCallback, the Digest-MD5 mechanism requires also callbacks to get the realm. The realm is obtained by using either a javax.security.auth.callback.TextInputCallback or javax.security.auth.callback.ChoiceCallback.

Here is an example of a callback handler that handles NameCallback and PasswordCallback by reading the data from Standard Input.

public class SampleCallbackHandler implements CallbackHandler {
    public void handle(Callback[] callbacks) 
	throws java.io.IOException, UnsupportedCallbackException {
	    for (int i = 0; i < callbacks.length; i++) {
		if (callbacks[i] instanceof NameCallback) {
		    NameCallback cb = (NameCallback)callbacks[i];
		    cb.setName(getInput(cb.getPrompt()));

		} else if (callbacks[i] instanceof PasswordCallback) {
		    PasswordCallback cb = (PasswordCallback)callbacks[i];

		    String pw = getInput(cb.getPrompt());
		    char[] passwd = new char[pw.length()];
		    pw.getChars(0, passwd.length, passwd, 0);

		    cb.setPassword(passwd);
		} else {
		    throw new UnsupportedCallbackException(callbacks[i]);
		}
	    }
    }

    /**
     * A reader from Standard Input. In real world apps, this would
     * typically be a TextComponent or similar widget.
     */
    private String getInput(String prompt) throws IOException {
	System.out.print(prompt);
	BufferedReader in = new BufferedReader(
	    new InputStreamReader(System.in));
	return in.readLine();
    }
}	

 

 

CRAM-MD5 by Using a Callback Handler

Here's a modified version of the CRAM-MD5 example that gets its password by using a callback handler instead the Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS environment properties. The CRAM-MD5 mechanism needs the authentication id and the password as input. These are supplied by SampleCallbackHandler.
// Set up the environment for creating the initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDIDocs");

env.put(Context.SECURITY_AUTHENTICATION, "CRAM-MD5");

// Specify the callback to use for fetching the authentication id/password
env.put("java.naming.security.sasl.callback", new SampleCallbackHandler());

// Create the initial context
DirContext ctx = new InitialDirContext(env);

// ... do something useful with ctx