はじめに
企業内などで複数のシステムが開発されると、ユーザーはシステムごとにユーザーID・パスワードを使い分けるなどの不便さを強いられることがしばしばあります。このようなわずらわしさを解消するために、シングルサインオンという仕組みへの取り組みが企業などではじまっています。シングルサインオンとは、ユーザが一度認証を受けるだけで、許可されているすべての機能を利用できるようになるシステムのことをいいます。このシングルサインオンにより、安全な認証機能の実現、システム管理者やアプリケーション開発者の負担軽減などの効果も期待できます。
シングルサインオンを実現する際は、ユーザー認証情報を「ディレクトリサービス」という仕組みで統合的に管理するという手法が一般的に採用されます。「ディレクトリサービス」とは、ユーザー情報などのネットワーク上の資源と、その属性とを保存し、検索できるようにしたシステムのことです。このディレクトリサービスにアクセスするためのプロトコルとして最も使用されるのがLDAP(Lightweight Directory Access Protcol)です。
シングルサインオンが普及していく中で、エンジニアもJavaからディレクトリサービスにアクセスし、データを操作するプログラムを開発する機会が増えてくると思われます。本稿では、そのようなエンジニアの最初の一歩として参考となる簡単なWebアプリケーションを紹介します。
対象読者
Javaでプログラミングしたことがある方を対象とします。
必要な環境
本稿ではLDAPサーバーとして、OpenLDAP(バージョン2.2.13)を使用します。OpenLDAPのインストール方法については、参考資料などを参照してください。
JNDI(Java Naming and Directory Interface)
Javaでは、ディレクトリサービスへアクセスするためのAPIとして、標準でJNDI(Java Naming and Directory Interface)が用意されています。JNDIは、ネーミングサービスやディレクトリサービスにアクセスするための汎用的なAPIです。ネーミングサービスとは、文字列で表現される名前と特定のオブジェクトとを関連づけ、名前を指定することにより対応するオブジェクトを取得することができるサービスのことです。ディレクトリサービスは上記で述べたとおりです。
LDAPについて
サンプルアプリケーションについて説明する前に、LDAPについての基本的な事項について簡単に説明します。
LDAPの概念
以下の図にLDAPの概念を示します。LDAPは、DIT(Direcotry Information Tree:ディレクトリ情報ツリー)という階層ツリー内に、エントリーが配置されるという構造になっています。
上記の図に登場した用語を以下の表にまとめます。
用語 | 説明 |
エントリ | 実世界にあるオブジェクトをコンピュータ上のLDAPの中に対応づけしたもの。ディレクトリサービスの階層ツリー(DIT)上に配置される。 |
DIT | エントリの階層関係をツリーで表したもの。Directory Information Tree(ディレクトリ情報ツリー)の略。 |
DN | ディレクトリ情報ツリー上で、エントリを一意に識別するための名前のこと。LDAPでは「属性名=属性値,属性名=属性値・・」の書式であらわした文字列。文字列の右から、ツリーのルートに近い属性となる。 |
ルートサフィックス | DITの最上位のエントリにつける名前。上記の図では「dc=example,dc=com」 |
またDIT上に配置されるエントリは下図のように複数の属性をもち、その属性は複数の値を持つことができます。
最後に、以下の表にLDAPで標準的に使用される代表的な属性型を列挙します。
属性名 | 説明 |
dc | ドメイン名の一部など(Domain Componentの略) |
ou | 組織の部署など(Organization Unitの略) |
cn | 一般名(Common Nameの略)。様々なオブジェクトの名前を表すために汎用的に使用される。 |
sn | 名字(Surname) |
c | 国の名前(Country。DNSで使われる2文字の国名などを使う) |
o | 組織の名前など(Organization) |
l | 地域の名前(Locality) |
st | 州、都道府県名など(State) |
LDAPの操作モデル
以下の表に、LDAPクライアントがLDAPサーバーに対して発行できる操作を示します。本稿のサンプルでは、バインド、検索、追加、更新、削除、アンバインドを使用します。
操作 | 内容 |
バインド | LDAPセッションの開始 |
比較 | 特定のエントリ中の属性値の比較 |
検索 | 検索条件(フィルター)に一致するエントリを検索 |
追加 | 新規エントリの追加 |
更新 | 特定のエントリの属性値の追加、更新、削除 |
削除 | 特定のエントリの削除 |
改名 | 特定のエントリのDN(識別名)の変更 |
放棄 | 要求中のLDAP操作の放棄 |
アンバインド | LDAPセッションの終了 |
サンプルアプリケーション概要
機能概要/画面遷移
ディレクトリサーバーで管理されている社員データを、JavaのWebアプリケーションから新規登録・検索・更新・削除(CRUD)するWebアプリケーションです。なおサンプルでは、StrutsなどのWebアプリケーションフレームワークは使用していません。画面遷移を下図に示します。
サンプルのデータ構造
本稿のサンプルでは、「example.com」ドメインの「Users」グループに属する社員をデータ操作の対象とします。以下の図にLDAPブラウザで、サンプルのディレクトリーツリーを参照した画面を示します。下図のLDAPブラウザは、LDAP Browser/Editorを使用しています。インストール方法・使用方法は、参考資料などを参照してください。
図中の「dc=example,dc=com」は、example.comをLDAPのDN形式で表した文字列です。またツリー上では、example.comの下にUsersという組織(ou:Organization Unit)が所属しています。そのUsersの中に、社員ID(cn:Common Name)が00001と00002の社員が所属しています。
サーバー・データの準備
サンプルアプリケーションを動作させるために、LDAPサーバー上にデータを準備します。
サフィックス・管理者・管理者パスワードの設定
「/etc/openldap/slapd.conf」ファイルにLDAPサーバーの基本設定を記述します。
suffix "dc=example,dc=com" rootdn "cn=Manager,dc=example,dc=com" rootpw secret
以下の表に「slapd.conf」に設定したディレクティブをまとめます。
ディレクティブ | 値 | 説明 |
suffix | dc=example,dc=com | ルートサフィックス |
rootdn | cn=Manager,dc=example,dc=com | 管理者のDN(Distinguished Name:識別名) |
rootpw | secret | 管理者のパスワード |
rootpw
ディレクティブの平文での指定は推奨されません。通常はハッシュ化した値を設定します。ハッシュ化された値を取得するには、openldap付属のslappasswdコマンドを使用しますが、詳細は参考資料などを参照してください。階層ツリーの作成
社員データを格納するためのDIT(ディレクトリ情報ツリー)を作成します。階層構造は、ルートから近い順にcom-example-Usersとなります。
- LDIFファイルの作成
- LDIFによるデータの投入
dn: dc=example,dc=com objectClass: dcObject objectClass: organization o: example dc: example dn: ou=Users,dc=example,dc=com objectClass: top objectClass: organizationalUnit ou: Users
ldapadd -x -h localhost -D cn=manager,dc=example, dc=com -f sample.ldif -W