概要
本記事では、業界標準であるOAuth2.0とOpenID Connectの概要を紹介した後に、Salesforceではそれらをどのように実装することができるのかを簡単に記載していきたいと思います。
本記事のベースとなるOAuth2.0やOpenID Connectの技術的な事項はこちらの本で学習しました。クライアント、認可サーバー、保護対象リソースのそれぞれについてサンプルのソースコードでどのように動作するかが詳細に記載されており理解するのに非常に役に立ちました。おすすめです。
認証・認可とは
それぞれ詳細を説明すると非常に長くなるのですが、あえて一言で言うと下記で表せます。
認証
通信の相手が誰(何)であるかを確認すること
認可
とある特定の条件に対して、リソースアクセスの権限を与えること
Salesforceにおける認証・認可とは
Salesforceで実現可能な認証・認可の仕組みは下記が上げられます。
# | 名称 | 概要 | 機能名 |
1 | フォーム認証 | Webブラウザでユーザ名とパスワードを入力する 最も基本的な認証方式 | 標準ログイン画面 |
2 | 2要素認証 | 認証に2つ目の要素を追加することでセキュリティを強化する | Salesforce Authenticator |
3 | SSO | 一回の認証で複数のサービスを利用できる仕組み Salesforceは、IdpとSPのどちらになることもできる | SAMLシングルサインオン |
4 | 証明書認証 | PCもしくはモバイルデバイスに配布されたクライアント証明書でログイン認証を行う | 証明書認証 |
5 | OAuth/OpenID Connect ←本記事ではこれを解説 | 外部アプリケーションにSalesforceのデータへのアクセスする際にその認可を与える仕組み | 接続アプリケーション |
6 | Social Sign on | ソーシャルアカウントで認証を行う | 認証プロバイダ |
7 | 代理認証 | ユーザの認証を外部サービスで行う 外部サービスはSalesforceが指定するWSDLに合わせたインターフェースを実装する必要がある | 代理認証 |
OAuth2.0とは
概要
OAuth2.0は、業界標準でありRFCに下記のように定義されております。RFC6794(The OAuth 2.0 Authorization Framework)
https://tools.ietf.org/html/rfc6749
‘OAuth 2.0 は, サードパーティーアプリケーションによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワークである. サードパーティーアプリケーションによるアクセス権の取得には, リソースオーナーとHTTPサービスの間で同意のためのインタラクションを伴う場合もあるが, サードパーティーアプリケーション自身が自らの権限においてアクセスを許可する場合もある. 本仕様書はRFC 5849に記載されているOAuth 1.0 プロトコルを廃止し, その代替となるものである.’
言い換えると、下記のように表せます。
- リソース所有者の代わりとして対象のリソースへのアクセスを許可するための手段
- サード・パーティー製のアプリケーションがHTTPサービスへの制限されたアクセス権を取得できるするようにするためのもの
- OAuthとはシステムを構成しているある要素から別の構成要素にアクセス権を渡すためのもの
では、なんのためにOAuthを使用して認可をするかというと
- サード・パーティ製のアプリケーションにユーザーの ID & パスワードを渡さない
となります。
概要イメージ
0. まずユーザであるリソース所有者がクライアントのアプリケーションを使用します。
1. クライアントは、保護対象リソースへアクセスするために一旦認可サーバーへリクエストを行います。
2. 認可サーバーはリソース所有者との間でユーザ認証および認可を行います。
3. 認可サーバーはユーザとの認証・認可が完了しているので、クライアントへアクセストークンを返却します。
4. クライアントは、保護対象リソースへアクセストークンを利用してAPIアクセスを行います。
各構成要素
- クライアント ・・・ ソフトウェアであり、リソース所有者の代わりとして保護対象リソースへのアクセスを行うもの
- 認可サーバー ・・・ OAuthの仕組みの中心的な役割を担うHTTPサーバーのこと. リソース所有者にクライアントを認可するための仕組みを提供し、トークンをクライアントに発行するもの
- リソース所有者 ・・・ クライアントにアクセス権を委譲する権限を持つ存在. ソフトウェアでなくユーザー.
- 保護対象リソース ・・・ HTTPサーバーから提供されており、そのリソースにアクセスするにはOAuthのトークンが必要となる. 保護対象リソースは提示されたトークンを検証して、リクエストに応えるかを判定する
- アクセストークン ・・・ 認可サーバーによってクライアントへ発行され、クライアントに権限が委譲されたことを示すもの
- スコープ ・・・ 保護対象リソースでの権限を表すものであり、クライアントに付与されるアクセス権限を制限するための仕組み
- リフレッシュトークン ・・・ 新しいアクセストークンを発行するために使用する
認可コードフロー(Authrorization Code Grant Type)
OAuthのいくつかあるフローの中で最も標準的なフローである認可コードフローは下記のようになります。
認可リクエスト/認可レスポンスのイメージ
- response_type=codeで認可コードフローを指定
- codeの値が発行された認可コード
トークンリクエスト/トークンレスポンスのイメージ
- grant_type ・・・ authorization_codeで認可コードフローを指定。
その他のフロー
# | フロー名 | 概要 |
1 | 認可コードフロー (Authorization Code Type) | 最も標準系のフロー。 クライアントが認可コードを経由してアクセストークンを取得する。 |
2 | インプリシットフロー (Implicit Grant Type) | JavaScriptアプリケーション等で完全にブラウザ内で動作している場合に使用する。 クライアントは認可エンドポイントから直接アクセストークンを取得する。 |
3 | クライアント・クレデンシャルフロー (Client Credentials Grant Type) | ユーザに関係なくクライアントアプリへ直接アクセストークンを発行する。 |
4 | リソースオーナー・パスワード・クレデンシャルズフロー (Resource Owner Password Credentials Grant Type) | 基本的に非推奨。(アンチパターン) アプリケーション側でID、PWを入力させて、それをトークンエンドポイントへ送り直接アクセストークンを取得する。 |
5 | リフレッシュトークンフロー (Refresh Token Grant Type) | リフレッシュトークンを使用して、アクセストークンの再発行を行う。 |
OpenID Connectとは
概要
OpenID Connect Core1.0
https://openid.net/connect/
OpenID Connect 1.0 は, OAuth 2.0 プロトコルの上にシンプルなアイデンティティレイヤーを付与したものである. このプロトコルは Client が Authorization Server の認証結果に基づいて End-User のアイデンティティを検証可能にする. また同時に End-User の必要最低限のプロフィール情報を, 相互運用可能かつ RESTful な形で取得することも可能にする.
これらをわかりやすく言い換えると下記のように表せます。
- OAuth 2.0 + Identity Layer = OpenID Connect
- Identity Layer = ID Token + UserInfo API
- ID Token ・・・ APIプロバイダー側のUser情報が取得できること
- UserInfo API ・・・ APIプロバイダー側のプロフィール情報を取得できる
では、なんのためにOpenID Connectを使うかというと
- クライアントがユーザの認証情報を取得するため
となります。
フロー
IDトークンとは
一言で言うと
認証結果として得られるトークン
です。
サンプルですが、実際の文字列は下記のようなものになります。
eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJmZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9leGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ.rHQjEmBqn9Jre0OLykYNnspA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcipR2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3KE7yM2macAAgNCUwtik6SjoSUZRcfO5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOYu0532g9ExxcmChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl 6cQQWNiDpWOl_lxXjQEvQ
これは以下のようにピリオド区切りの構成(JWS形式)となっています。
ヘッダー.ペイロード(本文).署名
それぞれは、base64urlでエンコードされているのでデコードすると下記のようになります。
[ペイロード]
{ “iss”: “http://server.example.com”,
“sub”: “248289761001”,
“aud”: “s6BhdRkqt3”,
“nonce”: “n-0S6_WzA2Mj”,
“exp”: 1311281970,
“iat”: 1311280970,
“name”: “Jane Doe”,
“given_name”: “Jane”,
“family_name”: “Doe”,
“gender”: “female”,
“birthdate”: “0000-10-31”,
“email”: “janedoe@example.com”,
“picture”:”http://example.com/janedoe/me.jpg” }
SalesforceにおけるOAuth2.0/OpenID Connectとは
概要
OAuth2.0の認可サーバーとOpenIDプロバイダーにあたる部分がSalesforceでは接続アプリケーションによって簡単に作成することができます。
エンドポイント
接続アプリケーションを定義してあとはクライアントアプリケーションが呼び出すエンドポイントは下記のようになります。
# | エンドポイント | 概要 |
1 | https://login.salesforce.com/services/oauth2/authorize | Salesforceの認証エンドポイント |
2 | https://login.salesforce.com/services/oauth2/success | redirect_uri パラメータで指定されたコールバック URL 接続アプリケーションにも設定 ※ リフレッシュトークンを取得する場合には、SalesforceのURIにする必要がある |
3 | https://login.salesforce.com/services/oauth2/introspect | Salesforceのトークンイントロスペクションエンドポイント ※ アクセストークンが有効かを確認 |
4 | https://login.salesforce.com/services/oauth2/token | Salesforceのトークン要求エンドポイント |
5 | https://login.salesforce.com/services/oauth2/revoke | Salesforceのトークン取り消しエンドポイント |
Salesforceでのフロー名とのマッピング
# | フロー名 | Salesforce |
1 | 認可コードフロー (Authorization Code Type) | Webサーバーフロー |
2 | インプリシットフロー (Implicit Grant Type) | ユーザエージェントフロー |
3 | リソースオーナー・パスワード・クレデンシャルズフロー (Resource Owner Password Credentials Grant Type) | ユーザ名パスワードフロー |
4 | クライアント・クレデンシャルフロー (Client Credentials Grant Type) | JWTベアラーフロー |
5 | リフレッシュトークンフロー (Refresh Token Grant Type) | 更新トークンフロー |
接続アプリケーション
設定項目 | 設定値 |
OAuthの有効化 | チェックあり |
コールバックURL | 認可レスポンスのリダイレクト先を指定 |
選択したOauth範囲 | 認可リクエストを受け付けるスコープ |
Webサーバフローの秘密が必要 | OpentID Connectを使用する場合はチェックあり |
IDトークンを設定 | IDトークンにカスタム属性を含める場合はチェックあり |
コンシューマ鍵 | client_id として使用 |
コンシューマの秘密 | client_secret として使用 |
アプリケーションハンドラー
接続アプリケーションにApexで実装したハンドラーを紐づけることで、IDトークンのカスタム属性として値を返却することができます。下記のサンプルは、ログインユーザに紐づく権限セットを返す処理になります。
global class ConnectedAppPluginExample extends Auth.ConnectedAppPlugin{
global override Map<String,String> customAttributes(Id userId, Id connectedAppId, Map<String,String> formulaDefinedAttributes, Auth.InvocationContext context){
List<PermissionSetAssignment> psas = [SELECT id, PermissionSet.Name FROM PermissionSetAssignment WHERE PermissionSet.IsOwnedByProfile = false AND (AssigneeId = :userId)];
String permsets = '[‘;
for (PermissionSetAssignment psa :psas) {
permsets += psa.PermissionSet.Name + ';’;
}
permsets += ']’;
formulaDefinedAttributes.put('PermissionSets', permsets);
return formulaDefinedAttributes;
}
}
参考
OAuth徹底入門 セキュアな認可システムを適用するための原則と実践
一番分かりやすい OAuth の説明
https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be
一番分かりやすい OpenID Connect の説明https://qiita.com/TakahikoKawasaki/items/498ca08bbfcc341691fe
OAuth & OIDC 入門編