OpenAMでSAMLアサーションを暗号化する

#SAML アサーションの暗号化とは？
弊社OSSテクノロジではOpenAMの開発とサポートを行っています。
SAMLといえばOpenAM、OpenAMといえばSAMLという訳ではありませんが、SAMLについて少し書きます。

##SAMLアサーション？
SAMLについては、今更詳しく書くことはしませんが、サラッと関連事項だけフォローしておきます。
SAMLとはフェデレーション(シングルサインオン)に使われているプロトコルで、G-SuitesやOffice365、Salesforce、AWSなど主要なクラウドサービスでサポートされています。
SAMLにはIdP（認証サーバー）と、SP（認証を依頼し、認証情報を使うアプリケーションサーバー）の２役ありまして、このIdPからSPへ流れる認証情報をアサーションと呼んでいます。
SAMLアサーションはXML情報なので、暗号化にはXMLの暗号化規約[xmlenc](https://www.w3.org/TR/xmlenc-core1/)を利用しています。



暗号化しない時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。
![Screenshot at 2018-12-03 12-32-11.png](https://qiita-image-store.s3.amazonaws.com/0/316098/21a7e55f-54b1-3694-275d-ec35c140cfaa.png)

いたって普通のXMLです。
SAMLアサーションの暗号化はこのXMLの大事な部分を暗号化してしまおうとういことです。

##XML 暗号化の仕組み
ではどのようにXMLを暗号化するかというと、２種類の暗号方式が使われています。
###公開鍵暗号方式
IDPからSPへ渡される共通鍵を暗号化するのに使います。
共通鍵暗号方式に比べて計算に時間がかかるため、SAMLアサーション全体を暗号化するのではなく、共通鍵のみを暗号化するのに使われます。
暗号に使った共通鍵は、IdPがSPの公開鍵で暗号化してSAMLアサーションと一緒に送ります。

###共通鍵暗号方式
SAMLアサーションを暗号化するのに使います。
公開鍵暗号方式にくらべて計算時間が短いため、SAMLアサーション全体を暗号化するのに使われます。


#SAMLアサーションの暗号化を試して見る
SAMLアサーションの暗号化がわかったところで、設定して試してみます。

##OpenAMでのSAMLアサーション暗号化の設定
特に難しいことはありません、以下のチェックボックをチェックするだけです。
![Screenshot at 2018-12-03 12-38-36.png](https://qiita-image-store.s3.amazonaws.com/0/316098/8bc448a7-4cc2-e58f-f2ce-13d0ca754e88.png)


先程と同じように暗号化した時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。
![Screenshot at 2018-12-03 12-46-43.png](https://qiita-image-store.s3.amazonaws.com/0/316098/be606938-b6aa-10e9-1471-36a465e6c25d.png)

画像だと分かりにくいので、一部抜粋します。
先程説明しました２種類の暗号化方式が使われています。

```xml

共通鍵暗号方式（SAMLアサーションの暗号）
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> 
公開鍵暗号方式（共通鍵の暗号）
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> 
```

## あぁ...エラー
若干上の説明でネタバレしてますが、今回SPに使ったソフトウェアはshibbolethです。
OpenAMからのSAMLアサーションを受けた時に、以下のエラー画面が出ます。

![Screenshot at 2018-11-30 16-47-11.png](https://qiita-image-store.s3.amazonaws.com/0/316098/54403c46-028f-081f-1dd8-ac9ee0f602ce.png)

HTMLのエラーメッセージだけでは詳細が分からないので、/var/log/shibboleth/shibd.logをみるとshib.logxmlenc#rsa-1_5　は許されないぞと...復号化時にエラーになってます。

```
2018-11-30 16:44:30 WARN XMLTooling.Decrypter [2] [default]: XMLSecurity exception while decrypting key: XSECAlgorithmMapper::mapURIToHandler - URI http://www.w3.org/2001/04/xmlenc#rsa-1_5 disallowed by whitelist/blacklist policy

```

#機能が無いならコードを追加すればいいじゃない
パンが無いならケーキを食べればいいじゃないの法則

##RSAES-PKCS1-v1_5は無しの方向で...

SAMLアサーションの暗号化はあまり人気が無い技術で、いろいろなWebサービスでは「SAMLの暗号化はオフにすること」なんて注釈があったりしますが、、、
RSA-1.5が許されない世界なら、[RSA-OAEP](https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#rsa-oaep-mgf1p)を使えるように改造するのです。

とりあえず、コードを見てみるのです。
OpenAMのコードでは以下のような実装です。RSAなら1.5決め打ち。
[FMEncProvider.java](https://github.com/openam-jp/openam/blob/master/openam-federation/openam-federation-library/src/main/java/com/sun/identity/saml2/xmlenc/FMEncProvider.java)

```java
   
  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);

  } else if ...
```
後方互換性を気にしないで、単純にRSA-OAEPにしたいだけなら以下のようにするのもアリです。

```java

  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    cipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP);

  } else if ...
```


弊社はアップデートするお客様までフォローする必要があるので、高度な設定にuseRSAOAEPという設定を追加して、そのパラメーターが true だったら RSA_OAEPで暗号化するようなコードとします。


```java
  
  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    if (useRSAOAEP) {
      cipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP);
    } else {
      cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
    }

```


##実食というかテスト
いままでと同じように、暗号化時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。
![Screenshot at 2018-12-03 14-44-06.png](https://qiita-image-store.s3.amazonaws.com/0/316098/46dd32c1-ef92-cfa8-3345-ee65bed0639d.png)


スクリーンショットでは分かりにくいので抜粋します。
公開鍵暗号方式がrsa-oaep-mgf1pに変わったのがお分かりいただけるだろうか？

```xml

共通鍵暗号方式（SAMLアサーションの暗号）
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
公開鍵暗号方式（共通鍵の暗号）
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />

```


機能が欲しければ自分で書く、オープンソースの基本ですね。おはり