概要
業務において、SAML認証の実装が必要となり、SP-InitiatedでIdP側を実装し、IdP-InitiatedでSP側を実装しました。 具体的な実装について尋ねられたため、改めて自身でも簡単に振り返っておきます。
実装方法
既存のPHPアプリケーションに組み込む必要があったため、lightSAMLを選択しています。
実装当時、SimpleSAMLphpという比較的多くの記事が存在するフレームワークも検証しましたが、何らかの理由により断念しました。 (既存システムのログイン処理に組み込むのが難しかったと記憶しています) lightSAMLはシンプルで理解しやすい構造で、ミドルウェア周りに手を加えることで要件に合致させることができました。 ただドキュメントは整備されていなかったため、試行錯誤の連続でしたが……
主にサイボウズのブログを参考にしつつ、lightSAMLの実装を解析・要件に合うように調整しました。
リリース後に近しい実装を行った記事がBaseで公開され、もう少し早く公開されていれば……と思いました。 ここまで細かく理解できていなかったので、参考になりました(ありがとうございます)。

SAML連携について
仕組み
事前にシステム間で信頼関係を築くことが重要で、信頼関係がない場合は認証ができない仕組みとなっています。 この信頼関係は互いを証明する情報のやり取りによって実現します。 基本的にはメタデータのやり取りがベターですが、要件に含まれていなかったため手動でやり取りしました。
実装にあたっては特にアサーション(IdPでログインしたことをSPに伝える)のフローが理解しにくく、実装中に「今、自分は何の処理を作っているのだろうか?」と考えることが多かったです。 以下の内容を頭に入れておくと理解がスムーズかもしれません。 みんなここで苦戦しているのか、一見正しいと思われる記事が誤っている場合もあります(それもあって混乱しました)。
アサーションの署名
IdPはAssertionを生成し、自身の秘密鍵を使用してデジタル署名を行います。
アサーションの暗号化
IdPはSPの公開鍵を使用してAssertionを暗号化します。これにより対応する暗号鍵を所有するSPだけがAssertionを復号できる仕組みとなっています。
アサーションの送信
IdPはデジタル署名+暗号化されたAssertionをSPに送信します。
SPでの検証と復号
SPはIdPの公開鍵を使用して署名を検証し、成功した場合にはAssertionを自身の秘密鍵で復号します。
アサーションの中には任意の値を含めることができるため、ここにログインユーザの情報(メールアドレスなど)を付与することでSAMLログインが実現します。どの項目をログインに使用するかはSPとIdPの合意によるので、実際の案件では仕様を調整しながら実施しています。
SP-Initiated
SAMLRequestとRelayStateをIdPに渡して認証を行います。 「RelayStateは渡さなくても良い」という解説がありましたが、特に理由がなければセットで渡すのが無難です(なぜだったか思い出せませんが、RelayStateなしでは結局認証できなかったと記憶しています)。
IdP-Initiated
生成したSAMLResponseをSPに送り、SP側はSAMLResponseを解析するだけのため実装が比較的簡単。
まとめ
lightSAMLを使用した実装を通じて、SAML認証の仕組みを理解することができました。 簡単な振り返りでしたが、具体的な処理などは機会があれば追記したいと考えています。