Delphi でも LDAP
| 
 | 
	軽井沢、白糸の滝。夏休み最後の日曜日、案外犬を連れた人が多かった。 | 
Novell eDirectory へのLDAP認証だが、Delphiでも試してみた。クグってみたところ、SynapseというDelphiで使えるTCP/IPツールにLDAPクライアントが見つかった。Synapseは以前にも別の目的で試したことがあったが、LDAPは今回が初めてだ。
LDAPサーバーへの接続は簡単だ。今回は、ユーザーIDとパスワードで認証し、OKならアトリビュート値を返すような関数にしてみた。
LdapSeek というユニット仕立てだ。
{*
 * [Ararat Synapse] を使用して LDAP(eDirectory) にアクセスする
 *                                    Copyright(c) flyman
 * Version 0.10 2008/09/10
 *}
	
unit LdapSeek;
	
interface
	
uses
  Classes, Windows, SysUtils, ldapsend;
	
Function LdapAuth(userID, password : String; AttrList : TStringList) : Boolean;
var
  Host : String;
  Port : String;
  Version : Integer;
  Search : String;
	
implementation
	
{指定ユーザー、パスワードの認証
 認証に成功すると、AttrListにアトリビュート値が入る
 認証に失敗すると False を返す}
Function LdapAuth(userID, password : String; AttrList : TStringList) : Boolean;
var
  ldap: TLDAPsend;
  al,gl : TStringList;
begin
  Result := True;
  AttrList.Clear;
	
  ldap:= TLDAPsend.Create;
  al := TStringList.Create;
  gl := TStringList.Create;
  try
    ldap.TargetHost := Host;
    ldap.TargetPort := Port;
    ldap.Version := Version;
	
    if ldap.Login then begin
      ldap.UserName := 'cn=' + userID + Search;
      ldap.Password := password;
      if ldap.Bind then begin
        {検索したいアトリビュート名のリストを作る}
        al.Append('dn');
        al.Append('passwordMinimumLength');
        al.Append('loginDisabled');
        al.Append('nLSLicensesUsed');
        al.Append('sn');
        al.Append('nRDRegistryData');
        al.Append('loginMaximumSimultaneous');
        al.Append('passwordRequired');
        al.Append('Language');
        al.Append('passwordAllowChange');
        al.Append('objectClass');
        al.Append('uid');
        al.Append('groupMembership');
        al.Append('loginTime');
        al.Append('cn');
        al.Append('securityEquals');
        al.Append('ACL');
        al.Append('nRDRegistryIndex');
        al.Append('networkAddress');
        al.Append('fullName');
        al.Append('ndsHomeDirectory');
	
        ldap.Search('cn=' + userID + Search, False, '(objectclass=*)', al);
        gl.Text := LDAPResultdump(ldap.SearchResult);
	
        AttrList.AddStrings(gl);
      end else begin
        AttrList.Add('*** Bind Failure ***');
        Result := False;
      end;
      ldap.Logout;
    end else begin
      AttrList.Add('*** Login Failure ***');
      Result := False;
    end;
  finally
    ldap.Free;
    al.Free;
    gl.Free;
  end;
end;
	
end.
	こんな感じだ。なんのことはない、eDirectoryだからといって、特段変わったテクニックは必要ない。
認証が必要なければ ldap.UserName と ldap.Password をブランクにしておけば Anonymusで接続してくれる。その上で ldap.Search すれば必要なアトリビュート値を取り出すことが可能だ。
この関数は、Formのボタン押下イベントから、以下のようにして呼び出す。
uses LdapSeek;
	
{$R *.dfm}
	
procedure TForm1.Button1Click(Sender: TObject);
var
  AttrList : TStringList;
begin
  Memo1.Lines.Clear;
  LdapSeek.Host := '10.9.225.214';
  LdapSeek.Port := '389';
  LdapSeek.Version := 3;
  LdapSeek.Search := ',ou=users,o=flynet';
  Screen.Cursor := crHourGlass;
  AttrList := TStringList.Create;
  try
    // ユーザーID、パスワード、アトリビュート値の入れ物を渡す
    if LdapAuth(EditUSER.Text, EditPASS.Text, AttrList) then begin
      // ここに認証成功時の処理を書く
    end else begin
      // 認証失敗 !!
    end;
    Memo1.Lines.AddStrings(AttrList);
  finally
    AttrList.Free;
    Screen.Cursor := crDefault;
  end;
end;
	――サンプル用コードとしてはちょっと適当じゃないかも知れないが、まあ、こんな感じで作ってしまったので勘弁して欲しい。
* LdapSeek の uses に余計なモノが入っている。オリジナルでは他にも関数やプロシージャを入れているので、それ用のユニットも読み込ませているのだ(どれが不要だか判らなくなったので、そのまま残してある)。
LDAPサーバーに認証要求を投げたり、PCのログインユーザーの所属するグループ一覧を取得したり、色々な用途が思い浮かぶ。
私はまだ試していないが、LDAPサーバーの値(LDIF)を書き換えることも可能なようだ。
今回は Novell eDirectory が相手だったが、Active Directory でも、OpenLdap でも、基本は同じみたいなので勤務先のディレクトリサービスが変更になっても大丈夫、使えるワザである。

