SFDCをIdP, LINE WORKSをSPにして SAMLで認証連携させてみた

#SFDCをIdP, LINE WORKSをSPにして SAMLで認証連携させてみた

クラウドベースの CRM・SFA サービス **SFDC（セールスフォース・ドットコム）** と、ビジネス版LINEの **LINE WORKS** が共に SAML のSPもIdPもサポートしているということで、接続実験してみました:grinning::grinning:

![SFDC_SAML_LW.png](https://qiita-image-store.s3.amazonaws.com/0/246440/7334a09e-7eb4-fab5-3ec7-977266d4681d.png)


今回試すのは、SFDCをIdP、LINE WORKSをSPとした認証連携です:bangbang:
では、早速どのように設定したか＆動作についてを見ていきましょう。

##SFDC側の設定

まずはIdPとして動作させる、SFDC側の設定から行います。
管理者のアカウントでSFDC（ https://www.salesforce.com/jp/ ）にログインして作業してください。

###設定画面を開く
SFDCにログインした後、右上の歯車マークをクリック、「設定」を選択します。

![SFDC_設定-1.png](https://qiita-image-store.s3.amazonaws.com/0/246440/1ad34ff4-fdb1-4793-4b58-7225b82e963e.png)

###マイドメインを登録する
設定画面が開けたら「会社の設定」＞「私のドメイン」の項目を選択します。
下の図は、「私のドメイン」の設定が完了している画面になりますが、設定が完了していない場合、手順が表示されますので説明に従って、ドメイン登録を行ってください。

![SFDC_設定-2.png](https://qiita-image-store.s3.amazonaws.com/0/246440/15509e51-1573-3fa9-b00a-745daaba3273.png)

設定が完了しても、登録完了までは数分ほど時間がかかります。
下記のようなメールが届いたら、登録完了なので気長に待ちましょう:exclamation:

![SFDC_設定-4.png](https://qiita-image-store.s3.amazonaws.com/0/246440/9837e826-0b42-d28a-f1b2-d6f738b54727.png)

###IdPの設定を確認して必要な情報をDLする
マイドメインの登録が完了したら、設定画面の「ID」＞「IDプロバイダ」に移動します。IdPの設定情報はここにあるので覚えておきましょう。

![SFDC_設定-3.png](https://qiita-image-store.s3.amazonaws.com/0/246440/0d5b4103-4ca9-5b68-ec46-c6e99488096d.png)

LINE WORKS側の設定に必要な情報をDLします。

- 「証明書のダウンロード」で証明書をDL
- 「メタデータのダウンロード」でメタデータをDL

###接続アプリ（LINE WORKS）を登録する

続いて接続アプリ（LINE WORKS）の登録を行います。
先ほどの「IDプロバイダ」の設定画面に、「サービスプロバイダ」の項目があります。その隣に「接続アプリケーションでサービスプロバイダを作成する」のような文言のリンクが表示されていると思いますので、そちらをクリックします。（下図は作成済みの状態のため「サービスプロバイダが作成されました。」となっています。）

![SFDC_設定-5.png](https://qiita-image-store.s3.amazonaws.com/0/246440/f1b216b5-78e8-8640-f865-7fc0c289b2ee.png)

すると、新規接続アプリケーションの設定画面が表示されるため、「基本情報」の必須項目を埋めます。これだけではSAMLの設定が何もされていないので、「Webアプリケーション設定」＞「SAMLの有効化」のチェックボックスをONにして、SAMLの設定項目を表示します。

![SFDC_設定-6.png](https://qiita-image-store.s3.amazonaws.com/0/246440/319be0fa-0d52-0f1c-b131-ea00a0d1914a.png)

SAMLの設定項目が表示されたら、下記の通り入力してください。

![SFDC_設定-7.png](https://qiita-image-store.s3.amazonaws.com/0/246440/8a6199d6-7946-6966-d95f-899143f082d7.png)

|No.| 項目 | 内容 | 備考 |
|:--:|:----------:|:----------|:---------------|
| 1 | 開始URL | http://mail.worksmobile.com/ | メールのトップ画面を登録したが他でもOK |
|2| SAMLの有効化 | チェックON | |
|3| エンティティID | worksmobile.com | 全てのドメインで共通の値 |
|4| ACS URL | https://auth.worksmobile.com/acs/[LINEWORKSで利用しているドメイン名] | |
|5| シングルログアウトを有効化 | チェックOFFのまま | チェックONにしてもOK |
|6| 件名種別 | 「統合ID」を選択 | 他を選択した場合の設定方法については省略 |
|7| 名前IDの形式 | `urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified` | LINE WORKSの仕様に従う |
|8| 発行者 | https://sami.my.salesforce.com | マイドメインで既に入力されているのでそのまま |
|9| IdP証明書 | SelfSignedCert_DDmmYYYY_XXXXXX | IdPの設定画面でDLしたものを選択する |
|10| 要求署名を確認 | チェックOFFのまま | LINE WORKSはRequestに署名付さない |
|11| SAMLレスポンスを暗号化 | チェックOFFのまま | LINE WORKSは暗号レスポンスを復号しない |

- なお、LINE WORKSのドキュメントには必要な記述は存在しなかったので、LINE WORKSが送信しているAuthnRequestを解析して取得しました:sweat_smile::sweat_smile:

一応、LINE WORKS側のドキュメントは下記です。

>SAML 2.0基盤のSSO連携のためのクライアント実装項目
>https://developers.worksmobile.com/jp/document/1001003

###対象ユーザに接続アプリの利用を許可する

「ユーザ」＞「ユーザ」から対象ユーザを選択し「プロファイル」の項目（ここでは「システム管理者」）をクリックします。

![SFDC_設定-8.png](https://qiita-image-store.s3.amazonaws.com/0/246440/e379e967-6f75-7bcf-e1a7-5f6d3aeb8dfd.png)

「プロファイル」の設定が画面が表示されるので「編集」を押下して、編集できる状態にします。

![SFDC_設定-9.png](https://qiita-image-store.s3.amazonaws.com/0/246440/5467c3ed-4086-7aaa-4bdc-94ec1193eb39.png)

「接続アプリケーションへのアクセス」の項目に「LINE_WORKS」があるので、チェックボックスをONにして、「保存」します。

![SFDC_設定-10.png](https://qiita-image-store.s3.amazonaws.com/0/246440/aeb6b16b-e94f-27c7-b530-26dd254d4da4.png)

###対象ユーザの統合IDを登録する

「ユーザ」＞「ユーザ」から対象ユーザを選択し、「編集」を押下して編集できる状態にします。

![SFDC_設定-8.png](https://qiita-image-store.s3.amazonaws.com/0/246440/5a939b32-023f-e138-e63c-ecab06f38e5a.png)

「シングルサインオン設定」の項目に「統合ID」があるので、適当な値を入力します。（LINE WORKS側で、`External Key`として登録する値になります。）

![SFDC_設定-11.png](https://qiita-image-store.s3.amazonaws.com/0/246440/79732652-c6af-337c-1e4f-7efe94c7b605.png)

「保存」して、SFDC側の設定は完了:clap::clap::clap:


##LINE WORKS側の設定

続いてSPとして動作させる、LINE WORLS側の設定を行います。
DeveloperのアカウントでLINE WORKS Developer Console( https://developers.worksmobile.com/jp/console/ )にログインして行ってください。

###SSO設定

Developer Console画面の「SSO」＞「SSO Type」で「SAML」を選択し、それぞれ下記の通り設定します。

![LW_設定-1.png](https://qiita-image-store.s3.amazonaws.com/0/246440/b9ee1007-e3df-9d65-a665-f93379908426.png)

|No.| 項目 | 内容 | 備考 |
|:--:|:----------:|:----------|:---------------|
|1| Web Login URL | ※1 | 表下部参照 |
|2| Layer Popup Login URL | 修正/入力なしでOK | |
|3| Application Login URL | 修正/入力なしでOK | |
|4| IMAP/CalDAV Login API | 修正/入力なしでOK | |
|5| Logout URL | ※2 | 表下部参照 |
|6| Certificate File | DLしたSFDCの証明書ファイル※3 |  |

※1 DLしたSFDCメタデータ中、Binding属性が`urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` であるSingleSignOnService要素のLocation属性の値。
※2 DLしたSFDCメタデータ中、Binding属性が`urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` であるSingleLogoutService要素のLocation属性の値。
※3 DLした証明書ファイルの拡張子は`.crt`となっているので、`.pem`と書き換えたもの（ファイルの拡張子を変えるだけでOK）

```xml:【参考】SFDCのメタデータ
<?xml version=“1.0” encoding=“UTF-8”?>
<md:EntityDescriptor xmlns:md=“urn:oasis:names:tc:SAML:2.0:metadata”
 entityID=“https://sami.my.salesforce.com”
 validUntil=“2028-03-23T08:01:22.771Z”
 xmlns:ds=“http://www.w3.org/2000/09/xmldsig#”> 
  <md:IDPSSODescriptor protocolSupportEnumeration=“urn:oasis:names:tc:SAML:2.0:protocol”>
    <md:KeyDescriptor use=“signing”>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>...</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:SingleLogoutService 
     Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
     Location="https://sami.my.salesforce.com/services/auth/idp/saml2/logout"/>
    <md:SingleLogoutService
     Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
     Location="https://sami.my.salesforce.com/services/auth/idp/saml2/logout"/>
    <md:NameIDFormat>
        urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
    </md:NameIDFormat>
    <md:SingleSignOnService
     Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
     Location="https://sami.my.salesforce.com/idp/endpoint/HttpPost"/>
    <md:SingleSignOnService
     Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
     Location="https://sami.my.salesforce.com/idp/endpoint/HttpRedirect"/>
  </md:IDPSSODescriptor>
</md:EntityDescriptor>
```

最後に、「適用」を押下して、設定完了。

###External Keyの設定

SSOを行う対象ユーザのExternanl Keyを設定します。
Developer Console画面の「SSO」＞「構成員 External Key Mapping」で、対象ユーザのメールアドレス（ログインID）とSFDCで統合IDに登録した値をマッピングしたCSVファイルをアップロードします。

![LW_設定-2.png](https://qiita-image-store.s3.amazonaws.com/0/246440/b53cf953-58fa-ca5a-bbd8-1f345d3e0acc.png)

CSVファイルの内容はこんなかんじで。

```csv:ExternalKey.csv
"Mail Address","External Key"
"sami@sami.sample.com.","sami"
"taro@sami.sample.com","taro"
```

![LW_設定-3.png](https://qiita-image-store.s3.amazonaws.com/0/246440/1aa7bd78-99e6-db01-20e0-aec04faa12bd.png)

アップロードが成功したら、External Keyの設定も完了。
LINE WORKS側の設定も完了です。:clap::clap::clap:

##動かしてみる

ということで、早速動かしてみたいと思います。
動かしてみるシーケンスは、ざっくりこんなかんじ。


![SSOシーケンス.png](https://qiita-image-store.s3.amazonaws.com/0/246440/cf29e067-fb7f-6943-c34a-38d5115b3c39.png)




ということでまず LINE WORKS にアクセスします。
[LINE WORKS] https://mail.worksmobile.com/

すると早速AuthnRequestが送付されています。

リクエスト内容

```
GET /idp/endpoint/HttpRedirect?SAMLRequest=fZLLb...9icE3&RelayState=...&worksId=sami@sami.sample.com HTTP/1.1
Host: sami.my.salesforce.com
```

AuthnRequestの中身はこんな感じでした。

```xml:AuthnRequest
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" 
 AssertionConsumerServiceURL="https://auth.worksmobile.com/acs/sami.sample.com"
 ID="ohhfjgfhmcjmhgobdoogdpggkgpmmjjojgoihmoo"
 IssueInstant="2018-04-12T04:45:44.212Z" 
 ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" 
 ProviderName="worksmobile.com"
 Version="2.0">
  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
      worksmobile.com
  </saml2:Issuer>
  <saml2p:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>
</saml2p:AuthnRequest>
```

すると、おお:bangbang:
SFDCのログイン画面が表示されました:v::v:

![SFDC_ログイン画面.png](https://qiita-image-store.s3.amazonaws.com/0/246440/a2ffec40-69ff-28fb-267f-fd09b19123fd.png)

「ログイン」ボタンを押下すると、AuthnResponseが返却されます。

レスポンス内容

```
POST /acs/sami.sample.com HTTP/1.1
Host: auth.worksmobile.com
 
RelayState=...&SAMLResponse=PD94b...T4%3D
```

AuthnResponseの中身はこんな感じでした。

```xml:AuthnResponse
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
 Destination="https://auth.worksmobile.com/acs/sami.sample.com" 
 ID="_b896ada187ab0081098dfa4db9eb9c381523508344601" 
 InResponseTo="ohhfjgfhmcjmhgobdoogdpggkgpmmjjojgoihmoo"
 IssueInstant="2018-04-12T04:45:44.601Z" Version="2.0">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
   Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
      https://sami.my.salesforce.com
  </saml:Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <ds:Reference URI="#_b896ada187ab0081098dfa4db9eb9c381523508344601">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> 
            <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="ds saml samlp xs xsi"/>
          </ds:Transform>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue>RTsRR...wKCw=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>WSPvM...Xhw==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data> 
        <ds:X509Certificate>MIIEr...GS2LU</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> 
  </samlp:Status>
  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
   ID="_a127072ac7acf6c73248a2709da105c21523508344602"
   IssueInstant="2018-04-12T04:45:44.602Z" Version="2.0">
    <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
        https://sami.my.salesforce.com
    </saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
        <ds:Reference URI="#_a127072ac7acf6c73248a2709da105c21523508344602">
          <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> 
              <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="ds saml xs xsi"/>
            </ds:Transform>
          </ds:Transforms>
          <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
          <ds:DigestValue>BnW5P...YqIc=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>ANpUn...VDw==</ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MIIEr...GS2LU</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">sami</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="ohhfjgfhmcjmhgobdoogdpggkgpmmjjojgoihmoo"
         NotOnOrAfter="2018-04-12T04:50:44.602Z"
         Recipient="https://auth.worksmobile.com/acs/red.wmjsales.xyz"/> 
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2018-04-12T04:45:14.602Z"
     NotOnOrAfter="2018-04-12T04:50:44.602Z">
      <saml:AudienceRestriction>
        <saml:Audience>worksmobile.com</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2018-04-12T04:45:44.602Z">
       <saml:AuthnContext> 
         <saml:AuthnContextClassRef>
             urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
         </saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="userId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"> 
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:type="xs:anyType">005...WZW</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="username" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:type="xs:anyType">xxxxxxxx</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:type="xs:anyType">xxxx.xxxx@xxxx.com</saml:AttributeValue> 
      </saml:Attribute>
      <saml:Attribute Name="is_portal_user" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:type="xs:anyType">false</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>
```

SFDCのAuthnResponseって、AuthnStatementだけじゃなくてAttributeStatementも含んでるんですね。

そして最後はきちんとLINE WORKSログイン後の画面が表示されました。

![LW_メール画面.png](https://qiita-image-store.s3.amazonaws.com/0/246440/cf158c2a-1eda-4afb-0e25-5db2f2c81921.png)

おしまい:hugging::hugging::hugging::hugging::hugging:


##おわりに

設定して、SSOできました、って、すんなり行ったように見えてますが、そうでもなかったです・・・。
とにかく、LINE WORKSが出すエラーメッセージは正しくなくて振り回されるので、SFDC側のログを見て詳細確認したほうが良いですよ。

設定画面の「ID」＞「IDプロバイダイベントログ」でSFDC側の詳細ログは見れます:sparkles::sparkles:

でわでわ。気が向いたら逆も試して見ます:wave::wave: