OpenLDAPでユーザー認証までやってみる

Windowsログオンなどで使ったことはあるLDAPですが、詳細や構築などはやったことがなかったので、本を見ながら勉強してみたのでメモ。
参考にさせてもらった本の内容を途中までやった時の作業メモとなります。

# 参考

+ [インフラエンジニア教本2――システム管理・構築技術解説 (Software Design別冊)](http://www.amazon.co.jp/gp/product/4774177822/ref=s9_simh_gw_g14_i4_r?pf_rd_m=AN1VRQENFRJN5&pf_rd_s=desktop-1&pf_rd_r=1X35ZRCN02H7Q0PJA0WY&pf_rd_t=36701&pf_rd_p=302362649&pf_rd_i=desktop)
+ [入門LDAP/OpenLDAPディレクトリサービス導入・運用ガイド第2版](http://www.amazon.co.jp/%E5%85%A5%E9%96%80LDAP-OpenLDAP%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E5%B0%8E%E5%85%A5%E3%83%BB%E9%81%8B%E7%94%A8%E3%82%AC%E3%82%A4%E3%83%89%E7%AC%AC2%E7%89%88-%E3%83%87%E3%83%BC%E3%82%B8%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88/dp/4798033499/ref=sr_1_1?ie=UTF8&qid=1462484994&sr=8-1&keywords=ldap)

# 環境

+ Amazon Linux AMI 2016.03.1

# LDAPとは

+ Lightweight Directory Access Protocolの略語で、OSI参照モデルではHTTPなどと同じアプリケーション層のプロトコル。検索(search)、追加(add)、削除(delete)、変更(modify)といった機能を利用して登録した情報にアクセスできるプロトコルを提供。
+ LDAPでは名前の通り、Directoryの管理を行う。LDAPにおけるディレクトリとはコンピューターの電話帳や名簿に相当し、コンピューターのユーザー情報やグループ情報をネットワークで共有するためのサービス
+ LDAPはLDAPクライアント(認証される側)とLDAPサーバー(認証する)で構成される。LDAPサーバーを複数台で構成し、負荷分散及び冗長化構成をとることもできる
+ UnixソケットもしくはTCPプロトコルで通信。ldapプロトコルの389ポートかldapsの636ポートを利用する

# LDAPの設計

+ LDAPではDIT(Directory Information Tree)というツリー構造のデータ形式で情報を管理する
+ ツリーには「エントリ」と呼ばれる単位で情報が登録される
+ 一つのエントリにはDN(Distinguished Name)と呼ばれるツリー構造内のエントリの位置を示す識別子が一意に付与される
+ 一つのエントリは複数の「属性」で構成される。属性は「属性名:値」のセットで登録されている
+ エントリには必ず「objectClass」と呼ばれる属性が指定され、エントリに登録されるべき属性などを定義できる
+ objectClassはスキーマと呼ばれ、LDAPサーバーごとに定義できるが、標準的なスキーマはRFCで定義されている
+ 独自の属性情報を追加したい場合などにはobjectClassに追加したい独自の属性情報を定義すればOK

以下、よく使う属性名

|属性タイプ|説明|
|:-----------|:------------|
| dn       |識別子(Distinguished Name|
| objectClass|オブジェクトクラス|
| dc|ドメイン構成要素(Domain Component|
| o        |組織名(Organization)|
| ou       |組織単位(Organization Unit|
| cn    |一般名称(Common Name)|


# LDAPの複製(レプリケーション)

+ LDAPサーバーごとの複製(replication)を利用することでLDAPサーバー間でエントリ情報を共有し、複数台構成ができる
+ 複製のプロトコルは定義されておらず、製品ごとに違うため、複数台構成を行う場合、同じ製品を使う必要がある
+ エントリの追加・更新が可能なLDAPサーバーをマスターもしくはプロバイダーと呼び、エントリの参照のみが可能なLDAPサーバーをスレーブもしくはコンシューマと呼ぶ
+ 一般的なLDAP製品では複数台のマスターで構成されるマルチスター構成が可能で、用途によっては上記に加え、認証や参照専用のスレープサーバーを加える構成も可能
+ マルチスター構成でLDAPマスターサーバーが複数の場合に同じエントリに対して連続の書き込みがそれぞれ別のマスターサーバーによって実行されるとエントリの内容が意図した通りにならない場合がある（後述）上記より、ロードバランサによって同じエントリの更新は同じマスターサーバーに通信するなどの工夫が必要
+ エントリの複製方法として大きく分けて以下の2種類がある。「操作ログによる対象の属性のみを複製する方式」、「エントリ全体を複製する方式」
+ 「操作ログを送る方式」では自身のマスターサーバーで実行した追加処理のログを他のサーバーに送信し、他のサーバーではそのログ情報に基づいて対象エントリの更新を行う
+ 「エントリ全体を複製する方式」例えば仮にグループXという所にユーザーAを追加した場合、他のサーバーにはユーザーAだけが入ったグループXのエントリ全体の情報が送信される。上記仕様より、同じタイミングで同じグループにユーザー追加の依頼(ユーザーBとする)がユーザーAを登録するサーバーで以外であった場合、双方のサーバーでグループXのエントリの情報が更新されることによってユーザーAもしくはユーザーBの情報が喪失する可能性がある
+ OpenLDAPで一般的に利用される「syncrepl」は「エントリ全体を複製する方式」である。「操作ログを送る方式」は「Delta-syncrepl」と呼ばれ、マスター・スレーブ方式での利用が想定されている

# OpenLDAPサーバー、クライアントのインストール及び初期設定
 
まずはOpenLDAPサーバーとクライアントのインストール、LDAPサーバーの起動を行います。
 
```bash
# インストール
$sudo yum install openldap-clients openldap-servers

# バージョン確認
$slapd -V
@(#) $OpenLDAP: slapd 2.4.40 (Mar  8 2016 23:38:46) $
	mockbuild@gobi-build-60006.pdx1.amazon.com:/builddir/build/BUILD/openldap-2.4.40/openldap-2.4.40/build-servers/servers/slapd

# 起動
$sudo service slapd start
Starting slapd:                                            [  OK  ]
```

何も設定しないとLDAPのログは出力されません。
LDAPではsyslog(rsyslog)のログファシリティー「local4」でログ出力をするようになっているようなので、上記ログファシリティーのログ情報送信時にファイルに出力するように以下を追記します。

```text:/etc/rsyslog.conf
local4.*                                                /var/log/slapd
```

変更後、rsyslogプロセスを再起動して設定ファイルを読み込みます。

```bash
$sudo serivice slapd restart
```

上記で`/var/log/slapd`とファイルができていればOKです。
出力するログレベルはデフォルトは「stats」というものらしいので必要に応じてログレベルを変更することでログ出力される内容を変更出来ます。


# 検索してみる

LDAPをインストールしただけですが、デフォルト状態でもcn=configというLDAPサーバーの設定に関するエントリについては登録されており、その情報を検索してみます。
(rootユーザーで実行する点に注意。基本的に以降のコマンド操作はrootユーザーでの操作を想定。rootユーザでないとファイル権限がなくエラーになります)

```bash
$sudo su
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: cn=config

dn: cn=schema,cn=config

dn: cn={0}corba,cn=schema,cn=config

dn: cn={1}core,cn=schema,cn=config

dn: cn={2}cosine,cn=schema,cn=config

dn: cn={3}duaconf,cn=schema,cn=config

dn: cn={4}dyngroup,cn=schema,cn=config

dn: cn={5}inetorgperson,cn=schema,cn=config

dn: cn={6}java,cn=schema,cn=config

dn: cn={7}misc,cn=schema,cn=config

dn: cn={8}nis,cn=schema,cn=config

dn: cn={9}openldap,cn=schema,cn=config

dn: cn={10}ppolicy,cn=schema,cn=config

dn: cn={11}collective,cn=schema,cn=config

dn: olcDatabase={-1}frontend,cn=config

dn: olcDatabase={0}config,cn=config

dn: olcDatabase={1}monitor,cn=config

dn: olcDatabase={2}bdb,cn=config
```

コマンドオプションの意味はざっくり以下です。

+ -LLL->LDAP検索結果表示のオプション
+ -Y EXTERNAL->SASLのEXTERANL認証を利用してLDAPサーバーに接続
+ -H ldapi:///->LDAPサーバーのホスト。今回はInter process Communication(IPC)を利用してクライアントと同一ホスト上のプロセスと通信を実施
+ -b　cn=config dn->検索エントリの条件。今回の場合には属性cn=configの条件のdn属性エントリについて表示

上記表示された内容を実際のファイルで確認してみます。

```bash
# ディレクトリ移動
$/etc/openldap

# slap.d/cn=configディレクトリ配下がcn=configの条件に合致するファイル
$tree slapd.d/
slapd.d/
├── cn=config
│   ├── cn=schema
│   │   ├── cn={0}corba.ldif
│   │   ├── cn={10}ppolicy.ldif
│   │   ├── cn={11}collective.ldif
│   │   ├── cn={1}core.ldif
│   │   ├── cn={2}cosine.ldif
│   │   ├── cn={3}duaconf.ldif
│   │   ├── cn={4}dyngroup.ldif
│   │   ├── cn={5}inetorgperson.ldif
│   │   ├── cn={6}java.ldif
│   │   ├── cn={7}misc.ldif
│   │   ├── cn={8}nis.ldif
│   │   └── cn={9}openldap.ldif
│   ├── cn=schema.ldif
│   ├── olcDatabase={-1}frontend.ldif
│   ├── olcDatabase={0}config.ldif
│   ├── olcDatabase={1}monitor.ldif
│   └── olcDatabase={2}bdb.ldif
└── cn=config.ldif

2 directories, 18 files

# 実際に検索してみる
$find slapd.d/ -type f|xargs cat|grep dn:|sort
dn: cn=config
dn: cn=schema
dn: cn={0}corba
dn: cn={10}ppolicy
dn: cn={11}collective
dn: cn={1}core
dn: cn={2}cosine
dn: cn={3}duaconf
dn: cn={4}dyngroup
dn: cn={5}inetorgperson
dn: cn={6}java
dn: cn={7}misc
dn: cn={8}nis
dn: cn={9}openldap
dn: olcDatabase={-1}frontend
dn: olcDatabase={0}config
dn: olcDatabase={1}monitor
dn: olcDatabase={2}bdb
```

上記結果より、cn=configディレクトリ配下のldifという拡張子でdn属性の記述についての結果をldapsearchコマンドでは抜き出している事が分かりました。

# 色々検索してみる

色々検索してみます。

## ベースツリー

まずはベースツリーを検索します。ベースツリーには起動時のパラメーターやPIDファイル、TLS接続時のファイルなどの情報が確認できます。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=config -s base
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: cn=config
objectClass: olcGlobal
cn: config
olcConfigFile: /usr/share/openldap-servers/slapd.conf.obsolete
olcConfigDir: /etc/openldap/slapd.d
olcAllows: bind_v2
olcArgsFile: /var/run/openldap/slapd.args
olcAttributeOptions: lang-
olcAuthzPolicy: none
olcConcurrency: 0
olcConnMaxPending: 100
olcConnMaxPendingAuth: 1000
olcGentleHUP: FALSE
olcIdleTimeout: 0
olcIndexSubstrIfMaxLen: 4
olcIndexSubstrIfMinLen: 2
olcIndexSubstrAnyLen: 4
olcIndexSubstrAnyStep: 2
olcIndexIntLen: 4
olcListenerThreads: 1
olcLocalSSF: 71
olcLogLevel: 0
olcPidFile: /var/run/openldap/slapd.pid
olcReadOnly: FALSE
olcReverseLookup: FALSE
olcSaslSecProps: noplain,noanonymous
olcSockbufMaxIncoming: 262143
olcSockbufMaxIncomingAuth: 16777215
olcThreads: 16
olcTLSCACertificatePath: /etc/openldap/certs
olcTLSCertificateFile: "OpenLDAP Server"
olcTLSCertificateKeyFile: /etc/openldap/certs/password
olcTLSVerifyClient: never
olcTLSProtocolMin: 3.1
olcToolThreads: 1
olcWriteTimeout: 0
```

上記はファイルとしては`/etc/openldap/slapd.d/cn\=config.ldif`の内容の一部が表示されているようです。

### frontendデータベース

次にfrontendデータベースの値について確認します。
frontendデータベースはすべてのデータベースで適用する設定を記載するための暗黙のデータベースです。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={-1}frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: {-1}frontend
olcAddContentAcl: FALSE
olcLastMod: TRUE
olcMaxDerefDepth: 0
olcReadOnly: FALSE
olcSchemaDN: cn=Subschema
olcSyncUseSubentry: FALSE
olcMonitoring: FALSE
```

上記のように特にパラメーターは設定されていません。

## configデータベース

次にconfigデータベースの値を確認します。
configデータベースはOpenLDAPサーバーの設定を行うためのデータベースです。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b olcDatabase={0}config,cn=config
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to *  by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=externa
 l,cn=auth" manage  by * none
olcAddContentAcl: TRUE
olcLastMod: TRUE
olcMaxDerefDepth: 15
olcReadOnly: FALSE
olcRootDN: cn=config
olcSyncUseSubentry: FALSE
olcMonitoring: FALSE
```

## monitorデータベース

次にmonitorデータベースの値を確認します。
monitorデータベースはLDAPの動作状況を確認するためのデータベースです。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b olcDatabase={1}monitor,cn=config
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={1}monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {1}monitor
olcAccess: {0}to *  by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=externa
 l,cn=auth" read  by dn.base="cn=manager,dc=my-domain,dc=com" read  by * none
olcAddContentAcl: FALSE
olcLastMod: TRUE
olcMaxDerefDepth: 15
olcReadOnly: FALSE
olcSyncUseSubentry: FALSE
olcMonitoring: FALSE
```

こちらもconfigデータベースと同じ設定が確認できました。

## デフォルトのデータベース

最後にLDAPでデータを管理するために利用するデータベースのデフォルトの設定を確認します。

デフォルトのデータベースを確認してみます。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b olcDatabase={2}bdb,cn=config
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={2}bdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcBdbConfig
olcDatabase: {2}bdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=my-domain,dc=com
olcAddContentAcl: FALSE
olcLastMod: TRUE
olcMaxDerefDepth: 15
olcReadOnly: FALSE
olcRootDN: cn=Manager,dc=my-domain,dc=com
olcSyncUseSubentry: FALSE
olcMonitoring: TRUE
olcDbCacheSize: 1000
olcDbCheckpoint: 1024 15
olcDbNoSync: FALSE
olcDbDirtyRead: FALSE
olcDbIDLcacheSize: 0
olcDbIndex: objectClass pres,eq
olcDbIndex: cn pres,eq,sub
olcDbIndex: uid pres,eq,sub
olcDbIndex: uidNumber pres,eq
olcDbIndex: gidNumber pres,eq
olcDbIndex: givenName pres,eq,sub
olcDbIndex: ou pres,eq,sub
olcDbIndex: mail pres,eq,sub
olcDbIndex: sn pres,eq,sub
olcDbIndex: loginShell pres,eq
olcDbIndex: memberUid pres,eq,sub
olcDbIndex: nisMapName pres,eq,sub
olcDbIndex: nisMapEntry pres,eq,sub
olcDbLinearIndex: FALSE
olcDbMode: 0600
olcDbSearchStack: 16
olcDbShmKey: 0
olcDbCacheFree: 1
olcDbDNcacheSize: 0
```

デフォルトで利用しているデータベースの種類はBDB(Berkeley)であることが「objectClass: olcBdbConfig」となってる点から確認できました。なお、CentOS7でパッケージのインストールを行った場合、BDBを改良したHDB(Hierarchical DB)などがデフォルトのバックエンドデータベースとなっているようです。

「olcSuffix: dc=my-domain,dc=com」と指定されているので一度こちらの内容で検索してみます。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b dc=my-domain,dc=com
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
No such object (32)
```

デフォルトではデータベースはまだ作成されていないため、上記のような結果で表示されるようです。

# データベースの作成

LDAPサーバーとして利用するために既に記載されているデータベース定義を削除します。

```bash
# サービスの停止
$sudo service slapd stop
Stopping slapd:                                            [  OK  ]

# データベース定義ファイルの削除
$sudo rm /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{2\}bdb.ldif

# サービス起動
$sudo service slapd start
Starting slapd:                                            [  OK  ]

```

以下にサフィックス名「dc=example, dc=com」のツリーを作成するデータベースのLDIFファイルを記載します。作成するデータベースはHDBとします。

```text:example_com.ldif
dn: olcDatabase=hdb,cn=config
objectClass: olcHdbConfig
olcDatabase: hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcRootDN: cn=Manager,dc=example,dc=com
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * none
```

上記のolcAccess行ではOpenLDAPをインストールしたサーバーのrootユーザーがSASL/EXTERNALで認証した時に管理者権限が付与されるように指定しています。

また、「olcRootDN: cn=Manager,dc=example,dc=com」とすることでLinuxなどのrootユーザーに似た全てのディレクトリ情報を操作できるルートDNのDNを指定しています。cn(一般名称)では一般的に「Manager」が使われます。

上記example_com.ldifファイルは任意の場所に配置します。(/etc/openldap/slapd.d/cn\=config配下など配置するとプロセス起動時にwarningが表示されるのでそれ以外の任意の場所に置くように注意)
配置後、以下のコマンドで設定を書き込みます。

```bash
$ldapadd -Y EXTERNAL -H ldapi:/// -f example_com.ldif
```

書き込み後、以下のコマンドで設定を確認してみます。

```bash
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=config
(略)
dn: olcDatabase={2}hdb,cn=config
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external
 ,cn=auth" manage by * none
olcRootDN: cn=Manager,dc=example,dc=com
```

上記のように先ほどldifファイルに書いた内容が記載されていればOKです。

# データベースにエントリを格納する

データベースが作成できたので、次に上記のデータベースにエントリを追加していきます。

以下のような2つのエントリをbase.ldifとして作成します。

```text:base.ldif
# 一つ目のエントリ
dn: dc=example,dc=com
dc: example
o: example.com
objectClass: dcObject
objectClass: organization

# 2つ目のエントリ
dn: ou=Users,dc=example,dc=com
ou: Users
objectClass: organizationalUnit
```

一つのldifファイルでもエントリとエントリの間に空行を入れることで複数のエントリを記述することができます。
一つ目のエントリは「dn: dc=example,dc=com」となっており、このDITの一番上のエントリとなります。
2つ目はou=Usersという記述があり、一つ目のエントリの一つ下の階層に位置するUsersという組織のエントリであることが分かります。

今回、上記に合わせて管理者エントリも追加します。
管理者エントリに記載するパスワードのハッシュ値をコマンドを使って作成します。

```bash
$slappasswd
New password:
Re-enter new password:
{SSHA}WLxWiWqlZb8jWRWm19qV9ptFo3nOUfwj
```

上記を利用して先ほどのbase.ldifに管理者エントリ情報を追記します。userPassword属性には上記で生成したハッシュ値を指定します。

```text:base.ldif
# 一つ目のエントリ
dn: dc=example,dc=com
dc: example
o: example.com
objectClass: dcObject
objectClass: organization

# 2つ目のエントリ
dn: ou=Users,dc=example,dc=com
ou: Users
objectClass: organizationalUnit

# 3つ目のエントリ
dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: Manager
userPassword: {SSHA}WLxWiWqlZb8jWRWm19qV9ptFo3nOUfwj
```

上記ファイルを任意の場所に配置し、以下のコマンドでデータベースに登録を行います。

```bash
# 登録
$ldapadd -Y EXTERNAL -H ldapi:/// -f base.ldif

# 登録確認。エントリを全て表示
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: dc=example,dc=com
dc: example
o: example.com
objectClass: dcObject
objectClass: organization

dn: ou=Users,dc=example,dc=com
ou: Users
objectClass: organizationalUnit

dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: Manager
userPassword:: e1NTSEF9V0x4V2lXcWxaYjhqV1JXbTE5cVY5cHRGbzNuT1Vmd2o=

# 特定のエントリのみ表示
$ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=Manager,dc=example,dc=com
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: Manager
userPassword:: e1NTSEF9V0x4V2lXcWxaYjhqV1JXbTE5cVY5cHRGbzNuT1Vmd2o=
```

問題なければ登録できるはずです。
記述が誤っている場合、どの属性名が誤っているか表示されるので修正し、登録し直します。注意点として一つのldifファイルに複数のエントリを記述し、一つ目のエントリは問題なかったが、2つ目のエントリの記述誤りがある場合、一つ目のエントリは登録された状態になります。
そのため、同じldifを用いて登録しようとすると「dn: dc=example,dc=com」はすでに存在するという旨の表示がされるため、その場合、既に登録した情報は削除する必要があります。

基本的に以降は同じデータベース「dc=example,dc=com」を参照するのでLDAPクライアントでデフォルトで参照する設定にします。
LDAPクライアントが参照するファイルを編集します。

```text:/etc/openldap/ldap.conf
BASE dc=example,dc=com
URI ldapi:///
```

上記により、今後はホスト名とベースエントリを指定しなくても情報の参照ができます。

```bash
$ldapsearch -LLL -Y EXTERNAL
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: dc=example,dc=com
dc: example
o: example.com
objectClass: dcObject
objectClass: organization

dn: ou=Users,dc=example,dc=com
ou: Users
objectClass: organizationalUnit

dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: Manager
userPassword:: e1NTSEF9V0x4V2lXcWxaYjhqV1JXbTE5cVY5cHRGbzNuT1Vmd2o=
```

# 外部からの接続設定

次にネットワーク経由でLDAPに接続するための設定を行います。
まずはエントリに認証のために権限を付与します。

```text:acl.ldif
dn: olcDatabase={2}hdb,cn=config
replace: olcAccess
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * break
olcAccess: to attrs=userPassword by anonymous auth by * none
olcAccess: to * by * read
```
既に定義されたエントリを変更するために`ldapmodify`コマンドを実行します。

```bash
$ldapmodify -Y EXTERNAL -f acl.ldif
```

登録後、管理者エントリで認証できるかやってみます。
認証時のパスワードは`slappasswd `コマンドで指定したパスワードを入力します。

```bash
$dapsearch -x -D"cn=Manager,dc=example,dc=com" -H ldap://localhost -W
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
dc: example
o: example.com
objectClass: dcObject
objectClass: organization

# Users, example.com
dn: ou=Users,dc=example,dc=com
ou: Users
objectClass: organizationalUnit

# Manager, example.com
dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: Manager
userPassword:: e1NTSEF9V0x4V2lXcWxaYjhqV1JXbTE5cVY5cHRGbzNuT1Vmd2o=

# search result
search: 2
result: 0 Success

# numResponses: 4
# numEntries: 3
```

認証後、エントリの情報が無事取得できました。

# ユーザー、グループの追加

ユーザーがグループのエントリを登録できる準備をします。
ユーザーの作成にobjectClassとして「inetOrgPerson」、「posixAccount」を利用します。
利用したいobjectClassが読み込みされているか確認します。

```bash
$ldapsearch -LLL -Y EXTERNAL -b cn=schema,cn=config dn
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: cn=schema,cn=config

dn: cn={0}corba,cn=schema,cn=config

dn: cn={1}core,cn=schema,cn=config

dn: cn={2}cosine,cn=schema,cn=config

dn: cn={3}duaconf,cn=schema,cn=config

dn: cn={4}dyngroup,cn=schema,cn=config

dn: cn={5}inetorgperson,cn=schema,cn=config

dn: cn={6}java,cn=schema,cn=config

dn: cn={7}misc,cn=schema,cn=config

dn: cn={8}nis,cn=schema,cn=config

dn: cn={9}openldap,cn=schema,cn=config

dn: cn={10}ppolicy,cn=schema,cn=config

dn: cn={11}collective,cn=schema,cn=config
```

inetOrgPersonが依存しているcosineスキーマ、inetorgpersonスキーマ、posixAccountが定義されているnisスキーマが読み込まれており、すでに各objectClassが利用出来る状態であることが確認できましたので、何もする必要はありません。

# ユーザーの登録

実際にユーザーの登録を行ってみます。
登録するユーザー情報のldifファイルを作成します。

```text:user.ldif
dn: uid=testuser01,ou=Users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: testuser01
cn: ゆーざー01
sn: テスト
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/testuser01
```

追加します。

```bash
# 登録
$ldapadd -Y EXTERNAL -f users.ldif

# 確認
$ldapsearch -LLL -Y EXTERNAL -b uid=testuser01,ou=Users,dc=example,dc=com
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: uid=testuser01,ou=Users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: testuser01
cn:: 44KG44O844GW44O8MDE=
sn:: 44OG44K544OI
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/testuser01
```

ユーザー情報が追加できました。
上記ユーザーで認証をしてみたいのですが、パスワードが設定されていないので`ldappasswd`コマンドを利用してランダムのパスワードを割り当ててから認証してみます。

```bash
# ランダムのパスワードを設定
$ldappasswd -Y EXTERNAL uid=testuser01,ou=Users,dc=example,dc=com
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
New password: sqZUZ7Zh

# 割り当てられたパスワードで認証
$ldapwhoami -x -D uid=testuser01,ou=Users,dc=example,dc=com -H ldap://localhost -W
Enter LDAP Password:
dn:uid=testuser01,ou=Users,dc=example,dc=com
```