まだコロナの影響もなく、騒いでいることのできた昨年末のAdvent Calendarで「Salesforce で外部サービスを使うときには「指定ログイン情報」を使いましょう」と偉そうに書いてから、もう4ヶ月近くが経過します。
確かに「指定ログイン情報」は便利です。Apex
コールアウトするときも、「外部サービス」を利用するときも指定ログイン情報様様です。
しかし、その便利な「指定ログイン情報」も、「認証プロバイダ」があってこそです。いま対応しているプロバイダは次の10個です。
- Apple
- Janrain
- Salesforce
- Open ID Connect
- Microsoft アクセスコントロールサービス
- GitHub
※ 2020/4/20 現在 (Apple増えたね)
これを見て、心穏やかにならないなにかがありませんか?そうです、「認可」として業界標準で最も利用されている「OAuth2.0」がありません。TwitterやFacebookだってOAuthアクセスなのに、なぜ標準的なOAuth2.0は登録されていないのか。Open ID Connect
はあるのに...。
と気が滅入った方。多分仕方ないです。OAuth2.0はその認可の方法が多岐にわたり、一つ一つを登録していく労力やらを考えると、利用者の多いサイトを認証プロバイダとして登録するほうがサービサー的には正しいかもしれません。
しかし、我々は OAuth2.0 で認可されているサイトを外部サービスとして利用したいんです。さて、どうするべきか。
この方法は、われらがデベロッパエヴァンジェリストである@hrk623の書いた「netatmo Weather Station のデータを定期的に Salesforce に取り込んでみた」のように、長い手順を踏んだ上に「カスタム認証プロバイダ」をapex
で記述する必要があります。
なんてこった。
Salesforce はAdmin利用の多いサービスであり、ノーコード・ローコードが売りです。この部分なんとかならんかと思い、ここでわたしは一肌脱いだ次第です(前置きが長い)。
Client Credentials をかんたんに実装しよう
そこで、外部サービスとしてシステム連携を行う際に利用する頻度の高いと思われる「Client Credentials」について、できるだけかんたんに実装できる「ソースコード」を準備しました。しかも、カスタマイズ機能付き。
今日は、こちらの使い方を紹介します。Apexコードの解説は別途。
Client Credential フローって?
先程のauth0サイトのドキュメントが詳しいのですが、事前に認証されて取得した次の2つを利用して(1)、認可用のアクセストークンを発行してもらい(2),(3)、APIサーバへはそのアクセストークンを使ってアクセスする方式(4),(5)です。システム連携用としては、非常に多いパターンです。認証スキーム名としてBearer
を利用する方式ですね。
- Client ID
- Client Secret
※ from https://auth0.com/docs/flows/concepts/client-credentials
使い方
Github 上のソースコードに記載のあるとおりの手順を実行すれば、DevHub内にスクラッチ組織を作成して、そこへ「Client Credentials」用のカスタム外部認証プロバイダを登録します。
流石に投げっぱなしすぎるので、一つずつ手順と注意事項を記載しておきます。
前提条件
- 組織でDevHubを利用可能としている (その他の環境へDeployする場合は不要です)
- Salesforce CLI をインストールしていること
- git コマンドが利用できること
ソースコードを準備します
Githubのソースコードを、git clone
して入手します。
git clone https://github.com/sho7650/clientCredentialsAuthProvider.git
cd ./clientCredentialsAuthProvider
ls -latr
すると、こんな感じのディレクトリ構成になっていれば問題なしです。
$ ls -latr
total 56
drwxr-xr-x 3 sho staff 96 Apr 20 10:40 ../
-rwxr-xr-x 1 sho staff 349 Apr 20 10:40 .forceignore*
-rwxr-xr-x 1 sho staff 597 Apr 20 10:40 .gitignore*
-rwxr-xr-x 1 sho staff 155 Apr 20 10:40 .prettierignore*
-rwxr-xr-x 1 sho staff 228 Apr 20 10:40 .prettierrc*
-rwxr-xr-x 1 sho staff 4206 Apr 20 10:40 README.md*
drwxr-xr-x 4 sho staff 128 Apr 20 10:40 bin/
drwxr-xr-x 3 sho staff 96 Apr 20 10:40 config/
drwxr-xr-x 4 sho staff 128 Apr 20 10:40 force-app/
drwxr-xr-x 3 sho staff 96 Apr 20 10:40 manifest/
-rwxr-xr-x 1 sho staff 193 Apr 20 10:40 sfdx-project.json*
drwxr-xr-x 12 sho staff 384 Apr 20 10:40 .git/
drwxr-xr-x 14 sho staff 448 Apr 20 10:41 ./
drwxr-xr-x 5 sho staff 160 Apr 20 10:44 .sfdx/
Salesforce 組織の認証
DevHub を利用する場合は次のとおりに行います。
- ... 使用するDevHubのエイリアス(別名)をつけます。使いやすいようにです
- ... deploy先のスクラッチ組織のエイリアス(別名)をつけます。同じく使いやすくするためです
sfdx force:auth:web:login -d -a <alias your DevHub>
sfdx force:org:create -s -f config/project-scratch-def.json -a <alias your scratch Org>
sfdx force:auth:web:login
すると Salesforce組織へWebベースフローで認証するため、Salesforce のログインが出てきます。ここでDevHub
のある組織へログインします。次の sfdx force:org:create
コマンドにてスクラッチ組織を作成します。
もしここで、スクラッチ組織ではなくログイン先のDevloper、Sandbox、本番環境へdeployする場合にはスクラッチ組織を作らなければdeploy可能です(多分)。
ソースコードのpushとテスト
では、手元にあるソースコードを Salesforce へ push
(アップロード) しましょう。
sfdx force:source:push
何事もなければ、次のようにファイルがすべて登録されます。
=== Pushed Source
STATE FULL NAME TYPE PROJECT PATH
───── ───────────────────────────────────────────────────────────────── ───────────────── ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Add ClientCredentials AuthProvider force-app/main/default/authproviders/ClientCredentials.authprovider-meta.xml
Add ClientCredentialsAuthProvider ApexClass force-app/main/default/classes/ClientCredentialsAuthProvider.cls
Add ClientCredentialsAuthProvider ApexClass force-app/main/default/classes/ClientCredentialsAuthProvider.cls-meta.xml
Add ClientCredentials_Metadata.ClientCredentials CustomMetadata force-app/main/default/customMetadata/ClientCredentials_Metadata.ClientCredentials.md-meta.xml
Add ClientCredentials_Metadata__mdt-ClientCredentials_Metadata Layout Layout force-app/main/default/layouts/ClientCredentials_Metadata__mdt-ClientCredentials_Metadata Layout.layout-meta.xml
Add ClientCredentials NamedCredential force-app/main/default/namedCredentials/ClientCredentials.namedCredential-meta.xml
Add ClientCredentials_Metadata__mdt CustomObject force-app/main/default/objects/ClientCredentials_Metadata__mdt/ClientCredentials_Metadata__mdt.object-meta.xml
Add ClientCredentials_Metadata__mdt.Access_Token_URL__c CustomField force-app/main/default/objects/ClientCredentials_Metadata__mdt/fields/Access_Token_URL__c.field-meta.xml
Add ClientCredentials_Metadata__mdt.Auth_Provider__c CustomField force-app/main/default/objects/ClientCredentials_Metadata__mdt/fields/Auth_Provider__c.field-meta.xml
Add ClientCredentials_Metadata__mdt.Client_ID__c CustomField force-app/main/default/objects/ClientCredentials_Metadata__mdt/fields/Client_ID__c.field-meta.xml
Add ClientCredentials_Metadata__mdt.Client_Secret__c CustomField force-app/main/default/objects/ClientCredentials_Metadata__mdt/fields/Client_Secret__c.field-meta.xml
Add ClientCredentials_Metadata__mdt.User_Name__c CustomField force-app/main/default/objects/ClientCredentials_Metadata__mdt/fields/User_Name__c.field-meta.xml
Add clientCredentials RemoteSiteSetting force-app/main/default/remoteSiteSettings/clientCredentials.remoteSite-meta.xml
Add ClientCredentialsAuthProviderTest ApexClass force-app/test/default/classes/ClientCredentialsAuthProviderTest.cls
Add ClientCredentialsAuthProviderTest ApexClass force-app/test/default/classes/ClientCredentialsAuthProviderTest.cls-meta.xml
無事に登録された場合には、テストも可能です。テストコードも実行してみましょう。
sfdx force:apex:test:run --tests ClientCredentialsAuthProviderTest --resultformat human --outputdir .sfdx/tools/testresults/apex --loglevel error --codecoverage
全体で6つのテストケースがありますので、問題がなければすべて次のように全てパスします。
=== Test Reports
FORMAT FILE
────── ──────────────────────────────────────────────────────────────────
txt .sfdx/tools/testresults/apex/test-result.txt
txt .sfdx/tools/testresults/apex/test-run-id.txt
junit .sfdx/tools/testresults/apex/test-result-7075D000018Sj4b-junit.xml
json .sfdx/tools/testresults/apex/test-result-7075D000018Sj4b.json
json .sfdx/tools/testresults/apex/test-result-codecoverage.json
=== Apex Code Coverage
ID NAME % COVERED UNCOVERED LINES
────────────────── ───────────────────────────── ───────── ───────────────
01p5D0000013JboQAE ClientCredentialsAuthProvider 100%
=== Test Results
TEST NAME OUTCOME MESSAGE RUNTIME (MS)
─────────────────────────────────────────────────────────── ─────── ─────── ────────────
ClientCredentialsAuthProviderTest.getCustomMetadataTypeTest Pass 23
ClientCredentialsAuthProviderTest.getUserInfoTest Pass 6
ClientCredentialsAuthProviderTest.handleCallbackErrorTest Pass 6
ClientCredentialsAuthProviderTest.handleCallbackTest Pass 5
ClientCredentialsAuthProviderTest.initiateTest Pass 5
ClientCredentialsAuthProviderTest.refreshTest Pass 5
=== Test Summary
NAME VALUE
─────────────────── ──────────────────────────────────────────────────────────
Outcome Passed
Tests Ran 6
Passing 6
Failing 0
Skipped 0
Pass Rate 100%
Fail Rate 0%
Test Start Time Apr 20, 2020 10:44 AM
Test Execution Time 50 ms
Test Total Time 50 ms
Command Time 1783 ms
Hostname https://java-business-3629-dev-ed.cs72.my.salesforce.com/
Org Id 00D5D000000DRVEUA4
Username test-clientcredentials@example.com
Test Run Id 7075D000018Sj4b
User Id 0055D000003BGPDQA4
Test Run Coverage 100%
Org Wide Coverage 100%
これで、コードは登録できましたので、あとは次の2つを相手の認証・認可サーバに必要な設定を行えば設定完了です。
どうせなら、カスタマイズしたままdeployしたい
そうでしょう。そうでしょう。どうせなら、コードをpush
した時にすべての構成が反映している方が望ましいです。分かります、その気持ち。
はい、準備しました。次のコマンドを実行するだけです。
./bin/config.sh <your config>
※ macOSかLinuxで実行すること。WindowsユーザはWSL上で実行してください
とは言え、このままだと何も起きません、残念な結果になります。まずは設定ファイルを準備しましょう。
次のようなファイルを作成します。.config
というファイル名にすれば設定ファイル名を指定しなくとも自動的に読み込みます。
ENDPOINT='https://test.example.com'
EXECUTION_USER='test@example.com'
REMOTE_SITE_URL='https://api.example.com'
ACCESS_TOKEN_URL='https://example.com/token'
CLIENT_ID='client_id'
CLIENT_SECRET='client_secret'
環境変数名 | 内容 | デフォルト値 |
---|---|---|
ENDPOINT | 指定ログイン情報で指定するコールアウト先のエンドポイント | https://test.example.com |
EXECUTION_USER | 認証プロバイダに登録される実行ユーザ名。実際に登録されているシステムユーザを指定しましょう | test-clientcredentials@example.com |
REMOTE_SITE_URL | リモートサイトへ登録するリモートサイトのホスト名 | https://api.example.com |
ACCESS_TOKEN_URL | カスタムメタデータ型に登録されているアクセストークンを発行するリモートサイトのURL | https://example.com/token |
CLIENT_ID |
カスタムメタデータ型 に登録されている、外部サービスから発行された Client_ID
|
client_id |
CLIENT_SECRET |
カスタムメタデータ型に登録されている、外部サービスから発行されたClient_SECRET
|
client_secret |
これらを指定したファイルを準備して、./bin/config.sh
を実行すると該当のソースコード部分が全て置き換わります。書き換え後の情報は機密情報になるので、そのまま github
などのオープンリポジトリへはpush
しないように気をつけましょう。
それでは、より良いハック人生を。