クライアントログイン情報

バージョン 1.3 以降で使用できます。

認証コード許可タイプは、ユーザーの代理で動作するアプリケーションの認証に主眼を置いていますが、クライアントログイン情報許可タイプは、自身のために動作するアプリケーションの認証に主眼を置いています。この許可は、人間の介入を必要としないため、マシン間の通信に適しています。

クライアントログイン情報対応コネクタの開発

クライアントログイン情報のサポートは、​@ClientCredentials​ アノテーションを使用して ​ConnectionProvider​ レベルで追加できます。

Salesforce 用 Anypoint Connector (Salesforce Connector) 用の ​ConnectionProvider​ を極端に簡素化した例を示します。

@ClientCredentials(tokenUrl = "https://login.salesforce.com/services/oauth2/authorize")
public class SalesforceOAuthConnectionProvider<C> implements ConnectionProvider<SalesforceClient> {

   @Parameter
   @Optional(defaultValue = "34.0")
   private Double apiVersion;

  /**
   * Tailors the login page to the user's device type.
   */
  @OAuthParameter
  private String display;

  /**
   * Avoid interacting with the user
   */
  @OAuthParameter
  @Optional(defaultValue = "false")
  private boolean immediate;

  /**
   * Specifies how the authorization server prompts the user for reauthentication and reapproval
   */
  @OAuthParameter
  @Optional(defaultValue = "true")
  private boolean prompt;

  @OAuthCallbackValue(expression = "#[payload.instance_url]")
  private String instanceId;

  @OAuthCallbackValue(expression = "#[payload.id]")
  private String userId;

  private AuthorizationCodeState state;

  @Override
  public SalesforceClient connect() throws ConnectionException {
    if (state.getAccessToken() == null) {
      throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "accessToken"));
    }

    if (instanceId == null) {
      throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "instanceId"));
    }

    return new SalesforceClient(state.getAccessToken(), instanceId, apiVersion);
  }

  public void disconnect(SalesforceClient connection) {
    connection.close();
  }

  @Override
  public ConnectionValidationResult validate(SalesforceClient connection) {
    return success();
  }
}

SDK の他の接続と同様に、クラスは ​ConnectionProvider​ を実装しています。オブジェクトによって認証された操作は、プロバイダーが返す ​SalesforceClient​ オブジェクトを処理します。このデザインアプローチの重要な点は、コネクタは基本認証を使用する ​ConnectionProvider​ を別に定義することもできるため、使用する認証方法と操作が切り離され、すべての操作の互換性が保証されるということです。

@ClientCredentials

このアノテーションは、この接続プロバイダーがクライアントログイン情報許可種別を使用した OAuth ダンスを必要とすることを示します。このアノテーションには以下の属性があります。

public @interface ClientCredentials {

  /**
   * @return The Url of the endpoint which provides the access tokens
   */
  String tokenUrl();

  /**
   * @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token
   */
  String accessTokenExpr() default "#[payload.access_token]";

  /**
   * @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token expiration
   */
  String expirationExpr() default "#[payload.expires_in]";

  /**
   * @return The default set of scopes to be requested, as a comma separated list. Empty string means no default scopes.
   */
  String defaultScopes() default "";

  /**
   * Allows to customize the placement that the client credentials will have in the request.
   *
   * @return the selected {@link CredentialsPlacement}. Defaults to {@link CredentialsPlacement#BASIC_AUTH_HEADER}
   */
  CredentialsPlacement credentialsPlacement() default BASIC_AUTH_HEADER;

}

接続管理戦略

@ClientCredentials​ の例のプロバイダーは、ConnectionProvider インターフェースの特殊化を実装していないため、OAuth メカニズムを他の接続管理戦略と組み合わせることができます。使用するインターフェース (PoolingConnectionProvider、CachedConnectionProvider、ConnectionProvider など) によって、接続オブジェクトをプールまたはキャッシュしたり、毎回新しく作り直したりすることができます。接続管理の詳細については、接続性のリファレンスについての説明を参照してください。

このシナリオで特殊化されていない (たとえば、PollingConnectionProvider や CachedConnectionProvider ではない) ConnectionProvider インターフェースを使用する際のセマンティクスに注意してください。通常の「非 OAuth」接続プロバイダーでは、特殊化されていないインターフェースを使用することは、コンポーネントが接続を必要とするたびに新しい接続が作成され、コンポーネントの終了時に破棄されることを意味します。これは OAuth のケースにも当てはまりますが、OAuth ダンスが再び実行されるという意味ではありません。OAuth でも新しい接続オブジェクトが作成されますが、同じアクセストークンが有効である間は再利用されます。

