Salesforce 指定ログイン情報で自組織にAPIアクセス

#[概要]
SalesforceでApex Batch等で画面のようにログインユーザのセッションIDが存在しないような
処理で自組織のメタデータをToolingAPI経由で取得する手法として
本記事に記載する方法を紹介します。
具体的には、接続アプリケーション、外部認証プロバイダ、指定ログイン情報の機能を使用して実現します。

それぞれの機能の概要は、以下となります。
###接続アプリケーション
https://help.salesforce.com/articleView?id=connected_app_overview.htm&type=5
>接続アプリケーションは、API を使用してアプリケーションを Salesforce と統合します。接続アプリケーションは、標準の SAML および OAuth プロトコルを使用して認証し、シングルサインオンと Salesforce API で使用するトークンを提供します。接続アプリケーションでは、標準の OAuth 機能に加え、Salesforce システム管理者がさまざまなセキュリティポリシーを設定したり、対応するアプリケーションを使用できるユーザを明示的に制御したりすることができます。

###外部認証プロバイダ
https://help.salesforce.com/articleView?id=sso_authentication_providers.htm&type=5
>認証プロバイダは外部サービスプロバイダのログイン情報を使用して、Salesforce 組織にユーザがログインできるようにします。Salesforce では、Google、Facebook、Twitter、LinkedIn など、OpenID Connect プロトコルをサポートするアプリケーション用の認証プロバイダが提供されます。OpenID Connect をサポートしないアプリケーションには、カスタム認証プロバイダを作成するための Apex の Auth.AuthProviderPluginClass 抽象クラスが提供されます。

今回は、自組織への認証に使用するので、プロバイダタイプは「Salesforce」を利用します。
詳細は、こちらを参照ください。
https://help.salesforce.com/articleView?id=sso_provider_sfdc.htm&type=5

###コールアウトエンドポイントとしての指定ログイン情報
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_callouts_named_credentials.htm#!
>指定ログイン情報では、1 つの定義にコールアウトエンドポイントの URL と必要な認証パラメータを指定します。Apex コールアウトで指定ログイン情報をコールアウトエンドポイントとして指定するすべての認証が Salesforce によって管理されるため、コードでこれらを行う必要はありません。指定ログイン情報で定義されたサイトについては、外部サイトへのコールアウトに必要なリモートサイト設定もスキップできます。

#[用語]
###アクセストークン
https://help.salesforce.com/articleView?id=remoteaccess_terminology.htm&type=5
>ユーザの Salesforce ログイン情報を使用する代わりに、保護されたリソースへのユーザのアクセスを許可するためにコンシューマによって使用される値。

###コールバック URL
>クライアントアプリケーションに関連付けられた URL。場合によっては、URL は、クライアントの Web ブラウザのリダイレクト先である実際の URL にする必要があります。それ以外では、URL は実際には使用されませんが、クライアントアプリケーションとサーバ (接続アプリケーション定義) との間で値が一致する必要があります。

###コンシューマ
>Salesforce ユーザとアプリケーションの両方をユーザの代わりに認証するために OAuth を使用する Web サイトまたはアプリケーション。

###コンシューマ鍵
>Salesforce で識別するためのコンシューマによって使用される値。OAuth 2.0 では client_id と呼ばれます。

###コンシューマの秘密
>コンシューマ鍵の所有権を確立するためにコンシューマにより使用される秘密。OAuth 2.0 では client_secret として参照されます。

###更新トークン
>OAuth 2.0 のみで使用できます。新しいアクセストークンを取得するためにコンシューマが使用するトークン。エンドユーザがアクセスを再度承認する必要がありません。

#[手順]
※今回の設定は、DE環境で実施します。
1.　指定ログイン情報のOAuth認証で使用する接続アプリケーションを作成します。
1-1.　アプリケーション>アプリケーションマネージャで、新規接続アプリケーションを選択します。
1-2.　新規接続アプリケーションの必要情報を入力します。
ポイントとしては、この時点ではコールバックURLが確定していないので仮の値を設定します。2.で認証プロバイダを作成するとコールバックURLが決まるのでその後で再設定します。ちなみに、先に接続アプリケーションを設定するのは、認証プロバイダの設定でコンシューマ鍵の情報が必要となるからとなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138335/926bf023-3a82-f550-3b51-95747bf987d1.png)

2.　接続アプリケーションで使用する認証プロバイダを作成します。

2-1.ID>認証プロバイダで新規を選択します。
2-2.認証プロバイダの必要情報を入力します。
コンシューマ鍵、コンシューマの秘密は、1.で作成した接続アプリケーションから取得して設定します今回のOAuth認証で利用するのは、"refresh_token api"のみなので、デフォルトの範囲をそのように設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138335/10e37ac8-2b5f-11e6-21af-27408c1fff86.png)

3.　2.で作成したプロバイダのコールバックURLを1.で作成した接続アプリケーションに設定します。

4.　指定ログイン情報を作成します。
認証プロバイダには、先ほど作成したものを選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138335/2d9e3d5a-2faf-d6cd-5dab-0b9e760b715d.png)

5.　指定ログインの保存時に認証ユーザでの認可を行います。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138335/1c949b62-2d56-eb2a-47b1-dbcb5b4e2f11.png)

6.　最後にApexからの呼び出しで正しくコールできるかを確認します。
開発者コンソールのExecute Anonymous Windowで以下を実行します。
`String endPoint = 'callout:Test_Connection/services/data/v43.0/tooling/sobjects';
HttpRequest req = new HttpRequest();
req.setEndpoint( endPoint );
req.setHeader( 'Content-Type', 'application/json' );
req.setMethod( 'GET' );
Http http = new Http();
HTTPResponse res = http.send( req );
System.debug( res.getBody() );`

7.　デバックログの結果を確認します。以下のようなログが出力されていれば、成功となります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138335/265d995c-94b1-881e-a600-eb3dba981aad.png)

これで、自組織にセッションIDがないような機能(Apex Batch等)で指定ログイン情報を用いることでToolingAPIへのアクセスを行うことができるようになりました。