Salesforce(sandbox)にAzure ADでSingleSignonする

# はじめに
Salesforceサンドボックス環境にAzure ADを使ってシングルサインオン設定してみました。とても苦労しました。

「ひとまず動いた」というレベルなのでまだ更新する点があると思いますが、備忘録として書き留めておきます。

# 苦労した点
- 設定の公式ドキュメントが複数ある。
- Azureポータルがクラシックポータルと新ポータルの2種類ある。
- エラーメッセージから原因が特定できない。
- SalesforceもクラシックとLightningExperience（LEX)で2種類ある。

# 設定のコツ
- Azureクラシックポータルでの設定が簡単
- Salesforceもクラシックでの設定が簡単
- 先にSalesforceの__私のドメイン__でユーザー名／パスワード方式のログインができることを確認しておくと楽
  - [SALESFORCE ヘルプ - 私のドメイン](https://help.salesforce.com/articleView?id=domain_name_overview.htm&language=ja&type=0)

一番重要なポイントはAzureとSalesforceでエンティティIDの設定を一致させること。これには2通りのやり方がある。

1. SalesforceのエンティティIDは https://test.salesforce.com にして、Azure側のエンティティIDは設定しない。
2. SalesforceとAzure、それぞれのエンティティIDに 私のドメイン のURLを設定する。

## 参照するドキュメント
Microsoft公式からは3種類のドキュメントが公開されている。

- Azureでアプリケーションのシングルサインオン画面ページ下部にある「Salesforce の構成」をクリックすると表示される手順書。
  - 説明されているのはSalesforceの設定のみでAzure側の設定手順は記載されていない
- [Tutorial: Azure Active Directory integration with Salesforce Sandbox | Microsoft Docs](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-saas-salesforce-sandbox-tutorial)
  - Azureクラシックポータルでの設定手順
  - こっちを参照しながら進めた方が楽
- [チュートリアル: Azure Active Directory と Salesforce の統合 | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/active-directory/active-directory-saas-salesforce-tutorial)
  - Azure新ポータルでの設定手順

ただし、どの手順に従っても__正しく設定できない__[^1] 。それぞれの設定を組み合わせてあげる必要がある。ここハマリポイント。

[^1]: 記述が明らかに間違っているわけでなく、正しい設定ができてから改めて読み直してようやく理解できる 

# 正解の設定

## Salesforce側の設定

| 項目名(日本語)                        | 項目名(英語)                               | 設定する値                                                             | 備考              |
|:--------------------------------------|:-------------------------------------------|:-----------------------------------------------------------------------|:------------------|
| 名前                                  | Name                                       | AzureSSO                                                               | お好きな名前でOK  |
| API参照名                             | API Name                                   | AzureSSO                                                               | 名前と同じでOK    |
| 発行者                                | Issuer                                     | https://sts.windows.net/&lt;ディレクトリID&gt;/                        | Azure側設定時に提示される値を記入 |
| エンティティ ID                       | Entity ID | https://test.salesforce.com    | My Domain名ではないので注意!                                           |                   |
| ユーザプロビジョニングの有効化        | User Provisioning Enabled                  | チェックしない                                                         | ひとまず設定しないでOK。Salesforce Summer '17だと項目の場所がページ下方に移動してます。 |
| IDプロバイダの証明書                  | Identity Provider Certificate              | sfsandbox.cer をアップロード                                           |                   |
| 証明書の署名要求                      | Request Signing Certificate                | SelfSignedCert_xxxxx                                                   | デフォルト値でOK  |
| 署名要求メソッド                      | Request Signature Method                   | RSA-SHA256                                                             | デフォルト値でOK  |
| アサーション復号化証明書              | Assertion Decryption Certificate           |アサーション暗号化なし                                                  |                   |
| SAML ID種別                           | SAML Identity Type                         | アサーションには、ユーザの Salesforce ユーザ名が含まれます(Username)   |                   |
| SAML IDの場所                         | SAML Identity Location                     | ID は、Subject ステートメントの NameIdentifier 要素にあります(Subject) |                   |
| サービスプロバイダーの起動要求バインド| Service Provider Initiated Request Binding | HTTP リダイレクト                                                      |                   |
| IDプロバイダのログインURL             | Identity Provider Login URL                | https://login.microsoftonline.com/&lt;ディレクトリID&gt;/saml2         | Azure側設定時に提示される値を記入 |
| IDプロバイダのログアウトURL           | Identity Provider Logout URL               | https://login.microsoftonline.com/&lt;ディレクトリID&gt;/saml2 [^2]         | Azure側設定時に提示される値を記入 |
| カスタムエラーURL                     | Custom Error URL                           | 空値                                                                   | 入力しなくてOK    |

Active Directory環境固有の設定値については、Azureアプリケーションの「シングルサインオン」画面のページ下部にある__Salesforceの構成__をクリックすると確認することができる（英語文章中に記述されている）。

[^2]: ログアウトURLをAzureで提示されている https://login.microsoftonline.com/common/wsfederation?wa=wsignout1.0 にしても良いが、これだとSalesforceをログアウトするとAzureもログアウトされてしまうので使い勝手が良くない。

## Azure側の設定

| 項目名(日本語)                        | 設定する値                                           | 備考              |
|:--------------------------------------|:-----------------------------------------------------|:------------------|
| シングルサインオン モード             | SAMLベースのサインオン                               |  |
| サインオンURL                         | https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com | __私のドメイン__で設定したURL。__詳細なURL設定__は行わない。 |
| ユーザー属性                          | user.userprincipalname                               | 通常はデフォルト値でOK。ADユーザー名とSalesforceユーザー名が異なる時はSalesforceユーザー名に一致するように調整する。 |
| SAML署名証明書                        | デフォルトのまま                                     | __証明書(未加工)__をダウンロードしてSalesforceの__IDプロバイダの証明書__にアップロードする。 |
| 証明書署名の詳細設定                  | チェックしない                                       | デフォルトのままでOK |

# エラーになる設定

## AADSTS50003: No signing key is configured.

### エラーメッセージ
> AADSTS50003: No signing key is configured.

### 原因
Azure側 SAML 署名証明書の状態が __アクティブ__ になっていない？
※検証中何度か発生したんですが、いま再現できない。再現したら追記します。

### 対処方法
Azureで SAML 署名証明書の状態を __アクティブ__ にする。

## AADSTS70001: Application with identifier 'https://xxxxx.salesforce.com' was not found in the directory &lt;ディレクトリID&gt;

### エラーメッセージ
> AADSTS70001: Application with identifier 'https://xxxxx.my.salesforce.com' was not found in the directory &lt;ディレクトリID&gt;

### 原因
SalesforceのエンティティIDとAzureのエンティティIDが一致していない。

### 対処方法1: 詳細なURL設定をしない場合
- SalesforceのエンティティIDを https://test.salesforce.com にする
- AzureのサインオンURLに __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ を設定する

### 対処方法2: 詳細なURL設定をする場合
- SalesforceのエンティティIDを __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ にする
- AzureのサインオンURLに __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ を設定する
- 詳細なURL設定を表示して識別子に __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ を設定する

## AADSTS70001: Application 'https://mydomain--sandbox.my.salesforce.com' is disabled.

### エラーメッセージ
> AADSTS70001: Application 'https://mydomain--sandbox.my.salesforce.com' is disabled.

### 原因
Azure側のアプリケーションでユーザーのサインインが無効になっている。

### 対処方法
Azure側アプリケーションのプロパティで__ユーザーのサインインが有効になっていますか？__を「はい」にする

## AADSTS65005: Invalid resource.

### エラーメッセージ
> AADSTS65005: Invalid resource. The client has requested access to a resource which is not listed in the requested permissions in the client's application registration. Client app ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Resource value from request: . Resource app ID: 00000002-0000-0000-c000-000000000000. List of valid resources from app registration: .

### 原因
- SalesforceとAzureでエンティティIDが一致していないため
- Azure側の __Entity ID__ が __https://test.salesforce.com__ になっている。
- Azure側のサインオンURLで__詳細な URL 設定の表示__の__識別子(Entity ID)__に値が設定されている。

### 対処方法1: 詳細なURL設定をしない場合
- Azure側で__詳細な URL 設定__は設定しない。
- Azure側の __サインオンURL__ を私のドメイン(__https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com__) に修正する。

### 対処方法2: 詳細なURL設定をする場合
- SalesforceのエンティティIDを __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ にする
- AzureのサインオンURLに __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ を設定する
- 詳細なURL設定を表示して識別子に __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ を設定する

または一度Azure側のアプリケーション設定を削除し、一からやり直すとうまくいくかもしれません。

## AADSTS50105: 

### エラーメッセージ
> AADSTS50105: The signed in user 'user@example.com' is not assigned to a role for the application '&lt;アプリケーションID&gt;'.

### 原因
Azureユーザーにアプリケーションを利用する権限が割り当てられていない

### 対処方法
アプリケーションの「ユーザーとグループ」でユーザーを割り当てる

## Azureのシングルサインオンのページが表示されない（ユーザー／パスワードを聞かれる）

### エラーメッセージ
特になし

### 原因
- Azure側のサインオンURLが私のドメインになっていない。サインオンURLが https://test.salesforce.com になっている。
- Salesforceの「私のドメイン」で設定したシングルサインオン設定(AzureSSO)が認証サービスでチェックされていない。

### 対処方法
- Azure側のサインオンURLを __私のドメイン(https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com)__ にする。
- Salesforceの私のドメイン画面で認証サービスに__AzureSSO__をチェックする。

## Single Sign-On Error
### エラーメッセージ
> We can't log you in. Check for an invalid assertion in the SAML Assertion Validator (available in Single Sign-On Settings) or check the login history for failed logins.

URLは https://https://&lt;mydomain&gt;.&lt;node&gt;.salesforce.com/_nc_external/identity/saml/SamlError 

### 原因
Azureのユーザー識別子とSalesforceのユーザー名が一致しない。

### 対処方法
Azureのユーザー属性情報を調整してSalesforceのユーザー名と一致させる。

#シングル サインオンのテスト

アクセスパネル (https://myapps.microsoft.com) を開いて、テスト アカウントにサインインして [Salesforce (Sandbox)] をクリックします。