通常のパラメーターと OAuth パラメーターの違い

この ConnectionProvider は、他のすべての接続プロバイダーと同様にパラメーターを持ちます。ただし、通常のパラメーターと ​@OAuthParameter​ では概念が異なりますので注意してください。

OAuthParameter は、OAuth ダンスの実行中にカスタムパラメーターとして使用されます。たとえば、接続プロバイダーが ​apiVersion​ パラメーターを使用して SalesforceClient を作成する場合、即時パラメーターは、実際にはサービスプロバイダーへの OAuth 要求で送信されます。

モジュールの視点から見ると、OAuth パラメーターもユーザーが値を提供するパラメーターの 1 つに過ぎません。これらのパラメーターには、​@Optional​、​@Expression​、および従来の ​@Parameter​ アノテーションで使用できる他のすべてのアノテーションを組み合わせることができます。DSL では、通常のパラメーターと OAuth パラメーターは一緒に表示されます。モジュールのエンドユーザーには違いが一切分かりません。

requestAlias パラメーター

一部のカスタム OAuth パラメーターには、Java ではサポートされない文字が含まれています (例: Api-Key​)。​-​ は項目名には使用できないため、@OAuthParameter アノテーションには ​requestAlias​ という省略可能なパラメーターがあります。

@OAuthParameter(requestAlias = "api-key")
private String apiKey;

@OAuthCallbackValue アノテーション

サービスプロバイダーが OAuth コールバックで返す応答からは、コールバック値が抽出されます。ほとんどのサービスプロバイダーは標準項目 (アクセストークンや更新トークン、期限切れ情報など) のみを返しますが、一部のサービスプロバイダーは追加項目 (Salesforce の場合はユーザー ID やインスタンス ID など) も返します。

このアノテーションには、応答に適用して値を抽出するための式が含まれています。抽出された値は、接続プロバイダーが使用する項目に割り当てられます。connect()、validate()、または disconnect() メソッドを呼び出すと、項目が設定されて使用可能になります。

@ClientCredentialsState

@ClientCredentials​ アノテーションが付加されたすべての ConnectionProvider は、ClientCredentialsState 型の項目を 1 つ (だけ) 持っている​必要があります​。

この項目は、OAuth ダンスの結果に関する情報を含む、シンプルな不変の POJO です。この POJO には以下の情報が含まれます。

public interface ClientCredentialsState {

  /**
   * @return The obtained access token
   */
  String getAccessToken();

  /**
   * @return The access token's expiration. The actual format of it depends on the OAuth provider
   */
  Optional<String> getExpiresIn();
}

プロバイダーは、このオブジェクトを介して accessToken や OAuth ダンス中に取得した他の標準情報にアクセスします。元の Salesforce の例を見直せば、connect() メソッドがこの POJO を利用してクライアントを作成していることがわかります。

クライアントログイン情報コネクタの設定

ユーザーが OAuth 対応コネクタやモジュールをどのように使用できるかも重要です。SDK は OAuth プロトコルの複雑さを可能な限り隠しますが、OAuth ダンスなどは隠せません。この問題に対して SDK は、すべての OAuth Module の使用方法を標準化して、ユーザーエクスペリエンスを簡素化することに努めています。 このセクションでは、ユーザーがモジュールを使用するための手順について説明します。

合成パラメーター

ConnectionProvider で明示的に定義されているすべての設定に加えて、SDK はいくつかのパラメーターを追加して、適切な動作を挿入します。

パラメーター名 必須 デフォルト値 説明

clientId

はい

SUPPORTED

なし

サービスプロバイダーに登録されている OAuth ​clientId​ 値。

clientSecret

はい

NOT_SUPPORTED

なし

サービスプロバイダーに登録されている OAuth ​clientSecret​ 値。

tokenUrl

いいえ

SUPPORTED

@ClientCredentials​ アノテーションで提供されている値。

サービスプロバイダーのトークンエンドポイント URL。

scopes

いいえ

SUPPORTED

@ClientCredentials​ アノテーションで提供されている値。

OAuth ダンス時に要求する OAuth スコープ。指定されていない場合、デフォルトとしてアノテーション内のスコープが使用されます。

