| 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.Callback` 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. 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=JNDITutorial");

> >     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

| Security