2021年のアドカレ・・・に書こうと思っていて忘れていた内容を今更。
ID厨を離れて長いので昔話。SAMLです。
今回は 認証コンテキスト のお話。
1. 認証コンテキスト
1.1. 認証コンテキストとは?
コンテキスト=文脈、つまり、どのような文脈で認証が行われたか。
より端的に言うと、どのように認証が行われたか? という情報です。
- Qiitaを利用しようとして、メールアドレスとパスワードでログインした
- ネットバンクで振込を行おうとして、IDとパスワードでのログインに加えてワンタイムパスワードで認証した
- 会社で利用しているサービスを使おうとして、クライアント証明書を使ってログインした
みたいなものです。
1.2. なんでSSOで認証コンテキストが必要?
上記の例にも挙げたように、単純にIDとパスワードの確認だけで提供できるサービスもあれば、より厳密な確認が必要なサービス(お金の振込など)がありますよね。
多要素認証が行われているものであればそのまま連携して利用するけれども、IDとパスワードだけ確認したものであれば、いくら信頼できるIdPから連携された情報であったとしても、追加の認証を行いたい。
といった場合のように、それぞれのサービスに適切な強度の認証を実現するため、SSOでも認証コンテキストが重要になります。
2. SAMLの認証コンテキスト
SAMLでは、大まかに下記の3点が仕様として定められています。
- 認証コンテキストの種類
- SPからの認証要求時に認証コンテキストを指定する方法
- IdPからの認証結果に認証コンテキストを記す方法
2.1. SAMLが定義する認証コンテキストの種類
詳細は認証コンテキストについてまとめた仕様書があるのでそちら参照。
例えば、「3.4.9 PasswordProtectedTransport」がIDとパスワードで認証した場合の認証コンテキストですが、それを示すURIは urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
として定義されています。
その他、「3.4.23 SSL/TLS Certificate-Based Client Authentication」 や 「3.4.24 TimeSyncToken」など色々定義されていますが、独自に定義した認証コンテキストを使用することもできるように定められています!
2.2. SPからの認証要求時に認証コンテキストを指定する方法
SPから必要な認証コンテキストを要求するには、<AuthnRequest>
に下記のように <RequestedAuthnContext>
を含めます。
<AuthnRequest [中略]>
<RequestedAuthnContext Comparison="exact" [中略]>
<AuthnContextClassRef [中略]>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</AuthnContextClassRef>
</RequestedAuthnContext>
</AuthnRequest>
<AuthnContextClassRef>
には、要求したい認証コンテキストのURIを指定。
Comparison
には指定した認証コンテキストとの比較方法を指定します。比較方法の具体的な値は以下の通り。
-
exact
: 指定したものと同じ認証コンテキストが必要- 必要なもの = 指定したもの
-
minimum
:指定したもの以上のレベルの認証コンテキストが必要- 指定したもの ≦ 必要なもの
-
maximum
:指定したもの以下のレベルの認証コンテキストが必要- 必要なもの ≦ 指定したもの
-
better
:指定したものより上のレベルの認証コンテキストが必要- 指定したもの < 必要なもの
<RequestedAuthnContext> の詳細は Coreの仕様書の 3.3.2.2.1 に記述があります。
2.3. IdPからの認証結果に認証コンテキストを記す方法
IdPで確認済みの認証コンテキストをSPに伝えるには、
<Response>
中の <Assertion>
の <AuthnStatement>
に下記のように <AuthnContext>
を含めます。
<Response [中略]>
[中略]
<Status>
<StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</Status>
<Assertion [中略]>
[中略]
<AuthnStatement AuthnInstant="2003-04-17T00:46:00Z">
<AuthnContext>
<AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</AuthnContextClassRef>
</AuthnContext>
</AuthnStatement>
</Assertion>
</Response>
IdPでも未認証の場合は認証を行なってから<Response>
を返却するように、IdPで認証済みでもSPが指定する認証コンテキストを満たしていない場合は、満たすような認証を行なってからその認証コンテキストを含んだ<Response>
を返却します。
SPが指定する認証コンテキストを解釈できなかったり存在しない場合はエラーで urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext
を返却します。
2.4. 使用イメージ
認証コンテキストとして、下記を定義して利用するとします。
AuthnContextClassRef の URI | レベル | 認証方法 |
---|---|---|
urn:hoge:ac:Password |
1 | パスワードによる認証 |
urn:hoge:ac:PKI |
2 | クライアント証明書による認証 |
パスワード認証が完了している状態であるとします。
その場合に、<RequestedAuthnContext>
として下記のようなものが送信された場合、どうなるでしょうか?
- Comparison="exact" で
urn:hoge:ac:Password
が要求された場合 - Comparison="better" で
urn:hoge:ac:Password
が要求された場合 - Comparison="exact" で
urn:hoge:ac:PKI
が要求された場合 - Comparison="better" で
urn:hoge:ac:PKI
が要求された場合
以下の通りの動きとなります。
- 「1.」は、追加認証なく
<AuthnContext>
がPassword
のレスポンスが返却される - 「2.」「3.」は追加でクライアント証明書による認証が行われ、
<AuthnContext>
がPKI
のレスポンスが返却される - 「4.」は、要求された条件を満たす認証コンテキストが存在しないので、
urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext
のエラーが返却される
ちょっとややこしいですが、こんなややこしいこともできるように、仕様は定義されていますので是非活用してあげてください。
【参考】 NIST SP-800-63-3
認証のレベルが云々と出てきましたが、レベルって何?
ですよね。
詳細は NIST SP-800-63-3 をご参考ください。
Identity Proofingプロセスでのレベル(IAL:Identity Assurance Level)、Authenticationプロセスでのレベル(AAL:Authenticator Assurance Level) は、Federatedプロセスでのレベル(FAL:Federation Assurance Level)の3つの要素に分けて詳しく記されています。
【参考】 OIDCの認証コンテキスト
「SAML のことはいいから、OpenID Connect のことを教えなさい。」 そんな声が聞こえてきそうなので、OpenID Connect でのことも簡単に記しておきます。
OIDCで認証要求時に認証コンテキストを指定する方法
AuthenticationRequest 中の acr_values
(Requested Authentication Context Class Reference values) で同様のことができます!
OIDCで認証結果に認証コンテキストを記す方法
id_token の acr
(Authentication Context Class Reference)、amr
(Authentication Methods References)で同様のことができます!
拡張仕様
認証コンテキストを意識してOpenID Connectを利用するにあたって、参考にすべき拡張仕様があるので紹介しておきます。
IDA (Identity Assuarance)
OIDC for IDA では、Identify Verification の結果を連携する仕組みが定められており、それこそ、「NIST SP-800-63-3A の IAL2 に準拠した Identity Verificationを行なっています」 という情報が連携できたりします。
FAPI(Financial-grade API)
FAPI は "Finaincial" と名前がついてますが、金融で使うことを目的とされたものではなく、あくまで "金融で使えるくらいの高いレベルを確保できる" 拡張仕様です。