今さらSAML2.0を理解する(2)：OpenAMとSalseforceでSAML連携してみよう

# はじめに
第2回はSaaSとして、クラウド上に展開されている実際のサービスであるSalseforceとOpenAMでSAML連携をしてみます。
SAML2.0のIdPとしてOpenAMを利用し、SPとしてSalesforceを利用します。

また、第1回の内容も参考にしてください。

[今さらSAML2.0を理解する(1)：OpenAMとsimpleSAMLphpでSAML連携してみよう](https://qiita.com/kurotsu/items/e6d21591fa4d901b51a0)

# Salseforceの設定
あらかじめSaleseforceのアカウントを作成します。
Saleseforceでは記事執筆時点では無料トライアルも用意されています。
また、本記事では私のドメインという設定でカスタムのドメインでアクセスできるように設定しています。

Salesforceにログインして、メニューから[ID]->[シングルサインオン設定]を開きます。
![sf1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/4f3c5e19-05eb-4472-9eb5-71acf01464ae.png)

編集ボタンを押して、「SAMLを有効化」のチェックをONにして保存を押します。
![sf2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/30594d7f-9e07-4f5b-bfc8-7cbdf906b1e7.png)

続いてSAMLシングルサインオン構成にある「メタデータファイルから新規作成」ボタンを押して、IdP（OpenAM）のメタデータファイルを設定します。
OpenAM上のホストIdP設定は第1回で作成したものを利用します。
まだ作成していない方は第1回を参考にして「OpenAMのIdPメタデータ取得」でダウンロードしてください。
https://qiita.com/kurotsu/items/e6d21591fa4d901b51a0#openam%E3%81%AEidp%E3%83%A1%E3%82%BF%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%96%E5%BE%97

![sf3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/3fc715c9-a930-4a5b-b234-c49bdf58a995.png)

参照をクリックしてIdPのメタデータファイルを選択して、作成ボタンを押します。
![sf4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/e716d663-88ec-4f99-913f-284f63262cb3.png)

以下のように設定画面が表示されるのでそのまま保存ボタンを押します。
![sf5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/ea8bf45c-7f4a-436f-a93f-d1ba585f2a43.png)

保存後に以下の画面が表示されます。
もし、シングルサインオン設定に戻ったときは、ssoという名前で設定が保存されているのでssoのリンクをクリックすると再度同じ画面が表示されます。
「メタデータのダウンロード」ボタンを押してSP(Saleseforce)のメタデータファイルをダウンロードしてください。
![sf6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/5729acd7-04d6-415d-aeb0-2204777b11cc.png)

次にSalesforceの画面からシングルサインオンを実行するために、
マイドメインの設定を変更します。
メニューから[会社の設定]->[私のドメイン]を開きます。
認証設定の編集ボタンを押します。
![sf7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/566cf7c7-0862-40d8-b4a1-7601ef3d4a32.png)

認証サービスの「SSO」にチェックを入れて保存ボタンを押します。
![sf8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/4001c86f-051f-41d0-b0cc-0feb0bf33be6.png)

これでSalesforceの設定は完了です。

## OpenAMの設定

OpenAMにSalesforceをリモートサービスプロバイダとして登録します。
OpenAMの管理コンソールにアクセスして、ダッシュボードの[SAMLv2 プロバイダを作成]をクリックします。
次に[リモートサービスプロバイダを登録]をクリックします。
![openamconfig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/6d626cf7-c29e-4255-9f90-30d45ffca3e7.png)

[メタデータファイルはどこに存在しますか？]で「ファイル」を選択します。
続いてその下に表示される「アップロード」を押します。
![openamconfig7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/e4a4b20b-e975-4399-82a4-f64a1bd74f61.png)

ポップアップでファイルを選択する画面が表示されるので、「参照」ボタンで先ほどダウンロードした
Salesforceのメタデータファイルを選択して、「ファイルのアップロード」ボタンを押します。
![openam1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/6fa48406-f0b0-4636-ab63-b6878c88c167.png)


トラストサークルはIdPを作成したときのトラストサークルを選択して、右上の「設定」ボタンを押します。
完了画面が表示されたら「了解」ボタンを押します。
![openam2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/86cdbe5f-77a4-4daf-8608-4897a932a1aa.png)

上部のタブから[連携]のリンクを押すと、[エンティティープロバイダ]の欄に追加したSPのエントリが表示されています。
![openam3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/5e98082a-d19b-4c59-9842-4b5d4f4f0e33.png)

[エンティティープロバイダ]欄の追加したSaleseforceエンティティのリンクを押すとリモートSPに関する詳細なパラメータを変更することが出来ます。
![openam4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/d7a75d2c-902b-44a5-8528-509cd558e5ad.png)

「表明コンテンツ」タブでNameID値マップを変更します。
NameID値マップの新しい値に「`urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified=mail`」を入力して追加ボタンを押してください。
また、「Disable NameID persistence」にチェックを入れます。
最後に先頭右上にある保存ボタンを押してください。
![openam5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/1bc3be46-c113-4c9d-93a0-f7a345003149.png)

Salesforceのシングルサインオン設定で[SAML IDの場所]を「ID は、Subject ステートメントの NameIdentifier 要素にあります」としていました。
NameIDで値を受け渡すことになっています。
また、[SAML ID種別]を「アサーションには、ユーザーの Salesforce ユーザー名が含まれます」としていました。
私のSalesforceアカウントの設定ではユーザー名はメールアドレスとなっています。
そのため、OpenAMデータストアのmail属性をマッピングしています。
「Disable NameID persistence」の設定はNameID値を保存せず都度生成するという変更をしました。

これでOpenAMの設定は完了です。
第1回と同様にデータストアにはOpenLDAPを設定してあり、データストア認証モジュールでIDパスワード認証をしてログインします。

# いよいよ、動作確認

一度ブラウザを開きなおして管理者ユーザーのセッションを削除してください。
Salseforceの私のドメインで設定したURLを表示します。
https\://kurotsu-***.my.salesforce.com
![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/2f3f16c7-bd33-4d7d-a34e-84625f0012b3.png)

私のドメインの認証サービスでSSOを追加したことにより、
ログインフォームの下部に「次を使用してログイン SSO」というボタンが表示されます。
ここからシングルサインオンが出来ますが、SP(Salseforce)から起点となるフローであることから、
「SP initiated SSO」と呼ばれています。

このボタンを押すとOpenAMのログイン画面が表示されます。
![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/064c720b-c56d-4c8c-b66d-497a6b6e51ee.png)

データストアに存在するユーザーでログインします。
すると、Salseforceのログイン後の画面が表示されます。
![test3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/39a7cbe6-acb9-4a5f-9554-e9cc0143aed3.png)

次に「IdP initiated SSO」を試してみましょう。
IdP(OpenAM)を起点にするにはOpenAMで用意されているURLを直接ブラウザに入力します。
書式は以下になります。

https://(OpenAMのユーザーアクセスFQDN)/openam/idpssoinit?metaAlias=(ホストIdPのメタエイリアス)&spEntityID=(SPのエンティティID)&binding=(バインディング方法)&NameIDFormat=(指定するNameIDフォーマット)&RelayState=(連携後の遷移先URL)

metaAliasで指定する値はOpenAMの管理コンソールで連携に追加されているホストIdP設定の「サービス」タブで確認できます。
bindingで指定する値は連携に追加されているSalseforceのエンティティの「サービス」タブにある表明コンシューマサービスで既定されているタイプの中から選択できます。

必要最小限では下記URLで試してみてください。
`https://sso.qiita.osstech.co.jp/openam/idpssoinit?metaAlias=/usr/idp&spEntityID=https://kurotsu-***.my.salesforce.com`

フルで指定すると以下のようになります。
`https://sso.qiita.osstech.co.jp/openam/idpssoinit?metaAlias=/usr/idp&spEntityID=https://kurotsu-***.my.salesforce.com&binding=urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&NameIDFormat=urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified&RelayState=https://kurotsu-***.lightning.force.com/lightning/setup/ReleaseUpdates/home`

同様にOpenAMのログイン画面からSalseforceに遷移することを確認してください。

## エラーが発生したら
エラーに関しては第1回で紹介した方法を参考にしてください。
今回Salseforce側で発生したエラーに関しての情報を参照するページを確認してみます。

OpenAMのデータストアでログインするユーザーのmail属性をSalseforceのユーザー名と異なる値を設定してエラーを発生させます。
SSOするとSalesforceに以下のようなメッセージが表示されます。
![error1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/6b88c16f-49fc-4029-9826-fa269d35591a.png)

Salseforceに管理者ユーザーでログインして、メニューから[ID]->[シングルサインオン設定]を開き
上部にある「SAMLアサーション検証」ボタンを押してください。
![error2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/89d7908a-b435-4b3c-abf9-024be6974e66.png)

表示された画面にはSAMLレスポンスの検証結果やエラー内容が表示されます。
Subjectに指定されたメール属性がSalseforceのユーザーにマッチしないというメッセージが表示されています。

## 連携する属性の指定方法を変更してみよう
OpenAMのデータストアでログインするユーザーのmail属性をSalseforceのユーザー名と同じ値になるよう設定を戻します。

第1回で利用したSAMLトレーサーでSSOした際と同様にSAMLレスポンスを確認してみましょう。
```
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
                         NameQualifier="https://sso.qiita.osstech.co.jp/openam"
                         SPNameQualifier="https://kurotsu-***.my.salesforce.com"
                         >kurotsu@*****</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData InResponseTo="_2CAAAAZcVVIyAMDAwMDAwMDAwMDAwMDAwAAAA_jdXp21Dx17y6UeWp67lgti6yhOZ35r4AwILkcDmxz42-oPdYReH4nK2bHrfIQpWcrMtutwr1Sogj60wONOVuz3EaZCyerd1Xs8NgR7eNp-F_mdasG11l77Nfd-GdsRQ--Zx1tm2zbWQ44wAhifoItdi5Qo5TLMQfrzivVf9thJOifqo26GgOgr-xnPjOQWCa6aIGpftQSSGvUHSAXjmea3nx_FdLGUNQEldMizPxYf19W3Vp7Jw8rxE1do_x9ED4A"
                                              NotOnOrAfter="2025-04-30T05:29:24Z"
                                              Recipient="https://kurotsu-***.my.salesforce.com"
                                              />
            </saml:SubjectConfirmation>
        </saml:Subject>
```
SAMLレスポンス内に上記のようなSubjectタグが存在します。
これはNameID Formatに「`urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified`」が指定されていて、属性値のマッピングに「kurotsu@*****」とメールアドレスが指定されています。

Salesforceにログインして、メニューから[ID]->[シングルサインオン設定]を開きます。
「SAMLシングルサインオン構成」にあるエントリの編集リンクをクリックします。
![attr1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/098d39fe-e59c-4472-97c9-30d416c27caa.png)

[SAML IDの場所]を「IDはAttribute要素にあります」に変更します。
表示された[属性の名前]に「SF_ID」と指定します。
上部の保存ボタンを押します。

次にOpenAMの管理コンソールにログインします。
連携タブを開き、[エンティティープロバイダ]欄のSaleseforceエンティティのリンクを押します。
表明処理タブを開いて、属性マップの[新しい値]に「SF_ID=mail」と入力して右上の保存ボタンを押します。
[現在の値]に「SF_ID=mail」が追加されていることを確認します。
![attr2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/bfb04d20-e660-44cc-ba71-361ad2761741.png)

表明コンテンツタブを開いて、
NameIDの書式リストにある「`urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified`」を選択して削除します。
NameID値マップにある「`urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified=mail`」を選択して削除します。
「Disable NameID persistence」のチェックを外します。
そのあとに右上の保存ボタンを押します。
NameIDの書式リストとNameID値マップの[現在の値]が空欄になっていることを確認します。
![attr3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316107/d98123bf-5318-4511-92d1-3fa932cdc262.png)

ブラウザを開き直してにSalseforceのマイドメインからSSOを再度試してみてください。
SAMLトレーサーでSAMLレスポンスの違いを確認してみましょう。
```
       <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
                         NameQualifier="https://sso.qiita.osstech.co.jp/openam"
                         SPNameQualifier="https://kurotsu-***.my.salesforce.com"
                         >lGU3Q0slmv11mGmxGjQy7H40e9lJ</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData InResponseTo="_2CAAAAZcVevjHMDAwMDAwMDAwMDAwMDAwAAAA_lgw8DLKPl27-81v7_ooyDLOkYSucF81NE0IYdqHrOOD2cVp9_znTR5lt9VvENKckJEJ3JrWYdz2BBdZsPBhbaWML-1n-yfH76fr90f3j3Zbw4RKbBUnV3dqlus2zVl02do6edLFUHXQCdXkYUlJ1-0NJljxIgBF_YghID9Z13IM3enMA1Kan0JeoKyO1TN6P_AshWP4zFZHTlV5ZYvtwulEGi3oyyuz4MVgby56JszBEYzVo0voopeVkRwf-XuFdg"
                                              NotOnOrAfter="2025-04-30T06:11:19Z"
                                              Recipient="https://kurotsu-***.my.salesforce.com"
                                              />
            </saml:SubjectConfirmation>
        </saml:Subject>
```
SubjectタグはパーシステントIDに変わっています。

```
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="SF_ID">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                     xsi:type="xs:string"
                                     >kurotsu@*****</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
```
AttributeStatementタグに追加したSF_ID=mailの属性値が追加されています。

このように連携属性の方法がSalesforceにはいくつか用意されています。

# おわりに
今回はOpenAMをIdPとして利用して、SalseforceをSPとしてSAML連携の環境構築と実際にテストを実施してみました。
第1回、第2回の環境を同じOpenAMに設定することでオンプレ上のアプリケーションとクラウド上のサービスを１回のログインでどちらも利用可能にすることが出来ます。
実際にあるクラウド上のサービスを利用することで実用的なSSO環境を実感できたのではないでしょうか。