sAMAccountNameをキーとして、OpenLDAPとActiveDirectoryを検索する

参考URL：http://www.linuxtopia.org/online_books/network_administration_guides/ldap_administration/overlays_Chaining.html

sAMAccountNameをキーとして、OpenLDAPで管理しているアカウント、ActiveDirectoryで管理しているアカウントを一元で検索するようにしました。

<dl>
<dt>前提とするOS/MWのバージョン</dt>
<dd>CentOS 7.2.1511</dd>
<dd>cyrus-sasl：2.1.26</dd>
<dd>openldap-*：2.4.40</dd>
</dl>
RPMまで導入済みの状態とする。

**ドメイン定義**
　AD：dc=ZZZ,dc=local
　LDAP：dc=YYY,dc=ZZZ,dc=local
*ADのサブドメインとしてLDAPを定義*

**ユーザDN**
　AD：cn=[フルネーム],OU=OU_Users,dc=ZZZ,dc=local
　LDAP：sAMAccountName=[アカウント名],ou=[会社名],ou=partner,dc=YYY,dc=ZZZ,dc=local
*となるようにします。*

# 1.パスワード生成
```bash
slappasswd
```

```shell-session
New password:
Re-enter new password:
{SSHA}hth5u4U3WU9lWWvWT2zS2vePRxVUhBrg
```

# 2.DB_CONFIGファイルの配置
サンプルを使用します。

```bash
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
chown ldap:ldap /var/lib/ldap/DB_CONFIG 
```

# 3.ActiveDirectory用のスキーマファイル取得
```bash
wget http://lism.sourceforge.jp/docs/ad.schema -O /etc/openldap/schema/ad.schema
```

# 4.カスタムスキーマの定義
inetOrgPersonを継承して、ADと共通の検索キーとする"sAMAccountName"を必須属性として定義。
sAMAccountNameにはuidと同じ値を設定します。

```text:/etc/openldap/schema/custom.schema
# OpenLDAP User schema
objectclass ( 1.1.2.2.1
        NAME 'customObject'
        DESC 'Custom Object'
        SUP 'inetOrgPerson'
        STRUCTURAL
        MUST ( sAMAccountName ) )
```


# 5.slapd.conf
```text:/etc/openldap/slapd.conf
include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema

pidfile         /var/run/openldap/slapd.pid
argsfile        /var/run/openldap/slapd.args

modulepath      /usr/lib64/openldap
moduleload      back_ldap.la

# For Additional Schema
include         /etc/openldap/schema/ad.schema
include         /etc/openldap/schema/custom.schema
sizelimit unlimited

# チェイン先のADを検索する設定
overlay chain
chain-max-depth 2
chain-return-error TRUE

chain-uri "ldap://[ADのIP]/"
chain-rebind-as-user true
chain-idassert-bind bindmethod="simple"
  binddn="[検索ユーザのDN]"
  credentials="[パスワード]" mode="legacy" flags="non-prescriptive"
chain-acl-bind bindmethod="simple"
  binddn="[検索ユーザのDN]"
  credentials="[パスワード]"


# Access Control
### ACLは省略 ###

password-hash   {SSHA}

# For Local LDAP
database        bdb
suffix          "dc=YYY,dc=ZZZ,dc=local"
rootdn          "cn=Manager,dc=YYY,dc=ZZZ,dc=local"
rootpw          {SSHA}hth5u4U3WU9lWWvWT2zS2vePRxVUhBrg
directory       /var/lib/ldap
loglevel        256

# For Local Index
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
index sAMAccountName                    eq,pres
index distinguishedName                 eq,pres

# ADのみを検索するための設定
database        ldap
chase-referrals no
suffix          "dc=ZZZ,dc=local"
uri             ldap://[ADのIP]/
acl-bind        bindmethod="simple"
  binddn="[検索ユーザのDN]"
  credentials="[パスワード]"
idassert-bind   bindmethod="simple"
  binddn="[検索ユーザのDN]"
  credentials="[パスワード]" mode="legacy" flags="non-prescriptive"

# For monitoring
database monitor
```

# 6.設定反映
まずはシンタックスチェック。

```bash
slaptest -u -f /etc/openldap/slapd.conf -v
```
```shell-session
config file testing succeeded
```

