見出し画像

指定ログイン情報を理解する


はじめに

こんにちは荒武です。
この記事では、Salesforceの指定ログイン情報の仕組みやユースケースについて解説します。
想定する読者は、以下のようになっています。

  • 指定ログイン情報とはそもそもなんぞや、という方

  • 指定ログイン情報のドキュメントを読んでいて「外部ログイン情報とかプリンシパルって何のためにあるんだったっけ?」となる方

  • OAuth 2.0の基本的な流れを理解している方(本記事ではOAuth 2.0を用いた指定ログイン情報の利用についての記述がありますが、OAuth 2.0そのものの詳細な解説は行っておりません)

また、この記事は、指定ログイン情報のディテールを深く掘り下げるというよりかは、全体像を理解することを目的としています。

指定ログイン情報とは

この章では指定ログイン情報とは何なのかを説明します。指定ログイン情報(英:Named Credential)とは何なのかをざっくり一言で表すと「HTTPコールアウトを行うURLとその時に用いる認証情報をまとめたもの」になります。そして指定ログイン情報を用いれば認証プロトコルに応じた実装や、認証トークンの保存を行う必要がなくなります。
例えば、Google Calendar APIを呼び出す必要があるとします。APIの呼び出しにはOAuth 2.0プロトコルを用いるので、以下のようなものを実装する必要があります。

  • アクセストークンの取得

  • アクセストークンの保存

  • アクセストークンのリフレッシュ

  • リモートサイト設定

  • etc…

これらを自分で実装するのは大変ですし、特にアクセストークン等の機密データは取り扱いに注意が必要になってきます(できれば触りたくない)。指定ログイン情報はこれらの面倒をまるっとみてくれるので、ビジネスロジックに注力することができます。うれしいですね。
加えて、指定ログイン情報はOAuth 2.0だけでなく様々な認証プロトコルに対応しており、以下のような認証プロトコルが利用可能となっています。

  • Basic認証

  • OAuth 2.0

  • AWS SigV4 署名

  • JWT

  • カスタム(任意の認証パラメータを設定し、独自の認証プロトコルを定義できる)

  • 認証なし

また、指定ログイン情報の利用は現在、以下の機能でサポートされています

  • Apexコールアウト

  • 外部データソース

  • 外部サービス

例えば外部サービスはフローからの呼び出しができるので、指定ログイン情報と組み合わせれば文字通りノーコードでの認証が必要なAPIの利用が可能になります。

指定ログイン情報に登場する要素

この章では指定ログイン情報の全容を把握するために指定ログイン情報を構成する要素について解説します。指定ログイン情報は複数の要素から構成されており、以下の要素が存在します。

  • 外部ログイン情報(英:External Credential)

  • プリンシパル(英:Principal)

  • ユーザー外部ログイン情報(英:User External Credential)

  • 指定ログイン情報(英:Named Credential)

以下の画像はSalesforceの中の人が書いた記事から引用したもので指定ログイン情報の全体図を表した図になります。この章を読み終わった後にもう一度この画像を見てみるとそれぞれの要素の関係性の理解が深まると思います。

https://unofficialsf.com/understanding-named-credentials/ より引用

外部ログイン情報(英:External Credential)

外部ログイン情報は認証プロトコル、特定のプロトコルの認証を行うために必要な属性といった、どのように認証を行うかの詳細を定義するためのものです。指定ログイン情報とは「HTTPコールアウトを行うURLとその時に用いる認証情報をまとめたもの」とはじめに説明したのですが、この「認証情報をまとめたもの」 が外部ログイン情報にあたります。
例えばOAuth 2.0をプロトコルとして指定したら、OAuth 2.0のフローやスコープを設定することができます。
指定ログイン情報を用いるためには、まずこの外部ログイン情報を設定する必要があります。

プリンシパル(英:Principal)

