OpenLDAP のインストール †
インストール †
# yum -y install openldap-servers
# yum -y install openldap-clients
# /usr/sbin/slapd -V
@(#) $OpenLDAP: slapd 2.4.23 (May 25 2011 12:00:47) $
mockbuild@sl6.fnal.gov:/builddir/build/BUILD/openldap-2.4.23/openldap-2.4.23/build-servers/servers/slapd
初期データベース設定 †
- 2.2 までは、slapd.conf に設定内容を記入していたが 2.3 からは LDAP データベースに設定内容を保存する(Configuration Backend)
The older style slapd.conf(5) file is still supported, but its use is deprecated and support for it will be withdrawn in a future OpenLDAP release. Configuring slapd(8) via slapd.conf(5) is described in the next chapter. (OpenLDAP Software 2.4 Administrator's Guide 5. Configuring slapd)
- /etc/openldap/slapd.d 以下が LDAP の設定情報のデータベース。
- ひな形のデータベースを変更して目的のものを作るのは大変なので、旧来の slapd.conf からの移行ツールを使うのが便利
- まずは、パスワードの生成*1
# slappasswd -s passwd
{SSHA}UeZXLh4LqdPJaKggIyadtl/7JxnWzEBP
- slapd.conf を作成する
雛形 : /usr/share/openldap-servers/slapd.conf.obsolete
# cat ~/myslapd.conf
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/duaconf.schema
include /etc/openldap/schema/dyngroup.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/collective.schema
allow bind_anon_cred
allow bind_anon_dn
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
TLSCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
TLSCertificateFile /etc/pki/tls/certs/slapd.pem
TLSCertificateKeyFile /etc/pki/tls/certs/slapd.pem
access to attrs=userPassword
by dn="cn=manager,dc=example,dc=com" write
by self write
by anonymous auth
by * none
access to *
by dn="cn=manager,dc=example,dc=com" =rwcsx
by self =rwcsx
by * read
database bdb
suffix "dc=example,dc=com"
rootdn "cn=manager,dc=example,dc=com"
rootpw {SSHA}UeZXLh4LqdPJaKggIyadtl/7JxnWzEBP
directory /var/lib/ldap
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
database monitor
include | core.schema | OpenLDAP Core |
cosine.schema | X500 (Directory Access Protocol) |
inetorgpersion.schema | 組織構造 |
nis.schema | ユーザ・パスワード |
allow | bind_anon_cred | ユーザ名(DN)が指定されていて未認証のリクエストを受け付ける |
bind_anon_dn | ユーザ名(DN)が指定されていないリクエストを受け付ける |
update_anon | 匿名ユーザからの更新リクエストを受け付ける(普通は設定しない) |
access to attrs=userPassword | anonymous(匿名) | 照合のみ |
self(自分) | 書き込み可能 |
manager(管理者) | 書き込み可能 |
*(その他) | アクセス権なし |
accss to * | self =rwcsx | パスワード以外の自分のエントリについては、読み・書き・比較・検索・照合可能 |
manager(管理者) | パスワード以外の項目について読・書・比較・検索・照合可能 |
*(その他) | 読み込みのみ |
pidfile | slapd の pid |
argsfile | slapd の 引数 |
database | bdb(Oracle Berkeley DBが定石) |
suffix | トップレベルの組織 |
rootdn | 管理者名 |
rootpw | 管理者パスワード |
directory | データベース格納ディレクトリ |
index | eq | 完全一致検索のためのインデックスを作成する |
database monitor | --enable-monitor=yes でコンパイルしているとき、これを設定しないと "bdb_monitor_db_open: monitoring disabled; configure monitor database to enable" というエラーが出る。 |
- このほかに、メモリキャッシュサイズの cachesize、idlcachesize なんかが設定できるけど、デフォルト設定の 1000 件で問題ないでしょう
- 必要があれば、access の by 条件に peername.ip=127.0.0.1 (同じマシンからの場合) をつかうのはいい考えかも
- 設定DBの作成
# mv /etc/openldap/slapd.d/ /etc/openldap/slapd.d.original
# mkdir /etc/openldap/slapd.d/
# mv /var/lib/ldap /var/lib/ldap.original
# mkdir /var/lib/ldap/
# vi /var/lib/ldap/DB_CONFIG
set_cachesize 0 268435456 1
set_lg_regionmax 262144
set_lg_bsize 2097152
# chown -R ldap:ldap /etc/openldap/slapd.d
# chown -R ldap:ldap /var/lib/ldap
# service slapd start
slapd を起動中: [ OK ]
# service slapd stop
slapd を停止中: [ OK ]
# slaptest -f ~/myslapd.conf -F /etc/openldap/slapd.d
config file testing succeeded
いったん起動して、停止せずに slaptest で DB を作ろうとすると
bdb_db_open: database "dc=example,dc=com": db_open(/var/lib/ldap/id2entry.bdb) failed: No such file or directory (2).
backend_startup_one (type=bdb, suffix="dc=example,dc=com"): bi_db_open failed! (2)
slap_startup failed (test would succeed using the -u switch)
というエラーが出る
起動設定 †
# /sbin/chkconfig slapd --level 35 on
# /sbin/chkconfig --list | grep slapd
slapd 0:off 1:off 2:off 3:on 4:off 5:on 6:off
起動 †
# /etc/rc.d/init.d/slapd start
slapd を起動中: [ OK ]
LDAPS (TLS) の有効化 †
- /etc/rc.d/init.d/slapd で、SLAPD_LDAPS を yes して再起動
29 # Define default values of options allowed in /etc/sysconfig/ldap
30 SLAPD_LDAP="yes"
31 SLAPD_LDAPI="no"
32 #SLAPD_LDAPS="no"
33 SLAPD_LDAPS="yes"
34 SLAPD_URLS=""
35 SLAPD_SHUTDOWN_TIMEOUT=3
36 # OPTIONS, SLAPD_OPTIONS and KTB5_KTNAME are not defined
# service slapd restart
slapd を停止中: [ OK ]
slapd を起動中: [ OK ]
(なんかldaps : 639 が待ち受けにならないぞ・・・)
ユーザ登録 †
- LDAPの構造はこうしないとだめ
トップレベル
┃
┣ LDAP管理者
┃
┣ 組織と人間のツリー
┃
┗ 権限管理のためのグループ
┃
┣ 特権グループ (ユーザ名 (DN) ×n を含む)
┃
┗ 一般グループ (ユーザ名 (DN) ×n を含む)
- test.ldif
# トップレベル
dn: dc=example,dc=com
objectClass: organization
objectClass: dcObject
objectClass: top
dc: example
o: example
# LDAP管理者
dn: cn=manager,dc=example,dc=com
objectClass: organizationalRole
cn: manager
# 営業部門
dn: ou=marketing,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: marketing
# 一郎
dn: cn=ichiro,ou=marketing,dc=example,dc=com
objectClass: inetOrgPerson
cn: ichiro
sn: ichiro
uid: ichiro
userPassword: ichiro123
# 製造部門
dn: ou=producting,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: producting
# 次郎
dn: cn=jiro,ou=producting,dc=example,dc=com
objectClass: inetOrgPerson
cn: jiro
sn: jiro
uid: jiro
userPassword: jiro123
# 権限管理用の ou
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: Groups
# 幹部社員グループ
dn: cn=executive,ou=Groups,dc=example,dc=com
objectClass: groupOfUniqueNames
objectClass: top
cn: executive
uniqueMember: cn=ichiro,ou=marketing,dc=example,dc=com
# 一般従業員グループ
dn: cn=employee,ou=Groups,dc=example,dc=com
objectClass: groupOfUniqueNames
objectClass: top
cn: employee
uniqueMember: cn=jiro,ou=producting,dc=example,dc=com
- 実行
# /usr/bin/ldapadd -x -D"cn=manager,dc=example,dc=com" -w passwd -c -a -f ~/test.ldif
adding new entry "dc=example,dc=com"
adding new entry "cn=manager,dc=example,dc=com"
adding new entry "ou=marketing,dc=example,dc=com"
adding new entry "cn=ichiro,ou=marketing,dc=example,dc=com"
adding new entry "ou=producting,dc=example,dc=com"
adding new entry "cn=jiro,ou=producting,dc=example,dc=com"
adding new entry "ou=Groups,dc=example,dc=com"
adding new entry "cn=executive,ou=Groups,dc=example,dc=com"
adding new entry "cn=employee,ou=Groups,dc=example,dc=com"
- Apache Direcotry Studio で見ると、こんな感じになった
- (参考) inetOrgPerson? スキーマの中でよく使われる属性
uid | ユーザID |
userPassword | パスワード |
cn(必須) | 一般名称 |
sn(必須) | 姓 (Sur Name) |
givenName | 名 |
mail | メール |
ou | 所属組織(属しているLDAPの枝名) |
title | 所属組織名 |
glassfish の LDAP Realm の設定 †
- glassfish 管理コンソールの [設定]-[server config]-[セキュリティ]-[レルム] で LDAP Realm を追加する
- 設定項目
| JAASコンテキスト (jaas-context) | "ldapRealm" にする |
| ディレクトリ (directory) | LDAP サーバの URL |
| 基本DN (base-dn) | ルートノード |
| グループ割り当て (group-base-dn) | 権限グループのルートノード |
OPTION | search-bind-dn | LDAP管理ユーザのDN (LDAP に anonymous アクセスができないとき) |
OPTION | search-bind-password | LDAP管理ユーザのパスアワード |
OPTION | group-target | グループ名として利用するノードの属性(省略時 CN) |
OPTION | search-filter | ユーザ情報取得する際のクエリ(省略時 uid=%s、%s は subject name) |
OPTION | group-search-filter | グループ名を取得する際のクエリ(省略時 uniquemember=%d、%d は DN) |
- 管理コンソールの GUI にバグがあるので、結局 domain.xml を直接いじることになるかも・・・
→ Glassfish のディレクトリ構成
Webアプリケーションからの利用方法 †
- こんなアプリを作る
| 権限なしユーザ | member権限ユーザ | admin権限ユーザ |
/index.jsp | ○ | ○ | ○ |
/member/* | × | ○ | ○ |
/secure/* | × | × | ○ |
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Member Only</web-resource-name>
<url-pattern>/member/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>memberRole</role-name>
<role-name>adminRole</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Only</web-resource-name>
<url-pattern>/secure/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>adminRole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>ldapRealm</realm-name>
</login-config>
<security-role>
<role-name>memberRole</role-name>
</security-role>
<security-role>
<role-name>adminRole</role-name>
</security-role>
</web-app>
- Java EE 標準の設定ファイル
- <security-role> 設定で利用するロールを列挙するのを 忘れずに!。
これを忘れると、十分な権限のあるユーザでログインしても request.isUserInRole?(role) が false を返します。
- glassfish-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<security-role-mapping>
<role-name>adminRole</role-name>
<group-name>executive</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>memberRole</role-name>
<group-name>employee</group-name>
</security-role-mapping>
<session-config>
<cookie-properties>
<property name="cookieMaxAgeSeconds" value="-1">
</property>
</cookie-properties>
</session-config>
<class-loader delegate="true"/>
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class' java code.</description>
</property>
</jsp-config>
</glassfish-web-app>
- Glassfish の拡張。(3.0 までは sun-web.xml だった)
- ここの設定でLDAP のグループ名とロール名を読み替える
- 実験のため、cookieMaxAgeSeconds? = -1 として、Session-ID を Cookie に入れないようにしている。本来であれば、web.xml の session-timeout × 60 を設定すべき (session-timeout は分。cookieMaxAgeSeconds? は秒)
- ichiro ( executive グループ = admin ロール )の場合
- index.jsp はログインなしで見られる
- [member page] リンクを押すと、BASIC 認証を求められる
- [member page] が表示される
- [admin page] も表示できる
- jiro ( employee グループ = member ロール )の場合
- ユーザ情報の取得の仕方は、特に Glassfish であることを意識する必要ない
<%@page import="java.security.Principal"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Admin Only</h1>
<a href="../index.jsp">戻る</a>
<%
Principal p = request.getUserPrincipal();
%>
<br/>
<%= p.getClass().getCanonicalName() %><br/>
User = <%= request.getRemoteUser() %><br/>
is Admin? <%= request.isUserInRole("adminRole") %><br/>
is Member? <%= request.isUserInRole("memberRole") %><br/>
</body>
</html>
Java#Glassfish