SAML ~ Binding の 巻 ~

#SAML ~ Binding の 巻 ~
<img width="450" alt="SAML2.0" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246440/097ccec2-dd92-191b-86e4-5ec05d729205.png">
こんにちは、さみーです。

> [Digital Identity技術勉強会 #iddance Advent Calendar 2020](https://qiita.com/advent-calendar/2020/iddance)
> 2020年になりすっかりなりを潜めていますが、DigitalIdentityに関する技術の勉強会である #iddance のアドカレやります。

:point_up_tone2:こちらの14日目です。

すっかりID厨離れをしてしまっている今日この頃で新しいことはチョトワカラナイデスから、
昔話をします。**SAML**です。

##OpenID TechNight vol.17 で SAML の話もされてましたね

2020年8月に開催された「[OpenID TechNight vol.17 ~ with コロナ編](https://openid.connpass.com/event/183577/)」 にて、 「Safari (ITP) & Chrome (SameSite=Lax as default) が Federation に与える影響」 と題してnovさんがSAMLについてもお話しされてました。

> Federationは、Assertionを元に行うが、
> OpenIDでは、OPとRPバックチャネルの直接通信でAssertion（ID Token）をやり取り。
> SAMLではAssertionをフロントチャネルでやり取り。
> <img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246440/448fa6a0-4735-e61e-52de-0831785933e5.png">

OpenID Connect / SAML 共に、「こちらが主流」と説明がありますが、あくまで主流なだけであって、OpenID Connect でも 主に使われている Authorization Code Flow では バックチャネルで Assertion をやりとりしますが、フロントチャネルでやりとりする Implicit Flow も存在します。同じように、SAMLもバックチャネルでやりとりする Artifact Binding とうものが存在したりします。

ということで、今回は SAML の Bindingについてのお話です。

##SAML Bindings

SAML Bindingsの仕様はこちらです。
> Bindings for the OASIS Security Assertion Markup Language (SAML) V2.0
> http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf

色々ありますが、認証リクエスト/レスポンスで利用されるのは次の3つです。

- HTTP Rediret Binding
- HTTP POST Binding
- HTTP Artifact Binding

名前からイメージされる通りですが、それぞれのシーケンスをおさらいします。

###HTTP Redirect Binding
[saml-bindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) 3.4.5 Message Exchange より抜粋
<img width="600" alt="HTTP Redirect Binding" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246440/7ae843a3-f038-d697-e74b-8786a78ea453.png">
<font color="red">赤で囲った部分が 認証リクエスト</font>で用いられる HTTP Redirect Binding、
<font color="blue">青で囲った部分が 認証レスポンス</font>で用いられる HTTP Redirect Bindingです。

この Binding は、[OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) でいうところの [Implicit Flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth) ですね。


###HTTP POST Binding
[saml-bindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) 3.5.5 Message Exchange より抜粋
<img width="600" alt="HTTP POST Binding" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246440/3fca6878-f878-031d-af03-1f3e1778953b.png">
<font color="red">赤で囲った部分が 認証リクエスト</font>で用いられる HTTP POST Binding、
<font color="blue">青で囲った部分が 認証レスポンス</font>で用いられる HTTP POST Bindingです。

この Binding は、HTTP Redirect Binding 同様、[OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) でいうところの [Implicit Flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth) 、
加えて `response_mode` として [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) を採用したものになります。

###HTTP Artifact Binding
[saml-bindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) 3.6.5 Message Exchange より抜粋
<img width="600" alt="HTTP Artifact Binding" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246440/4c9be0d1-6c1e-5779-ba5a-808bfcc079a9.png">
<font color="red">赤で囲った部分が 認証リクエスト</font>で用いられる HTTP Artifact Binding、
<font color="blue">青で囲った部分が 認証レスポンス</font>で用いられる HTTP Artifact Bindingです。

<font color="blue">認証レスポンス</font>に Artifact Bindingを使うのは、[OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) でいうところの [Authorization Code Flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) ですね。

<font color="red">認証リクエスト</font>に Artifact Binding を使うのは、FAPI Part2 の [Request object endpoint](https://openid.net/specs/openid-financial-api-part-2-ID2.html#request-object-endpoint) を使うのと同じ、といったところでしょうか。
※ SAMLで Artifact を解決するのは Service Provider(Requester) で、OpenID Connet (FAPI) で request_uri を解決するのは Authorization Servier(Responder) といった違いはあります。

###  まとめると
上で挙げた3つの Binding について、OpenID Connect の Flow と比較してまとめると下記の通りです。

<table>
<tr>
 <th>Binding (SAML)</th>
 <th>Flow (OpenID Connect)</th>
</tr>
<tr>
 <td>HTTP Rediret Binding</td>
 <td>Implicit Flow (<code>response_type=id_token</code>)</td>
</tr>
<tr bgcolor="white">
 <td>HTTP POST Binding</td>
 <td>Implicit Flow (<code>response_type=id_token</code>)<br>
 + OAuth 2.0 Form Post Response Mode (<code>response_mode=form_post</code>)</td>
</tr>
<tr>
 <td>HTTP Artifact Binding<br>（認証リクエスト時の利用）</td>
 <td>FAPI Part 2 Request object endpoint 利用 (<code>request_uri=XXXX</code>)</td>
</tr>
<tr>
 <td>HTTP Artifact Binding<br>（認証レスポンス時の利用）</td>
 <td>Authorization Code Flow (<code>response_type=code</code>)</td>
</tr>
</table>

##使うBindingを指定したい

OpenID Connect では、

- Implicit Flow を使いたい場合には `response_type=id_token`
    - POST で `id_token` を送りたい場合は更に `response_mode=form_post` も指定
- Authorization Code Flow を使いたい場合には `response_type=code`

と、認証リクエストのパラメータで指定すれば良いですよね。

では、SAMLの場合はどうすれば、HTTP Redirect Binding、HTTP POST Binding、HTTP Artifact Binding をそれぞれ使えるのでしょう？

###認証レスポンスで使うBindingについて
認証レスポンスで使うBindingは、OpenID Connect と同じように、
SAMLの認証リクエストで送る `<AuthnRequest>` 電文の中で指定します。
指定する方法はいくつかありますが、例えば `ProtocolBinding` 属性で指定すると
指定した Binding にて認証レスポンスが返却されます。
その他の指定方法は [saml-core](http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) 3.4 Authentication Request Protocol をご参照ください。

```xml:RedirectBindingを指定する場合
<samlp:AuthnRequest
   ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
   [その他の属性省略]>
      [AuthnRequest中の要素省略]
</samlp:AuthnRequest>
```

```xml:ArtifactBindingを指定する場合
<samlp:AuthnRequest
   ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
   [その他の属性省略]>
      [AuthnRequest中の要素省略]
</samlp:AuthnRequest>
```

###認証リクエストで使うBindingについて

認証リクエストにて `SAMLart` パラメータ名で Artifact を送れば、あとはIdP側で良いようにやってくれます。Artifact を解決する `ArtifactResolutionService` は、もちろんSP側で準備ください。([saml-bindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) 3.6.4 Artifact Format で記載のフォーマットのArtifactを送ります）

```url:ArtifactBindingを指定したい場合
https://idp.example.com/SAML/SSO?SAMLart=[ここにArtifactを指定]&RelayState=XXXXXX
```

####Artifact Binding を使わない場合 との比較

ちなみに、Artifact Binding を使わない場合は `SAMLRequest` パラメータに `<AuthnRequest>`電文が指定されて送られます。（[saml-bindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) 3.4.4/3.5.4 Message Encoding で記載の通りにEncodeしたものを送ってます）

```url:RedirectBindingの場合の例
https://idp.example.com/SAML/SSO?SAMLRequest=[AuthnRequest電文]&RelayState=XXXXXX
```

##なぜ冒頭のように異なる主流を持つか

SAML も OpenID Connect も同じような Flow を持つにも関わらず、
なぜ [冒頭](https://qiita.com/samiii/private/9e64f4204bad46cf38a7#openid-technight-vol17-%E3%81%A7-saml-%E3%81%AE%E8%A9%B1%E3%82%82%E3%81%95%E3%82%8C%E3%81%A6%E3%81%BE%E3%81%97%E3%81%9F%E3%81%AD) のように、主流が異なるのでしょうか？

それは、その成り立ちに依ります。（←個人的見解です）

OpenID Connect は言うまでもなく OAuth 2.0 の上に構築された認証連携の仕様です。
その 元となる OAuth 2.0 の[Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16)(現状 Draft16) の [2.1.2.  Implicit Grant](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16#page-7)の項目には 

> SHOULD NOT use the implicit grant

と記載があります。

OAuth 2.0 で Protected Resources へのアクセスのために使われる アクセストークン は ほぼ Bearerトークンとして利用されるものであるため、フロントチャネルを介する＝不正なトークンの授受/利用がされてしまいかねず、脆弱であるといった理由からでしょう。

ここから、OpenID Connect も何となく Implicit Flow は避けたほうが良いというイメージになり（あるいは OAuth と合わせて使うことが多いため、Implicit Flow を避けるから？）
OpenID Connect といえば Authorization Code Flow、
すなわち、バックチャネルでAssertionをやりとりするのが主流となっているのではないでしょうか。

しかし、Assertion (id_token) は署名も付されており、
適切な検証がなされればフロントチャネルを介したからといって全く脆弱ではありません。

バックチャネルでのやりとりは単純に通信の回数が増えることから、
SAMLでは基本的にフロントチャネルでのやりとりを使っており、
電文のサイズが大きいなどの理由によりフロントチャネルでのやりとりが難しい場合に
Artifact Binding、すなわちバックチャネルでのやりとりを利用するという形を取っていたため
フロントチャネルでのやりとりが主流となっていると思われます。

## 温故知新

[SAML の NameID Format について書いた際](https://qiita.com/samiii/items/9b14967764d095cc5120) にも触れましたが、
SAMLを活用するユースケースに、当時は時代があまり追いついてなかったような気がします。

先日 [#idcon vol.28 DID特集その2 - その名も "#didcon"](https://idcon.connpass.com/event/191305/) が開催され、
DIDの最新について、学ばせていただきましたが、
ふと、Liberty Alliance Day 2007 の パネル展示で行われていたデモを思い出しました。

かなりうろ覚えではありますが、
PCで使っているWebサービスにて認証が必要になった時に
携帯に立てられた SAML IdP が起動され、
携帯をポチポチっと操作したら、
PC上で認証が完了、継続してサービスを利用できる、
といったようなものだったと思います。

スマホというものがまだ世に出回っていないガラケーの時代に、
既に DID のようなものが実装されていた、というわけです。

SAMLって、やっぱり奥が深いですね。
まだまだ学ぶことが多そうです。