プリンシパルは権限セットやプロファイルと外部ログイン情報をマッピングするためのもので、コールアウト実行者の外部サービス上でのアイデンティティを表します。アイデンティは実在するユーザー(人間)やバッチ処理等を実行するための実在しないユーザーにもなりえます。(ex.GCPでいうところのサービスアカウント等)。そして外部ログイン情報を参照するためにはその外部ログイン情報に紐づいたプリンシパルへの参照権限が必要となります。
例えば、OAuth 2.0をプロトコルとして利用する場合、外部ログイン情報に紐づくプリンシパル(アイデンティティ)を「外部サービス上で更新操作が可能なユーザー」と「参照のみ可能なユーザー」のように区別して用意します。それらに対して適切なスコープを設定し、異なる権限セットに関連付けることで、Salesforceユーザーごとに外部サービス上で許可される操作範囲を調整することが可能となります。また、ユーザーが複数のプリンシパルに対して参照権限を持っていた場合は連番という項目が一番小さいプリンシパルが適用されます。
加えて、プリンシパルには以下の2種類があります。

  • ユーザーごとのプリンシパル(英:Per User Principal)

  • 指定プリンシパル(英:Named Principal)

ユーザーごとのプリンシパルはAPI呼び出しを行うユーザー単位で認証情報を持ちたい場合に用いるためのもので、
指定プリンシパルはどのユーザーがAPIを呼び出したとしても、同じ認証設定を参照できるよう(使い回せるよう)にするものです。

ユーザー外部ログイン情報(英:User External Credential)

ユーザー外部ログイン情報は外部ログイン情報がコールアウトを行う際に参照する暗号化されたトークンが格納されているオブジェクトです。

指定ログイン情報(英:Named Credential)

呼び出し先エンドポイントのURLとコールアウトに用いる認証パラメータ(外部ログイン情報)を1つの定義にまとめたものです。

Google Calendar APIを用いた例

この章では、Google Calendar APIを使い、APIを呼び出したユーザーのカレンダーリストを取得するための指定ログイン情報を作成する例を示します。
* GoogleのAPIの細かい仕様については省略します。気になる方は以下を参考にされてください。

それぞれの設定値をまとめた全体像は以下の画像になります。以降の項でそれぞれの解説をします。

全体図

外部ログイン情報

この外部ログイン情報はOAuth 2.0のJWTベアラーフローでカレンダーリストの取得に必要なアクセストークンを取得するためのものです。
コールアウト実行ユーザーの項目がJWT Claimで参照できるので、UserオブジェクトにGoogleEmail__cというカスタム項目を作成し、subに指定しています。これによりログインユーザーが自身のリソースを参照できるようになります。

OAuth 2.0の設定値
JWTクレームの設定値

プリンシパル

ユーザー単位でGoogle Calendar APIを呼び出すので、種別を「ユーザーごとのプリンシパル」にしています。

プリンシパルの設定値

参考までに、Google Calendar APIで種別を「指定プリンシパル」に設定するケースとして、組織全体で取得する必要があるカレンダーが単一のGoogle Workspaceユーザーのものだけである場合が挙げられます。この場合、JWTのClaimにあるsubを取得したいGoogle WorkspaceユーザーのIDに設定し、プリンシパルを「指定プリンシパル」にすることで対応できます。

権限セット

作成したプリンシパル(Google Calendar User)にアクセスできるように、参照権限を付与しています。「外部ログイン情報プリンシパルアクセス」の項から設定します。コールアウトを実行するユーザーにこの権限を付与する想定です。

権限セットの設定値

指定ログイン情報

カレンダーリスト取得のURLに対して、外部ログイン情報を対応付けています。
今回はフルパスをURLに指定していますが、指定ログイン情報はコールアウト実行時にパスを渡すことができます。したがって今回のケースであればURLをhttps://www.googleapis.com/calendar/v3のみにしてパスに/users/me/calendarListを渡すようにすることも可能です。

指定ログイン情報の設定値

Apexで実行

実際に指定ログイン情報が機能しているか確認するためにApexから実行してみます。
作成した指定ログイン情報でコールアウト実行するとGoogleEmail__cのIDのカレンダーが取得できていることを確認できます。

GoogleEmailにGoogle WorkspaceのユーザーのIDを設定
// 匿名Apexで下記を実行
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:get_calendar_list');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
レスポンスをdebug表示

おわりに

いかがでしたでしょうか。指定ログイン情報を用いれば認証を用いたコールアウトが簡単に実行できることがお分かり頂けたと思います。指定ログイン情報は複数の要素から構成されているので全体の関連を理解するのは難しく感じる瞬間もありますが(少なくとも自分はそうでした)この記事がすこしでも理解の助けになれば幸いです。

参考記事