Previous | Next | Trail Map | Tips for LDAP Users | Security

Callbacks for SASL Mechanisms

A SASL mechanism is always given the authorization id--that specified by the java.naming.security.sasl.authorizationId or Context.SECURITY_PRINCIPAL(in the API reference documentation)("java.naming.security.principal") environment property. All other input are supplied on-demand: upon the request of the mechanism.

By default, the LDAP provider supplies the authentication id and credentials by using the Context.SECURITY_PRINCIPAL(in the API reference documentation)("java.naming.security.principal") and Context.SECURITY_CREDENTIALS(in the API reference documentation)("java.naming.security.credentials") environment properties, respectively. If a SASL mechanism requires input other than these, or if you prefer to supply these input through a different means, you can define a callback handler object for the mechanism to use. To do this, you set the 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(in the API reference documentation) package from the Java Authentication and Authorization Service. The object contained in the "java.naming.security.sasl.callback" environment property must be of type CallbackHandler(in the API reference documentation) . When a SASL mechanism requires input, it invokes CallbackHandler.handle()(in the API reference documentation) , and supplies the list of callbacks it needs to get that input. A mechanism must use the NameCallback(in the API reference documentation)when asking for the authentication id, and use the PasswordCallback(in the API reference documentation)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 Callback(in the API reference documentation) interface. 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.

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 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_CREDENTIALS environment property. The CRAM-MD5 mechanism needs the following input: the authorization id, and the password. The authorization id is obtained from the Context.SECURITY_PRINCIPAL property. All other input required by the CRAM-MD5 mechanism is supplied by SampleCallbackHandler.
// Set up environment for creating 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=JNDITutorial");

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

// Specify bind DN as C. User
env.put(Context.SECURITY_PRINCIPAL,
    "cn=C. User, ou=NewHires, o=JNDITutorial");

// If authorization id different, set using 
// java.naming.security.sasl.authorizationId property
// env.put("java.naming.security.sasl.authorizationId", "u:cuser");

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

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


Previous | Next | Trail Map | Tips for LDAP Users | Security