objectStore

いいえ

NOT_SUPPORTED

なし

各リソースオーナー ID のデータを保存する ObjectStore への参照。指定しない場合、Runtime は自動的にデフォルトのオブジェクトストアをプロビジョニングします。

式の使用について

合成パラメーターの表には、式を受け入れる多くの合成パラメーターが示されています。式を使用することで、通常のパラメーターで式を使用するのと同じ効果が得られ、動的なパラメーター設定を可能にします。

OAuth 接続 DSL

生成される DSL の例を示します。

<sfdc:config name="salesforce">
    <sfdc:client-credentials-connection display="PAGE" immediate="FALSE" prompt="CONSENT">
        <sfdc:oauth-client-credentials clientId="${sfdc.consumerkey}" clientSecret="${sfdc.consumersecret}" tokenUrl="http://..." />
        <sfdc:oauth-store-config objectStore="oauthObjectStore" />
</sfdc:config>

他のすべてのプロバイダーの場合と同様に、通常パラメーターと OAuth パラメーターはすべて接続プロバイダーレベルで示されています。 クライアントログイン情報許可種別に関連したパラメーターは、<oauth-client-credentials> という子要素に配置されます。 ObjectStore に関連したパラメーターは、<oauth-store-config> という子要素に配置されます。

カスタム ObjectStore の設定

取得したアクセストークンはオブジェクトストアに保存されます。デフォルトでは、SDK はトークンをアプリケーションのデフォルトストアに保存しますが、ユーザーは次の例に示すようにカスタムオブジェクトストアを定義することもできます。

<os:object-store name="tokenStore"
   entryTtl="1"
   entryTtlUnit="HOURS"
   maxEntries="100"
   persistent="true"
   expirationInterval="30"
   expirationIntervalUnit="MINUTES" />

<sfdc:config name="salesforce">
    <sfdc:client-credentials-connection display="PAGE" immediate="FALSE" prompt="CONSENT">
        <sfdc:oauth-client-credentials clientId="${sfdc.consumerkey}" clientSecret="${sfdc.consumersecret}" tokenUrl="http://..." />
        <sfdc:oauth-store-config objectStore="tokenStore" />
</sfdc:config>

期限切れになったクライアントログイン情報アクセストークンの更新

ほとんどのアクセストークンには有効期限が設定されており、通常は発行から 30 ~ 60 分です。そのため、ほとんどのプロバイダーでは更新トークンも提供しており、OAuth ダンスを再び実行しなくても済むようにしていますが、これはプロバイダーによって厳格に適用される標準ではありません。 SDK が期限切れのトークンを自動的に検出して新しいトークンを取得できるようにするような標準は適用されていません。通信方法は API ごとに異なるため、次のような ​AccessTokenExpiredException​ 例外が存在します。

public void someOperation(@Connection SalesforceRestClient client) {
    Response response = client.performSomeOperation();
    if (response.getStatusCode() == 401) {
        throw new AccessTokenExpiredException();
    }
}

この例では、架空の REST クライアントを使用して操作を実行しています。

  • この REST クライアントは、​@ClientCredentials​ アノテーションが付加された ConnectionProvider で作成されたものと想定されています。

  • このクライアントは操作を実行して、HTTP コールの情報が格納されたレスポンスオブジェクトを受け取ります。

  • この例では、状況コードの 401 (​UNAUTHORIZED​) はトークンの期限切れであると想定しています。

  • また、AccessTokenExpiredException をスローしています。

SDK がこの例外を検出すると、自動的に更新ダンスを実行して、新しいアクセストークンで操作を再試行します。 前述したように、アクセストークンの期限切れの通知方法は API ごとに異なります。例外をスローする API もありますし、カスタムメッセージを出力する API もあります。リモート API を調べて、最適な対応を決定してください。

アクセストークンの無効化

マルチテナントでは、特定の resourceOwnerId を持つアクセストークンを無効化して、関連付けられているトークン情報を削除することができます。 アクセストークンを無効化できるように、SDK はすべての OAuth 対応コネクタまたはモジュールに ​unauthorize​ という操作を自動的に追加します。次の例では、取得したトークンをこのように無効化できます。

<sfdc:unauthorize config-ref="salesforce"/>

この操作では、サービスプロバイダー側のトークンは無効化されません。Mule のキャッシュとオブジェクトストアからサービスプロバイダーが削除されます。