実際に反映させる。

```bash
chown root:ldap /etc/openldap/slapd.conf
chown -R ldap:ldap /var/lib/ldap
mkdir -p /etc/openldap/slapd.d/
slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d
```
```shell-session
config file testing succeeded
```

# 7.ADへの参照エントリ作成
```text:ref.ldif
dn: ou=XXX,dc=YYY,dc=ZZZ,dc=local
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: XXX

dn: cn=proxy,ou=XXX,dc=YYY,dc=ZZZ,dc=local
objectClass: referral
objectClass: extensibleObject
dc: AAATree
cn: proxy
ref: ldap://[ADのIP]/ou=OU_Users,dc=YYY,dc=local
```
参照エントリを登録。

```bash
ldapadd -x -D "cn=Manager,dc=YYY,dc=ZZZ,dc=local" -W -f ref.ldif
```



## 8.動作確認
LDAPのドメインをサーチベースとした時にLDAP/ADとも検索されることを確認。

```bash:LDAPのサブドメインからADのアカウントを検索
ldapsearch -x -h [LDAPのIP] -D "[LDAP検索ユーザーのDN]" -w'[パスワード]' \
 -b "dc=YYY,dc=ZZZ,dc=local"                                             \
 "(sAMAccountName=[ADに存在するアカウント])"                             \
 "sAMAccountName"
```
```shell-session
dn:: Y2496JiH55Sw5LquLG91PU9VX1VzZXJzLGRjPXRhZHMsZGM9bG9jYWw=
sAMAccountName: [ADに存在するアカウント]
```

```bash:LDAPのサブドメインからLDAPのアカウントを検索
ldapsearch -x -h [LDAPのIP] -D "[LDAP検索ユーザーのDN]" -w'[パスワード]' \
 -b "dc=YYY,dc=ZZZ,dc=local"                                             \
 "(sAMAccountName=[LDAPに存在するアカウント])"                           \
 "sAMAccountName"
```
```shell-session
dn: sAMAccountName=[LDAPに存在するアカウント],ou=[会社名],ou=partner,dc=YYY,dc=ZZZ,dc=local
sAMAccountName: [LDAPに存在するアカウント]
```

ADのドメインをサーチベースとした時にADのみ検索されることを確認。

```bash:ADのドメイン指定でADのアカウントを検索
ldapsearch -x -h [LDAPのIP] -D "[LDAP検索ユーザーのDN]" -w'[パスワード]' \
 -b "dc=ZZZ,dc=local"                                                    \
 "(sAMAccountName=[ADに存在するアカウント])"                             \
  "sAMAccountName"
```
```shell-session
dn:: Y2496JiH55Sw5LquLG91PU9VX1VzZXJzLGRjPXRhZHMsZGM9bG9jYWw=
sAMAccountName: [ADに存在するアカウント]
```

```bash:ADのドメイン指定でLDAPのアカウントを検索
ldapsearch -x -h [LDAPのIP] -D "[LDAP検索ユーザーのDN]" -w'[パスワード]' \
 -b "dc=ZZZ,dc=local"                                                    \
 "(sAMAccountName=[LDAPに存在するアカウント])"                           \
  "sAMAccountName"
```
```shell-session
(検索結果なし)
```


# 9.SASLの設定
```text:/etc/sysconfig/saslauthd
MECH=ldap
FLAGS="-O /etc/saslauthd.conf"
```

```text:/etc/saslauthd.conf
ldap_servers: ldap://127.0.0.1
ldap_use_sasl: no
ldap_bind_dn: [LDAP検索ユーザのDN]
ldap_password: [パスワード]
ldap_mech: PLAIN
ldap_auth_method: bind
ldap_filter: (sAMAccountName=%U)
ldap_scope: sub
ldap_search_base: dc=YYY,dc=ZZZ,dc=local
ldap_deref: always
```
```bash
chmod 600 /etc/saslauthd.conf
```

## 10.Subversionの認証をSASL経由に
```text:svnserve.conf
[sasl]
use-sasl = true
```

```text:/usr/lib64/sasl2/svn.conf
pwcheck_method: saslauthd
auxprop_plugin: ldap
mech_list: PLAIN
ldapdb_mech: PLAIN
```