関数の開発
APIゲートウェイ・デプロイメントをデプロイする前に、関数を開発してデプロイする必要があります。
ビジネス・ロジックについて
実装の重要性は、ファンクションにコードを入れることです。このコードは、必要に応じて複雑になり、複数のエンドポイントを呼び出したり、場合によっては集計を実行したりすることができます。ビジネス・ロジック・ファンクションは、Oracle Cloud Infrastructure API Gatewayで必要に応じてコールされるコードです。
このアーキテクチャの例では、APIゲートウェイがOracleファンクションをコールして、REST APIを介してOracle Fusion Applications Cloud Serviceから一部のデータを問い合せ、処理してユーザーに戻します。関数自体を記述するときは、目的のフレームワークを使用できますが、サーバーの機能が少ない場合のフレームワークの影響を理解しておく必要があります。この例では、Javaを言語として使用し、Apache HttpClientライブラリをREST Serviceに接続しています。Apacheライブラリは、使いやすく実装も簡単でしたが、Java 11では現在、使用可能な新しいHTTPクライアントが用意されています。
また、REST apiをコールする際に、多数のインメモリー・オブジェクトをインスタンス化するフレームワークを回避する必要があります。これは、これらのオブジェクトが各コールで破棄され、関数の実行が遅くなるためです。
ユーザー名およびロールの取得について
Oracle Cloud Infrastructure APIゲートウェイによって関数がコールされると、ゲートウェイはHTTPヘッダーを使用して一部のメタデータをコールに挿入します。これらのヘッダーには、Functions SDKを使用してアクセスできます。
たとえば、次のJavaコードのスニペット(このソリューション・プレイブックで提供されるサンプル・コードでは、クラスJWTUtils
から抜粋)では、認証トークンを抽出し、デコードしてから、本体の一部としてコール元に戻します。
public OutputEvent handleRequest(InputEvent rawInput) {
Optional<string> optionalToken=rawInput.getHeaders().get("Fn-Http-H-Authorization");
if (!optionalToken.isPresent())
{
throw new Exception("No Authentication Bearer token found");
}
String jwtToken=optionalToken.get().substring(TOKEN_BEARER_PREFIX.length());
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
byte[] decodedJWT = Base64.getDecoder().decode(base64EncodedBody);
try {
String JSONbody = new String(decodedJWT, "utf-8");
ObjectMapper mapper = new ObjectMapper();
JsonNode root=mapper.readTree(JSONbody);
username=root.get("sub").asText();
System.out.println(“Username = “+username);
} catch (Exception e)
{
Throw new Exception (e.getMessage());
}
Return OutputEvent.fromBytes(
username.getBytes(), // Data
OutputEvent.Status.Success,// Any numeric HTTP status code can be used here
"text/plain");
ユーザー名は、必要に応じてビジネス・ロジックを実装するために関数内で使用できます。ロールは認証トークンでは使用できませんが、REST apiを使用してOracle Identity Cloud Serviceから問合せできます。
Oracle API Gatewayが関数をコールすると、いくつかの有用なヘッダーも送信されます。これらのヘッダーは、関数のAPIを使用して読み取ることができます。関数Developerキットから使用できる有用なヘッダーには、次のものがあります。
Fn - Http - sql | 関数の呼出しに使用されるメソッド(GET/POST/PUTなど)。 |
Fn - Http - request - url | 関数の呼出しに使用されるURL。これには問合せパラメータが含まれます。 |
Fn - Http - User - gent | オペレーティング・システム、ベンダー、バージョンなどのクライアントの詳細 |
たとえば、Fn - Http - odとFn - Http - questrlの組合せを使用して、コード内にルーターを実装し、関数がどのようにコールされたか(PUT、PATCHなど)に基づいて、異なる関連項目を処理できます。このアプローチは「Serverless Service」パターンと呼ばれることが多く、開発者がより少ない関数を保持する必要があるという利点があり、各関数には、必要な作業を決定するためにわずかなルーターがあります。
public OutputEvent handleRequest(InputEvent rawInput, HTTPGatewayContext hctx) throws JsonProcessingException {
String httpMethod = hctx.getMethod();
String httpRequestURI = hctx.getRequestURL();
// etc
}
JWTアサーション・アクセス・トークンを使用したOracle Fusion Applications Cloud Serviceのコールについて
着信認可ヘッダーのサブジェクトを使用して、Oracle FunctionsからJWTアサーションを実装する必要があります。
このソリューション・プレイブックで提供されるサンプル機能では、idcsOAuthAsserter
という名前のヘルパー・ライブラリを使用して、このセキュリティ・プロセスを実行できます。ヘルパー・ライブラリは、Oracle Fusion Applications Cloud Serviceを起動する前にベアラー・トークンの交換を実行することで、OAuthアサーションの完全なフローを実行します。このライブラリは、サンプル関数と統合されています。
この関数では、OAuth JWTアサーションを使用して新しいベアラー・アクセス・トークンを作成するために、Oracle Identity Cloud Serviceの起動に使用されるユーザーおよびクライアントのアサーションを構築するために、秘密キーと公開証明書が必要です。
idcsOAuthAsserter
ライブラリには、「関数の構成」で定義できるプロパティがいくつか必要です。次の表の変数はすべて必須です:
構成名 | 説明 | 例 |
---|---|---|
IDCS_URL | Oracle Identity Cloud ServiceインスタンスのURL | https ://<アイデンティティ・クラウドhostname.identity.oraclecloud.com > |
CLIENT_ID | Oracle FunctionsおよびOracle API Gatewayに関連付けられたOracle Identity Cloud Serviceアプリケーション・クライアントID | 1a2b3c4d5e6f7g8h9i01j2k3l4m5o6p7 |
KEY_ID | 信頼できるOracle Identity Cloud Serviceアプリケーションにインポートされた証明書の別名 | fnassertionkey |
スコープ | このスコープは、Oracle Fusion Applications Cloud Serviceに関連付けられているOracle Identity Cloud ServiceアプリケーションであるターゲットOAuthリソースと一致する必要があります | urn: opc: resource: fa: instanceid = xxxxxxurn: opc: resource: consumer :: all https ://my_fusion_hostname: 443/ |
対象読者 | アサーション・プロセスの対象者。複数の入力値はカンマで区切ります。 | myhostname.identity.oraclecloud.com, https://myfusionservice.dc1.oraclecloud.com |
IDDOMAIN | Oracle Fusion Applications Cloud Serviceインスタンス・テナントの名前 | mytenant |
この関数では、idcsOAuthAsserter
に関連するアサーションのシークレットにアクセスするための構成プロパティも必要です。JWTアサーションでは、クライアントおよびユーザー・アサーションを生成するために、証明書および秘密キーが必要です。このファンクションは、V_KEYSTORE
で指定されたOCIDでキーストアを取得します。その情報を取得するための別名は、構成内のKEY_ID
値と一致している必要があります。キーストアと秘密キーの両方のパスフレーズは、V_KS_PASS
およびV_PK_PASS
で指定されたOCIDsを使用して、Oracle Cloud Infrastructure Vault Secrets Serviceから取得する必要があります。
構成名 | 説明 | 例 |
---|---|---|
V_KEYSTORE | キーストアのセキュア・ストアド・コンテンツを含むシークレット | ocid1.vaultsecret.oc1.dc1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_KS_PASS | キーストアのセキュア・ストアド・パスワードを含むシークレット | ocid1.vaultsecret.oc1.dc1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_PK_PASS | 秘密キーのセキュア・ストアド・パスワードを含むシークレット | ocid1.vaultsecret.oc1.dc1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
サポートされる追加の構成値は、プロパティUSE_CACHE_TOKEN
で、デフォルトではTrue
に設定されています。このプロパティを使用すると、トークンが有効な場合に、生成されたOracle Identity Cloud Serviceアサーション・トークンをOracle Fusion Applications Cloud Serviceの将来の呼出しで再利用できます。キャッシュされたトークンは、サブジェクトを着信トークンと比較し、有効期限を検証してまだ有効かどうかを確認することによって、使用前に検証されます。そうでない場合は、OAuthアサーションを使用して新しいアクセス・トークンがリクエストされます。この機能は、USE_CACHE_TOKEN
をFalse
に設定することで無効にできます。
実装する関数は、idcsOAuthAsserter
ライブラリのSecurityHelper object
を使用して、access-token
ヘッダーからサブジェクトを抽出し、OAuth JWTアサーションを使用して新しいベアラー・アクセス・トークンを生成し、新しいアクセス・トークンをAuthorization
ヘッダーとして使用してリクエストをOracle Fusion Applications Cloud Serviceに送信できます。
ソース・コード・サンプル内の関数saasopportunitiesfn
は、idcsOAuthAsserter
ライブラリとすでに統合されています。次のコード・スニペットは、サンプルのファンクションのhandleRequest
メトリックで使用できます。このサンプル・ファンクションは、idcsOAuthAsserter
のオブジェクトを初期化し、Oracle Identity Cloud Serviceを使用してアサーションを使用してトークンの欠如を実行する方法を示しています。
// Full Oauth scenario Perform exchange of tokens
if(fullOAauth) {
LOGGER.log(Level.INFO, "Full Oauth Assertion scenario - Perform exchange of tokens");
SecurityHelper idcsSecurityHelper = new SecurityHelper(context) // Initialize SecurityHelper with RuntimeContext
.setOciRegion(Region.US_PHOENIX_1) // Specify the OCI region, used to retrieve Secrets.
.extractSubFromJwtTokenHeader(rawInput); // Extracts the subject from Token in Fn-Http-H-Authorization.
// Get OAuth Access token with JWT Assertion using the principal extracted from Fn-Http-H-Access-Token Header
jwttoken = idcsSecurityHelper.getAssertedAccessToken();
LOGGER.log(Level.INFO, "Successfully token retrived with IDCS Assertion");
LOGGER.log(Level.FINEST, "Access Token from assertion [" + jwttoken + "]");
}
このスニペットでは、オブジェクトSecurityHelper
がRuntimeContext
タイプのコンテキスト・オブジェクトで初期化されていることに注意してください。これは、idcsOAuthAsserter
ヘルパー・ライブラリの構成でSecurityHelper
を初期化するために使用されます。
例のsaasopportunitiesfn
関数はUS_PHOENIX_1
領域を使用するように設定されているため、地域を指すようにスニペット内に表示されているメソッドsetOciRegion
の地域を変更する必要があります。
また、SecurityHelper
には、handleRequest
ファンクション・メソッドからInputEvent
オブジェクトを取り、API Gateway Authorization
ヘッダーにあるBearerトークンを抽出するメソッドextractSubFromJwtTokenHeader
もあります。その後、Oracle Identity Cloud Serviceアサーションの結果としてアクセス・トークンを取得できる必要があります。
idcsOAuthAsserter
の使用方法および関数との統合の詳細は、コード・リポジトリでidcsOAuthAsserter
のREADMEファイルを参照し、ダウンロード可能なコード・サンプルとともにこのソリューション再生ブックを参照してください。
構成パラメータの設定
Oracle Functions環境には、Oracle Cloud Infrastructure環境内でいくつかのパラメータを定義し、それらをコードから参照できる、非常に便利な機能があります。
このユースケースでは、FusionおよびOverrideJWTトークンURL、およびコードで使用されるパラメータとしてのfull_oauth
というフラグを設定します。パラメータを追加するには:
コード内では、特殊なJava注釈(@FnConfiguration
)を使用し、コンテキスト変数を介してパラメータにアクセスすることで、SDK関数を使用して次の構成変数にアクセスできます。
private String jwtoverride = "";
private String fusionHostname = "";
private String fnURIBase ="/fnsaaspoc/opportunities";
/**
* @param ctx : Runtime context passed in by Fn
*/
@FnConfiguration
public void config(RuntimeContext ctx) {
fusionHostname = ctx.getConfigurationByKey("fusionhost").orElse("NOTSET");
jwtoverride = ctx.getConfigurationByKey("overridejwt").orElse("NOTSET");
fullOAauth = Boolean.parseBoolean(ctx.getConfigurationByKey("full_oauth").orElse("false"));
LOGGER.info("Configuration read : jwt=" + jwtoverride + " saasurl=" + fusionHostname);
}
さらに、このソリューションではidcsOAuthAsserter
ヘルパー・ライブラリが使用されるため、関数構成で、前の項で説明されている特定の変数を提供してOracle Identity Cloud Service OAuthアサーションを使用し、アクセス・トークンを交換する必要があります。このプロセスには複数の必須構成が必要なため、yamlのファイルアプローチを使用して関数の構成を設定することをお薦めします。次に例を示します。
config:
AUDIENCE: <AUDIENCE_VALUES>
CLIENT_ID: <YOUR_CLIENT_ID>
IDCS_URL: <YOUR_IDCS_URL>
IDDOMAIN: <YOUR_FA_TENANT_NAME>
KEY_ID: <YOUR_IDCS_URL>
SCOPE: <FA_RESOURCE_SCOPE>
V_KEYSTORE: <YOUR_KS_OCID>
V_KS_PASS: <YOUR_KSPASS_OCID>
V_PK_PASS: <YOUR_PKPASS_OCID>
fusionhost: <value>
overridejwt: <value>
full_oauth: <value>
Fusionアプリケーションへのユーザー認証トークンの受渡し
関数では、セキュアなREST API相互作用のユーザー認証トークンを処理する必要があります。
関数が呼び出されると、認証トークンを含む「authorization」ヘッダー変数も送信されます。このトークンは、コール元のアプリケーションのアイデンティティ・サーバー(Oracle Cloud Infrastructure APIゲートウェイ関数がリクエストの検証に使用しているアイデンティティ・サーバーと同じ)で生成されます。
このソリューションのプレイブックで説明するアプローチでは、Oracle Identity Cloud Service OAuth JWTアサーションを使用して、idcsOAuthAsserter
ヘルパー・ライブラリを使用してトークンの交換を実行します。これにより、Oracle FunctionsからOracle Fusion Applications Cloud Serviceへの起動用の追加のセキュリティ・レイヤーが提供されます。アーキテクチャ・ダイアグラムに示されているように、OAuth JWTアサーションを使用したトークンの問合せは、API Gatewayヘッダーからのインバウンド呼出しに含まれ、Oracle Identity Cloud Serviceを使用したアサーション処理中に別のトークンが示されるように使用されます。この新しいトークンは宛先サーバー(Oracle Fusion Applications Cloud Service)へのアウトバウンド・コールで使用され、Oracle Fusion Applications Cloud Serviceでは、Oracle Visual Builderでユーザーとしてコールが実行されます。
指定されたサンプル関数(saasopportunitiesfn
)には、full_oauth
という構成があります。これはデフォルトでTrue
に設定されており、動作は前述のとおりです。
必要に応じて、 full_oauth
をFalse
に設定できます。この場合、ファンクションは、API Gatewayヘッダーからのインバウンド・コールにあるトークンを問い合せて、Oracle Fusion Applications Cloud Serviceへのアウトバウンド・コールでそのトークンを再使用します。2番目のトークンは生成されません。
次のコード・スニペットはApache HTTPライブラリを使用し、渡された認証トークンを使用してOracle Fusion Applications Cloud Service REST APIを呼び出します。
String fusionURL=”<yourfusionresturl>”;
HttpClient client = HttpClients.custom().build();
HttpUriRequest request = RequestBuilder.get().setUri(fusionURL).
setHeader(HttpHeaders.CONTENT_TYPE, "application/json").
setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + jwtToken).
build();
HttpResponse response = client.execute(request);
responseJson = EntityUtils.toString(response.getEntity());
status = response.getStatusLine().getStatusCode();
オプションで、Oracle Cloud Infrastructureでの認証ファンクションの定義
Oracle Cloud Infrastructure APIゲートウェイは、認証プロバイダとしてIDCSをネイティブでサポートしています。ただし、ゲートウェイではコール可能なファンクションの定義も許可されています。必要に応じて、この機能を使用してカスタム認証ファンクションを作成できます。
カスタム認証ファンクションはゲートウェイからのコールを受け取り、着信認可ヘッダーを渡します。ファンクションがtrueを戻す場合はファンクション・コールが許可され、反対にfalseを戻す場合はリクエストはHTTP 401エラー・コードを使用して拒否されます。この関数は、ソース・コード形式で指定され、関数内にデプロイされます。この関数は、そのOCIDを介してOCI API GATEWAYデプロイメント・ファイルで参照されます。コンソール内のデプロイ済ファンクションにナビゲートし、そのOCID列を展開することにより、OCIDを検出できます。関数をデプロイする前にResourceServerConfig.java
ファイルを編集する必要があります。これにより、関数のOracle Identity Cloud Serviceへの接続方法および使用するOracle Identity Cloud Service OAuthアプリケーションが定義されます。
次の関数の例では、クライアント・シークレットなどの機密の値をハードコーディングすることを防止しています。コメント// KMS Key for IDCS Client Secret
の下の4行で、コードによりOracle Cloud Infrastructureのキー管理機能であるOracle Cloud Infrastructure Vaultを使用してOAuthシークレットを復号化します。関数をデプロイする前に、Oracle Cloud Infrastructureコンソールにこれらの値を入力します。