はじめに
- spring-bootでLDAP認証したいと思ったが、実験環境が無かったのとLDAPの操作知識がなかったので勉強した。
- spring-bootでLDAP認証する部分については言及しない
- docker,docker-compose,docker-machineを利用しているがセットアップ方法は言及しない
- LDAPの用語であるところのDN,CN,DCなどについても言及しない
環境
- mac
- Docker version 18.03.0-ce, build 0520e24
- docker-compose version 1.20.1, build 5d8c71b
docker-compose
- LDAP
- port: 8389
- phpldapadmin
- port: 8080
- DN: cn=admin,dc=springframework,dc=org
- PW: ldappw
- 参考
docker-compose.yml
version: '2'
services:
openldap:
image: osixia/openldap:latest
container_name: test1-ldap
environment:
LDAP_ORGANISATION: "springframework"
LDAP_DOMAIN: "springframework.org"
LDAP_ADMIN_PASSWORD: "ldappw"
ports:
- "8389:389"
admin:
image: osixia/phpldapadmin:latest
container_name: test1-ldapadmin
environment:
PHPLDAPADMIN_LDAP_HOSTS: "ldap"
PHPLDAPADMIN_HTTPS: "false"
ports:
- "8080:80"
links:
- "openldap:ldap"
$ docker-compose up
補足
dockerコンテナのIPは下記で調べられる
$ docker-machine env default
set -gx DOCKER_TLS_VERIFY "1";
set -gx DOCKER_HOST "tcp://192.168.99.100:2376";
set -gx DOCKER_CERT_PATH "/Users/positrium/.docker/machine/machines/default";
set -gx DOCKER_MACHINE_NAME "default";
# Run this command to configure your shell:
# eval (docker-machine env default)
ldapコンテナに入る
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3b011e09d113 osixia/phpldapadmin:latest "/container/tool/run" 21 hours ago Up 21 hours 443/tcp, 0.0.0.0:8080->80/tcp test1-ldapadmin
570508cd3d27 osixia/openldap:latest "/container/tool/run" 21 hours ago Up 21 hours 636/tcp, 0.0.0.0:8389->389/tcp test1-ldap
$ docker exec -it test1-ldap bash
注意
# /etc/init.d/slapd restart
を行うと、slapdのstopは出来たがstartが出来なかった。(Dockerの特徴?イメージの問題?)
ldapに適当なldifを読ませる
$ ldapadd -x -D 'cn=admin,dc=springframework,dc=org' -W -f test-server.ldif
正常に入ったら中身を下記で確認できるが、userPasswordはBase64.encode()されたものが出てくる。
$ slapcat
- 下記、コメントアウト部分はコンテナによって自動作成されている部分
- 他のエントリはspring-securityから
- 小話: benのuserPasswordのrawは
benspassword
の筈だが、sha1Hexすると9c509e6d68f17da2db1c71b5424e54538b6b6ef4
なので、実はbenspassword
ではない気がする。
- 小話: benのuserPasswordのrawは
test-server.ldif
# dn: dc=springframework,dc=org
# objectClass: top
# objectClass: dcObject
# objectClass: organization
# o: springframework
# dc: springframework
#
# dn: cn=admin,dc=springframework,dc=org
# objectClass: simpleSecurityObject
# objectClass: organizationalRole
# cn: admin
# description: LDAP administrator
# userPassword:: {SSHA}uKmKC5S1n62OuXyikGfXylLLNiTkFMt7
dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people
dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople
dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: bobspassword
dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword
ldapsearch
uid=bobエントリを検索
$ ldapsearch -x -D 'cn=admin,dc=springframework,dc=org' -W -LLL -b 'ou=people,dc=springframework,dc=org' '(uid=bob)'
Enter LDAP Password:
dn: uid=bob,ou=people,dc=springframework,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword:: Ym9ic3Bhc3N3b3Jk
- ldif形式で出力される
- ldif形式での
::
(userPassword:: Ym9ic3Bhc3N3b3Jk など)はバイナリ値を表す - userPasswordは、Base64.encode()されており
Ym9ic3Bhc3N3b3Jk
だが、デコードすると平文でbobspassword
が入っている。
ldapcompare
uid=benの存在有無比較
$ ldapcompare -x -D 'cn=admin,dc=springframework,dc=org' -W 'uid=ben,ou=people,dc=springframework,dc=org' 'uid: ben'
Enter LDAP Password: [冒頭のphpldapadminのPWを入力]
TRUE
java code sample
<!-- https://mvnrepository.com/artifact/com.unboundid/unboundid-ldapsdk -->
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>4.0.5</version>
</dependency>
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPAttribute;
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPConnection;
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException;
public class Fuga {
public static void main(String[] args) {
Fuga fuga = new Fuga();
try {
fuga.go();
} catch (LDAPException e) {
e.printStackTrace();
}
}
public void go() throws LDAPException {
String address = "192.168.99.100";
Integer port = 8389;
String dn = "cn=admin,dc=springframework,dc=org";
String pass = "ldappw";
LDAPConnection c = new LDAPConnection();
c.connect(address, port.intValue(), dn, pass);
String user_dn = "uid=ben,ou=people,dc=springframework,dc=org";
LDAPAttribute ldapAttribute = new LDAPAttribute("uid", "ben");
if (c.compare(user_dn, ldapAttribute)) {
System.out.println("OK");
} else {
System.out.println("NG");
}
}
}
OKとでる。
uid=bobの平文パスワード比較
$ ldapcompare -x -D 'cn=admin,dc=springframework,dc=org' -W 'uid=bob,ou=people,dc=springframework,dc=org' 'userPassword::Ym9ic3Bhc3N3b3Jk'
Enter LDAP Password:
TRUE
- uid=bobのuserPasswordはbase64.encode()して保存されているので、base64.encode()された文字列を渡す。
- ldifで
::
はバイナリ値を表すのと同じく、ldapcompareでも同様に::
で値を指定する。
java code sample
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPAttribute;
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPConnection;
import com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException;
public class Fuga {
public static void main(String[] args) {
Fuga fuga = new Fuga();
try {
fuga.go();
} catch (LDAPException e) {
e.printStackTrace();
}
}
public void go() throws LDAPException {
String address = "192.168.99.100";
Integer port = 8389;
String dn = "cn=admin,dc=springframework,dc=org";
String pass = "ldappw";
LDAPConnection c = new LDAPConnection();
c.connect(address, port.intValue(), dn, pass);
String user_dn = "uid=bob,ou=people,dc=springframework,dc=org";
LDAPAttribute ldapAttribute = new LDAPAttribute("userPassword", "bobspassword");
if (c.compare(user_dn, ldapAttribute)) {
System.out.println("OK");
} else {
System.out.println("NG");
}
}
}
OKとでた。勝手にBase64してくれたらしい。
uid=benのSHAパスワード比較
$ ldapcompare -x -D 'cn=admin,dc=springframework,dc=org' -W 'uid=ben,ou=people,dc=springframework,dc=org' 'userPassword::e1NIQX1uRkNlYldqeGZhTGJISEcxUWs1VVU0dHJidlE9'
Enter LDAP Password:
TRUE
- userPasswordの指定に関しては前述同様
- java sample codeについては、 小話参照で、現状、uid=benのuserPasswordのrawが不明なので書き換えてやらないといけない。書き換えずとも、
{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
を入れてやればいい筈だが、通常のパスワード入力値を想定したコードを書いているつもりなので、一手間あって面倒なので検証してない。
その他の暗号形式の場合
未検証だが、平文、SHA同様にBase64.encode()したバイナリ値を入力すればTRUEが返るはず。