Use PCS REST API with OAuth2 authentication

ちょっと前に以下のような記事がUpされていました。

Accessing Oracle Process Cloud Service REST API using OAuth
https://community.oracle.com/community/cloud_computing/oracle-cloud-developer-solutions/blog/2017/02/19/accessing-oracle-process-cloud-service-rest-api-using-oauth

この記事のコードはJerseyに依存していたので、JAX-RS 2.0ベースに書き直してみました。

認証周りは、ClientRequestFilterを使います。headers()に書いてもよいのですが、こちらのほうがすっきりするので。

まず、Basic認証のためのFilter。

package pcsoauth2;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.MultivaluedMap;

import javax.xml.bind.DatatypeConverter;

public class BasicAuthenticator implements ClientRequestFilter {
  private final String user;
  private final String password;

  public BasicAuthenticator(String user, String password) {
    this.user = user;
    this.password = password;
  }

  public void filter(ClientRequestContext requestContext) throws IOException {
    MultivaluedMap<String, Object> headers = requestContext.getHeaders();
    final String basicAuthentication = getBasicAuthentication();
    headers.add("Authorization", basicAuthentication);
  }

  private String getBasicAuthentication() {
    String token = this.user + ":" + this.password;
    try {
      return "BASIC " + DatatypeConverter.printBase64Binary(token.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException ex) {
        throw new IllegalStateException("Cannot encode with UTF-8", ex);
    }
  }
}

つづいて、OAuth 2.0トークンをHeaderに載せるためのFilter。JWTでも同じしくみです。

package pcsoauth2;

import java.io.IOException;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.MultivaluedMap;

public class OAuth2Authenticator implements ClientRequestFilter {
  private final String accessToken;

  public OAuth2Authenticator(String accessToken) {
    this.accessToken = accessToken;
  }

  public OAuth2Authenticator() {
    this.accessToken = null;
  }

  public void filter(ClientRequestContext requestContext) throws IOException {
    MultivaluedMap<String, Object> headers = requestContext.getHeaders();
    final String oAuth2Authentication = "Bearer " + this.accessToken;
    headers.add("Authorization", oAuth2Authentication);
  }
}

まず、OAuth 2.0トークンを取得するために、ClientAssertionを取得します。

private Map<String, String> getClientAssertion() throws Exception {

  MultivaluedHashMap<String, String> formData = new MultivaluedHashMap();
  formData.putSingle("grant_type", "client_credentials");

  Response response = ClientBuilder.newClient()
                                   .target(entryMap.get("TOKEN_URL").toString())
                                   .register(new BasicAuthenticator(entryMap.get("CLIENT_ID").toString(),
entryMap.get("SECRET").toString()))
                                   .request()
                                   .header(HttpHeaders.CONTENT_TYPE,
"application/x-www-form-urlencoded;charset=UTF-8")
                                   .buildPost(Entity.entity(formData,
                                                            MediaType.APPLICATION_FORM_URLENCODED_TYPE))
                                   .invoke();
  if (response.getStatus() != Response.Status.OK.getStatusCode()) {
    throw new Exception(response.getStatusInfo().getReasonPhrase());
  }

  Map<String, String> assertionMap = new HashMap<>();
  try (JsonReader reader = Json.createReader(new StringReader(response.readEntity(String.class)))) {
    response.close();
    JsonObject jsonObj = reader.readObject();
    assertionMap.put("assertion_token", jsonObj.getString("access_token"));
    assertionMap.put("assertion_type", jsonObj.getString("oracle_client_assertion_type"));
  }
  return assertionMap;
}

取得したClientAssertionを使って、Access Tokenを取得します。

private String getAccessToken(Map clientAssertionMap) throws Exception {

  MultivaluedHashMap<String, String> formData = new MultivaluedHashMap();
  formData.putSingle("grant_type", "password");
  formData.putSingle("username", entryMap.get("USER_NAME").toString());
  formData.putSingle("password", entryMap.get("PASSWORD").toString());
  formData.putSingle("client_assertion_type", clientAssertionMap.get("assertion_type").toString());
  formData.putSingle("client_assertion", clientAssertionMap.get("assertion_token").toString());

  Response response = ClientBuilder.newClient()
                                   .target(entryMap.get("TOKEN_URL").toString())
                                   .register(new BasicAuthenticator(entryMap.get("CLIENT_ID").toString(),
entryMap.get("SECRET").toString()))
                                   .request()
                                   .header(HttpHeaders.CONTENT_TYPE,
"application/x-www-form-urlencoded;charset=UTF-8")
                                   .buildPost(Entity.entity(formData,
MediaType.APPLICATION_FORM_URLENCODED_TYPE))
                                   .invoke(Response.class);

  if (response == null || response.getStatus() != Response.Status.OK.getStatusCode()) {
    throw new Exception(response.getStatusInfo().getReasonPhrase());
  }

  String accessToken;
  try (JsonReader reader = Json.createReader(new StringReader(response.readEntity(String.class)))) {
    response.close();
    JsonObject jsonObj = reader.readObject();
    accessToken = jsonObj.getString("access_token");
  }
  return accessToken;
}

最後は、PCSのプロセスインスタンスを生成するAPIを呼び出します。17.2.3の時点で、PCS REST APIはv4が最新で、v3はDeprecated(非推奨、廃止対象)という扱いになっています。そのため、このコードではV4を使っています。

public String invokeFundsTransferProcess(String token, FundsTransferRequest ftr) throws Exception {

  JsonObject postObj = Json.createObjectBuilder()
                           .add("processDefId", entryMap.get("PCS_PROCESS_DEF_ID").toString())
                           .add("serviceName", entryMap.get("PCS_FTS_SVC_NAME").toString())
                           .add("operation", "start")
                           .add("action", "Submit")
                           .add("params",
Json.createObjectBuilder()
                                    .add("incidentId", ftr.getIncidentId())
                                    .add("sourceAcctNo", ftr.getSourceAcctNo())
                                    .add("destAcctNo", ftr.getDestAcctNo())
                                    .add("amount", ftr.getAmount())
                                    .add("transferType",
                                         ftr.getTransferType()
                                            .equals("tparty") ? "intra" : "inter"))
                           .build();

  Response response = ClientBuilder.newClient()
                                   .target(entryMap.get("PCS_URL").toString())
                                   .register(new OAuth2Authenticator(token))
                                   .request(MediaType.APPLICATION_JSON_TYPE)
                                   .buildPost(Entity.entity(postObj.toString(),
                                                            MediaType.APPLICATION_JSON_TYPE))
                                   .invoke(Response.class);

  if (response != null && response.getStatus() != Response.Status.OK.getStatusCode()) {
    throw new Exception(response.getStatusInfo().getReasonPhrase());
  }
  return String.valueOf(response.getStatus());
}

動作確認のために作成したコードは、以下にUpしています。

https://github.com/anishi1222/BPM-and-PCS/tree/master/PCS%20REST%20API%20with%20OAuth%202.0

anishi1222 について

とあるキャラクターの中の人です。
カテゴリー: Cloud, 未分類 タグ: , パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中