JavaからAcitiveDorectoryにアクセス

業務アプリで、JavaからAcitiveDirectory(Win2000)にアクセスしてパスワードの
変更をしなくてはならなくなった。

とりあえず、Google先生に尋ねてみる。
ここに行き着く。
(2011/05/28現在 見れなくなっている様子)
javax.naming.*、javax.naming.directory.*のクラスを使用すれば可能。

JNDIでActiveDirectoryに接続。
パスワードの変更は、LDAPS通信が必要。
ActiveDirectoryに証明局の導入。
アプリ側で証明書の取り込みが必要とのこと。

(source_code)

import java.io.UnsupportedEncodingException;
import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;

public class AdDaoImpl implements AdDao{
	// ★★ LDAP接続環境を保存するコレクション
	Hashtable<String, String> env = new Hashtable<String, String>();
	// 外部設定ファイル読み込み用モデル
	AdConfiguration config = new AdConfiguration();

	@Override
	public boolean auth(String empno, String psword, String uri) throws Exception {
		// ★★ LDAP接続環境を設定するメソッドの呼び出し
		setEnv(uri);
		// 接続ユーザIDを設定します
		env.put(Context.SECURITY_PRINCIPAL, empno ",DC=XXXX,DC=local");
		// 接続ユーザのパスワードを設定します。
		env.put(Context.SECURITY_CREDENTIALS, psword);
		// 	★★ LDAP接続環境を設定します End
		// 設定した環境を元にコンテキストを生成します
		try {
			InitialDirContext context = new InitialDirContext(env);
			context.close();
//			System.out.println("☆彡認証に成功しました");
			return true;
		} catch(AuthenticationException ae) {
//			System.out.println("× 認証エラーです");
			return false;
		} catch(Exception e) {
//			System.out.println("× その他エラーです");
//			System.out.println(e);
			return false;
		}
	}

	@Override
	public void update(String empno, String newpassword, String uri) throws Exception {
		// ★★ LDAP接続環境を設定するメソッドの呼び出し
		setEnv(uri);
		// 設定した環境を元にコンテキストを生成します
		InitialDirContext context = new InitialDirContext(env);
        // 変更対象属性情報を生成します。    
		ModificationItem[] modificationItem = new ModificationItem[1];
      	// ここでは第二引数で指定したパスワードに変更します
		try {
			String newQuotedPassword ="\"" + newpassword + "\"";
			byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
			modificationItem[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
					new BasicAttribute("unicodePwd",newUnicodePassword));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
        // 第一引数で指定したエントリに対して変更を実施します
		context.modifyAttributes(empno, modificationItem);		
	}

	@Override
	public boolean exist(String e32empno, String uri) throws Exception {
		// ★★ LDAP接続環境を設定するメソッドの呼び出し
		setEnv(uri);
		System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
		try{
			// 設定した環境を元にコンテキストを生成します
			InitialDirContext context = new InitialDirContext(env);
			// コンテキストを使用して対象の検索を行います
			context.getAttributes(empno);
		} catch(NamingException e) {
			throw new Exception();
		}
		return true;
	}

	private void setEnv(String uri) throws Exception{
		// ★★ LDAP接続環境を設定します Start
		// Contextファクトリを設定
		env.put(Context.INITIAL_CONTEXT_FACTORY, 
				"com.sun.jndi.ldap.LdapCtxFactory");
		// 接続先URL(ホスト,ポート番号,基本DN)を設定
		env.put(Context.PROVIDER_URL,"ldaps://XXXXX.XXXXX.local:636/DC=XXXXX,DC=local");
		// セキュリティレベルを設定します
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		// 接続ユーザIDを設定します
		env.put(Context.SECURITY_PRINCIPAL, "CN=administrator,OU=Not-Policy,DC=XXXXX,DC=local");
		// 接続ユーザのパスワードを設定します。
		env.put(Context.SECURITY_CREDENTIALS, "XXXXXX");
		// SSL 通信を行う設定
		env.put(Context.SECURITY_PROTOCOL, "ssl");
		// サービスプロバイダによって検出された照会を無視
		env.put(Context.REFERRAL, "ignore");
		//LDAPへのコネクションプーリングの使用
	    env.put("com.sun.jndi.ldap.connect.pool", "true");
		// 	★★ LDAP接続環境を設定します End
		// 使用するkeystore を指定する
		String keystore = "C:\\Program Files\\Java\\jre6\\lib\\security\\cacerts";
		// 既定のSSL の信頼するkeystore を設定する
		System.setProperty("javax.net.ssl.trustStore", keystore);		
	}

}