プライベート認証局で発行した証明書を使っているActive DirectoryのLDAPSをJavaから利用する方法

Page content

プライベート認証局で発行した証明書を使っているActive DirectoryのLDAPSをJavaから利用する方法

概要

プライベート認証局で発行したSSL証明書を利用しているActive DirectoryのLDAPSをJavaから利用する場合keytoolsにプライベート認証局のCA証明書を登録してJavaでLDAPS認証するには 以下のコマンドを実行する。

  1. keytoolsにCA証明書を登録する
    keytool -importcert -trustcacerts -alias MYCACERT -file CA証明書のファイル名 -keystore keystoreのファイル名
  2. LDAPS認証できるjavaのソースコードを用意してjavacでクラスファイルを用意する
    ActiveDirectoryをLDAP(S)として利用する場合ユーザ名を検索するにはcnではなくてsAMAccoutNameを利用する
  3. Javaを実行する
    java -Djavax.net.ssl.trustStore=keystoreのファイル名 -Djavax.net.ssl.trustStorePassword=keystoreのパスワード Javaのクラスファイル(拡張子抜き)

そもそもActiveDirectoryでLDAPSのポートが開いてるか確認する

PowerShellを開いて

Test-Netconnection ActiveDirectoryサーバのアドレス -Port 636

opensslが使える環境があるなら以下のコマンドを実行することでCA証明書でLDAPSのSSL証明書が正しいかどうかを確認することが出来る

echo "Q" |openssl s_client -connect ADサーバのアドレス:636 -trusted_first -CAfile CA証明書のファイルへのPATH | openssl verify -CAfile CA証明書のファイルへのPATH

これ echo "Q" じゃなくて -showcerts つける方が正しそうな気がする…

本文

今回の記事は完全に自分向けメモ。 会社でデモすることを想定して居るので作業環境はWindowsのコマンドプロンプトとnotepad

開発中の○○システムの認証を情シスが管理して居るActiveDirectoryのLDAPを使ってやりたい。会社から要求があるのでLDAPSにする必要がある。ActiveDirectoryの事なので情シスに協力していただきたい…とSESの(有名な)会社の人に言われたんだけど、協力の内容がActiveDirectoryサーバで証明書を発行してくださいだったので完全に???となり、必要になる筈のCA証明書を渡した後もまだ、これでは無くてActiveDirectoryで発行した証明書が必要なんですと言われて更に???となり自分のSSLに関する知識が誤った物では無いかと不安になったため、週末の時間を2時間も利用しJavaでLDAPS認証をする方法を調べる羽目になった。

javaは全く分からないのだけど、SESの人がActiveDirectoryで発行した証明書をkeytoolsに読み込ませる必要があるということを言っていたのでkeytoolsに付いても調べた。

結果、情シス側であとやる事はActiveDirectoryの検索を行う為のユーザの払い出しだけのようだと言う事がわかった。

もらった手順書とググった内容からActiveDirectoryサーバに自己署名の証明書が利用されていると言う想定で手順書やら設計が作られていて、サーバに自己署名ではない証明書が登録されていると言う事が想定外になっているらしい事もわかった …

Javaでプライベート認証局のCA証明書を利用する

keytoolsを以下のオプションで実行するとカレントディレクトリに指定したファイル名のkeystoreというファイルができあがる。この証明書を登録しても良いか?という様な出力を行って入力待機状態になるのでYを押して登録する。keytoolsにはパスワードを設定しないといけないのでパスワードを設定する。 aliasに指定する名前は何でも良さそう

keytool -importcert -trustcacerts -alias MYCACERT -file CA証明書のファイル名 -keystore keystoreのファイル名

で、このファイルを実行時に読み込ませるには以下のオプションが必要

java -Djavax.net.ssl.trustStore=keystoreのファイル名 -Djavax.net.ssl.trustStorePassword=keystoreのパスワード Javaのクラスファイル(拡張子抜き)

ActiveDirectory でLDAP認証をする

https://www.earthlink.co.jp/engineerblog/technology-engineerblog/3336/

のサンプルコードを元に説明しやすい用に諸々変数化したのがこれ https://gist.github.com/nyomo/23e5aadd1f3a7afa6505b3f4f41fc49b

パスワードが空の時に正しく認証されたのと同じ状態になってしまうらしいので、パスワードが空の時は例外を投げるようにしたけど私のJava力だとちゃんと正しい状態には出来なかったので、これはあくまでもLDAPSで正しく証明書が確認されてユーザの検索等が行える事を確認出来るだけのコードだという事の説明を忘れずにしなければならない。

これで任意のユーザでアカウント認証出来る様にするまでに必要だったのがActiveDirectoryのユーザを検索することが出来る権限を持つユーザとそのパスワード(特に制限をかけてないActiveDirectoryならDomain Usersのユーザで問題無い。)

あと、LDAPのユーザ検索は通常basednとcnで行うという様な事がググると出てくるが、ActiveDirectoryのcnはユーザの氏名が登録されているのでユーザ名で検索する場合はcnではなくsAMAccoutNameを利用する必要があった。sAMAccoutNameは以前のバージョンのWindowsとの互換性を得る為の物というドキュメントを見て、uidを使うのが正しいのか?…と思ったけどuidには値が設定されていないのが標準らしく使えなかった。

↑のGISTの内容をメモ帳などにコピーし、日本語で書いてある部分を完全に消した後、20行目までのStringで設定している変数を存在するサーバなどに書き換えた後 javac LDAPClientTest.java としてLDAPClientTest.classを作成

java -Djavax.net.ssl.trustStore=keystoreのファイル名 -Djavax.net.ssl.trustStorePassword=keystoreのパスワード LDAPClientTest

で動く。

エンタープライズの世界はわからないけどここまでの内容は私の知っているSSLとLDAPの内容と同じなので、私の知識が全く間違えているという事は無さそうなのが確認出来たので安心した…

userIDとuserPassが正しい場合と正しく無い場合とkeystoreを指定しなかった場合の3パターンSESの人に見せて私はこのパターンのLDAPSしかわからないので、あとはこちらで協力出来るのはLDAPuserを作ってパスワードを共有することくらいですね…とお伝えしても納得して貰えなかった場合どうしたらいいんだろうか…

あと、SESの会社ってよくある作業手順とかコードの共有化ってされてないんだろうか…?(ActiveDirectoryをLDAPSとして使うのが稀…ということは無い様な気がする)