JavaはJAASを使ってLDAP認証を行うことができる。Java 6になってLDAP認証周りが強化されたので確認してみた。

まず、jaas.configファイルを作成。

LDAPTest {
	com.sun.security.auth.module.LdapLoginModule REQUIRED
	userProvider="ldap://ldap-server/ou=People,dc=kurusugawa,dc=jp"
	userFilter="(&(uid={USERNAME})(objectClass=top)(objectClass=account)(objectClass=posixAccount))"
	useSSL=false
	debug=true
	;
};

com.sun.security.auth.module.LdapLoginModuleの利用がミソです。
userProvider, userFilter, useSSL 等は環境に合わせて適宜書き換え(ry

このファイルをJAASのクラスライブラリに認識させるにはVM引数の指定が必要。

-Djava.security.auth.login.config=jaas.config

あとは、javax.security.auth.login.LoginContextをnewしてloginメソッドを呼び出せば、認証が完了。

package jp.kurusugawa.benchmark.ldap;

import java.io.IOException;
import java.security.Principal;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import org.junit.Test;

public class LDAPTest {
  @Test
  public void testLoginContextConnection() throws LoginException {
    Subject tSubject = new Subject();
    LoginContext tLoginContext = new LoginContext("LDAPTest", tSubject, new CallbackHandler() {
      public void handle(Callback[] aCallbacks) throws IOException, UnsupportedCallbackException {
        for (Callback tCallback : aCallbacks) {
          if (tCallback instanceof NameCallback) {
            NameCallback tNameCallback = (NameCallback) tCallback;
            tNameCallback.setName("scott");
          } else if (tCallback instanceof PasswordCallback) {
            PasswordCallback tPasswordCallback = (PasswordCallback) tCallback;
            tPasswordCallback.setPassword("tiger".toCharArray());
          } else {
            throw new UnsupportedCallbackException(tCallback, "Unrecognized callback");
          }
        }
      }
    });
    tLoginContext.login();
    for (Principal tPrincipal : tSubject.getPrincipals()) {
      System.out.println(tPrincipal.getClass().getCanonicalName() + ", " + tPrincipal.toString());
    }
  }
}

標準出力結果

debug=trueになってるので、色々出ます。

    [LdapLoginModule] search-first mode; SSL disabled
    [LdapLoginModule] user provider: ldap://ldap-server/ou=People,dc=kurusugawa,dc=jp
    [LdapLoginModule] searching for entry belonging to user: scott
    [LdapLoginModule] found entry: uid=scott,ou=People,dc=kurusugawa,dc=jp
    [LdapLoginModule] attempting to authenticate user: scott
    [LdapLoginModule] authentication succeeded
    [LdapLoginModule] added LdapPrincipal "uid=scott,ou=People,dc=kurusugawa,dc=jp" to Subject
    [LdapLoginModule] added UserPrincipal "scott" to Subject
com.sun.security.auth.LdapPrincipal, uid=scott,ou=People,dc=kurusugawa,dc=jp
com.sun.security.auth.UserPrincipal, scott

{SSHA}, {CRYPT}, {MD5}でハッシュされたものは問題なく認証できることを確認。
以上

参考

「JAAS 認証」