Clojure
SAML

ClojureでActive Directory Federation Server(ADFS)とSAML2連携

More than 1 year has passed since last update.

ClojureのアプリケーションをService Provider(SP)、ADFSサーバをIdentity Provider(IdP)としてSAML2認証をするための覚書です。

Clojure用SAML SPライブラリ

https://github.com/k2n/saml20-clj

こちらは、https://github.com/vlacs/saml20-clj のフォークです。OpenSAMLではSHA1がSAML Requestの標準アルゴリズムになっていますが、ADFSはデフォルトではSHA256を要求します。(AD側のSP設定で変えられるようですが)私はADFSの管理権限を持っていないですし、SHA1の衝突攻撃は現実的ということなので、SP側でSHA256を用いるように変更しました。

既存のPEMファイルからJava KeyStore(JKS)の作成

今回は、もともとShibboleth+NGINX+FastCGIで動作していたSAML認証が、SSLターミネーションをAWS ELB側で行うことにしたため、動作しなくなってしまった問題の回避策として始まっています。NGINXはShibbolethでは公式にサポートされておらず、nginx-http-shibbolethdockerイメージとして利用していたのですが、SSLスキームの不一致によるエラーの回避策を調べてもわからず、本家MLでも回答が期待できそうになかったので、いっそClojureアプリ本体でSAMLを扱ってしまおう、というのが動機でした。ですので、すでにopensslでcert.pemとkey.pemを生成し、Idp側に登録されていました。通常、JKSファイルは新規プライベートキーと共に生成されるのですが、ここでは既存のファイルを使ってJKSを生成します。
この例では、certificateがsp-cert.pem、プライベートキーファイルがsp-key.pemです。

  • まずPEMファイルをPKCS12形式に変換します。
openssl pkcs12 -export -in sp-cert.pem -inkey sp-key.pem -certfile sp-cert.pem -out testkeystore.p12

プロンプトでパスワードを聞かれるので、適宜指定してください。

  • PKCS12ファイルを基にJKSファイルを生成します。ここではsaml-stg.jksというファイル名にしていますが、適宜変更してください。
keytool -importkeystore -srckeystore testkeystore.p12 -srcstoretype pkcs12 -destkeystore saml-stg.jks -deststoretype JKS
  • Aliasは標準で1が振られているので、わかりやすい名前に変更します。
keytool -change-alias -keystore saml-stg.jks -alias 1

プロンプトで新エイリアス名を尋ねられるので、名前を指定してください。

saml20-cljの設定

quephirdさんがsaml20-cljのテスト用プロジェクトを作成してくださっています。saml20-cljを使っている人があまりいない感じで、腰が引けていたのですが、こちらでIdPとのやりとりができることを確認し、だいぶ勇気づけられました。
こちらの設定サンプルを見れば、だいたいのところは見当がつきます。気づいた点を挙げておくと...

  • app-nameはentityIDに使われるのですが、URLが望ましいということで、https://sp.example.com/saml/metaを指定しておきました。
  • idp-uriは、ADFSの場合、https://sso.example.com/adfs/ls/ を指定します。
  • idp-certは、https://adfs.example.com/federationMetadata/2007-06/federationMetadata.xml/EntityDescriptor/RoleDescriptor/KeyDescriptor[@use="signing"]/KeyInfo/X509Data/X509Certificateを指定します。関数のドキュメントでは指定しなければverificationをしないだけでオプショナルだよ、と書いてありますが、実際はこれを指定しないと平文化したSAMLResponseを返してくれません。
  • keystore-fileはプロジェクトルートからの相対パス、または絶対パスで上で生成したJKSファイルを指定します。
  • keystore-passwordは生成時に指定したパスワードです。defのため、JVM起動時に評価されます。パスワードが指定されていないと、JKSファイルが壊れているかもというエラーが出てしまいますので、環境変数などで外出ししている場合は必ずコンパイル時に正しいパスワードが渡るように設定しておく必要があります。
  • key-aliasは前項のステップで指定したエイリアス名です。
  • relay-stateの検証がなぜか失敗します。今回のユースケースでは転送先は固定で、SAML Requestとともに渡す必要が無いので、relay-stateのHMAC検証のロジックは無効にしてしまいました。