2023年6月22日木曜日

OCIのシークレットを操作するアプリケーションを作成する(2) - シークレットの内容を操作する

 前の記事で作成したAPEXアプリケーションに、シークレットの内容を操作する機能を付加します。

APEXのWeb資格証明をシークレットとして保存します。シークレットとして保存したWeb資格証明の確認や更新をできるようにします。


RESTデータ・ソースの作成


Vault Secret Retrieval APIを呼び出すRESTデータ・ソースを作成します。

作成済みのシークレットのIdを取得します。Vault Secret Retrieval APIを呼び出す際の引数として与えます。

対話モード・レポートの鉛筆アイコンに対して、リンクのアドレスをコピーを実行し、p3_idとして渡されている値をコピーします。

javascript:apex.theme42.dialog('\u002Fords\u002Fr\u002Fapexdev\u002Fmanage-secrets\u002Fsecrets?p3_id=ocid1.vaultsecret.oc1.iad.ama****************************************************************354w6q\u0026p3_compartment_id=ocid1.tenancy.oc1..

共有コンポーネントRESTデータ・ソースを開き、作成を開始します。手順の最初の方は、Vault Secret ManagementのRESTデータ・ソースを作成したときと同じです。

ソース・タイプとしてOracle Cloud Infrastructure(OCI)を選択し、名前Vault Secret Retrievalとします。

URLエンドポイントとして、以下を指定します。

https://secrets.vaults.us-ashburn-1.oci.oraclecloud.com/20190301/secretbundles/シークレットのOCID

へ進みます。


リモート・サーバーとしてOCI Vault Secret Retrieval Endpoint(前の記事で作成済み)が選択されていることを確認します。

へ進みます。


認証が必要ですオンにし、資格証明としてOCI API Accessを選択します。

検出をクリックします。


secretIdで指定したシークレットが取得されます。

RESTデータ・ソースの作成をクリックします。


RESTデータ・ソースVault Secret Retrievalが作成されます。

編集画面を開きます。

最初にURLパス接頭辞よりsecretbundles以降の直書きされたsecretIdを削除します。

変更の適用をクリックします。


再度編集画面を開き、データ・プロファイルの編集をクリックします。


SECRETIDの名前をスネークケースのSECRET_IDに変更します。主キーYesにします。


キャメルケースのセレクタに合わせて、他の列名もスネークケースに書き換えます。

以上の変更を行い、変更の適用をクリックします。


操作行のフェッチの編集画面を開きます。鉛筆アイコンをクリックします。


操作URLパターン/{secretId}とします。

パラメータの追加をクリックします。


パラメータタイプとしてURLパターンを選択し、名前secretIdとします。詳細必須オンにします。

パラメータの追加をクリックします。


再度、パラメータの追加を開き、パラメータタイプとしてデータ・プロファイル列を選択します。

選択できるデータ・プロファイル列追加します。ただし、実際に使用する列はCONTENTのみです。


変更の適用をクリックします。


以上でRESTデータ・ソースVault Secret Retrievalは出来上がりです。

変更の適用をクリックします。

操作データベース・アクション行のフェッチURLパターンに、/{secretId}が設定されていることを再度確認してください。



シークレットを操作するパッケージの作成


APEXのWeb資格証明を作る情報からOCI Vaultのシークレットとして保存するデータを生成したり、その逆を行うファンクションを実装したパッケージUTL_APEX_WEB_CREDENTIAL_MANAGERを作成します。取り出したシークレットを元にAPEXのWeb資格証明を作成するプロシージャも含みます。

PL/SQLのコードは記事の末尾に添付します。

コードの実行には、SQLワークショップSQLスクリプトが使えます。


Web資格証明の扱いを追加



フォーム・リージョンのページ・アイテムP3_CONTENTは、ボールトに保存されるシークレットにそのまま対応しています。このシークレットにAPEXのWeb資格証明の情報を含めます。

ページ・アイテムP3_CONTENTを直接扱うことは無くなるため、タイプ非表示に変更します。


Web資格証明の情報を入力するページ・アイテムを作成します。

タイプは特に指定が無ければテキスト・フィールドラベルはページ・アイテム名からページ番号を外し、読みやすいように変えます。セッション・ステートストレージはすべてリクエストごと(メモリーのみ)を設定します。


ページ・アイテムP3_CREDENTIAL_NAMEP3_CREDENTIAL_STATIC_IDP3_AUTHENTICATION_TYPEを作成します。P3_AUTHENTICATION_TYPELOVタイプ静的値を選択します。

追加値の表示オフNULL値の表示オンNULL表示値として-- Select Authentication Type --を設定します。


LOV静的値として、以下の設定を行います。

表示値としてBasicHTTP HeaderQuery ParameterOAuth2OCISecret Dataを設定し、それらの戻り値としてBASICHTTP_HEADERHTTP_QUERY_STRINGOAUTH2_CLIENT_CREDENTIALSOCISECRET_DATAを設定します。

実行時にソートオフにします。


P3_AUTHENTICATION_TYPEには、APEXのWeb資格証明として設定可能なタイプを選択肢として設定しています。ただし、SECRET_DATAには対応するWeb資格証明のタイプはありません。APEXの機能に含まれていない、JWTにRS256の署名を付けるための秘密キーを保存する用途を想定しています。

選択したWeb資格証明ごとに入力可能なページ・アイテムの表示を切り替えるために、上記の選択肢に対応した静的コンテンツのリージョンを作成します。

リージョンのタイトルLOVの表示値外観テンプレートBlank with Attributesを選択します。静的IDとしてLOVの戻り値を設定します。

リージョンとしてBasicHTTP HeaderQuery ParameterOAuth2OCISecret Dataを作成します。


リージョンBasicにページ・アイテムP3_USERNAMEP3_PASSWORDを作成します。

リージョンHTTP Headerにページ・アイテムP3_HEADER_NAMEP3_HEADER_VALUEを作成します。

リージョンQuery Parameterにページ・アイテムP3_PARAMETER_NAMEP3_PARAMETER_VALUEを作成します。

リージョンOAuth2にページ・アイテムP3_CLIENT_IDP3_CLIENT_SECRETP3_SCOPEを作成します。

リージョンOCIにページ・アイテムP3_USER_IDP3_PRIVATE_KEYP3_TENANCY_IDP3_FINGERPRINTを作成します。

リージョンSecret Dataにページ・アイテムP3_SECRET_DATAを作成します。

このうち、P3_PRIVATE_KEYP3_SECRET_DATAのタイプはテキスト領域にします。

続けてP3_ALLOWED_URLSP3_PROMPT_ON_INSTALLP3_CREDENTIAL_COMMENTを作成します。P3_ALLOWED_URLSP3_CREDENTIAL_COMMENTタイプテキスト領域P3_PROMPT_ON_INSTALLタイプ切替えとします。


ページ・アイテムP3_AUTHENTICATION_TYPEの選択により、表示するページ・アイテムを切り替えるためにP3_AUTHENTICATION_TYPE動的アクションを作成します。

識別名前onChange show / hideとします。タイミングイベントはページ・アイテムのデフォルトである変更です。


TRUEアクションとしてJavaScriptコードの実行を選択し、設定コードに以下を記述します。

/*
* 選択したリージョンのみを表示する。
*/
const v = $v(this.triggeringElement);
["BASIC","HTTP_HEADER","HTTP_QUERY_STRING","OAUTH2_CLIENT_CREDENTIALS","OCI","SECRET_DATA"].forEach(
(e) => {
if ( e == v ) {
$x_Show(document.getElementById(e));
}
else
{
$x_Hide(document.getElementById(e));
}
}
);
/*
* APEXのWeb資格証明のパラメータは、SECRET_DATAのときは表示しない。
*/
if ( v == "SECRET_DATA" ) {
apex.items.P3_CREDENTIAL_NAME.hide();
apex.items.P3_CREDENTIAL_STATIC_ID.hide();
apex.items.P3_ALLOWED_URLS.hide();
apex.items.P3_PROMPT_ON_INSTALL.hide();
apex.items.P3_CREDENTIAL_COMMENT.hide();
}
else
{
apex.items.P3_CREDENTIAL_NAME.show();
apex.items.P3_CREDENTIAL_STATIC_ID.show();
apex.items.P3_ALLOWED_URLS.show();
apex.items.P3_PROMPT_ON_INSTALL.show();
apex.items.P3_CREDENTIAL_COMMENT.show();
}

初期化時に実行オンにします。


ページ・アイテムP3_KEY_IDP3_VAULT_IDP3_COMPARTMENT_IDは、常にアプリケーション定義の置換文字列に設定した値にするので、これらはページ・アイテムとして非表示にします。


シークレットの名前P3_SECRET_NAMEは更新不可なので、ページ・アイテムP3_IDアイテムがNULLでないときに読取り専用にします。


Vault Secret Retrieval APIを呼び出して、シークレットを取得します。

ヘッダーの前プロセスを作成し、初期化フォームSecret Detail下に配置します。

識別名前Get SecretタイプAPIの呼び出しを選択します。設定タイプRESTソースRESTソースとしてVault Secret Retrieval、操作としてGET - /{secretId}を選択します。

サーバー側の条件タイプとしてアイテムはNULLではないを選択し、アイテムとしてP3_IDを指定します。


パラメータsecretIdを選択し、タイプアイテムアイテムとしてP3_IDを指定します。


パラメータCONTENTを選択し、パラメータ出力を無視オフに変更します。アイテムとしてP3_CONTENTを指定します。


以上で、ページ・アイテムP3_IDの値をsecretIdとしてVault Secret Retrieval APIが呼び出され、CONTENTとして返されたシークレットの値がページ・アイテムP3_CONTENTに設定されます。

それ以外の出力パラメータは不要なので、出力を無視オンのままにしておきます。

取得したシークレットからWeb資格証明の値を取り出します。

ヘッダーの前プロセスを作成し、シークレットの取り出し下に配置します。

識別名前Extract Credential From SecretタイプAPIの呼出しを選択します。設定タイプPL/SQLパッケージパッケージとしてUTL_APEX_WEB_CREDENTIAL_MANAGERを選択します。プロシージャまたはファンクションとしてEXTRACT_CREDENTIAL_FROM_SECRETを選択します。

サーバー側の条件タイプとしてアイテムはNULLではないアイテムとしてP3_CONTENTを指定します。P3_CONTENTにデータが設定されている場合に限り、その値よりWeb資格証明のデータを取り出します。


パラメータp_secretを選択し、タイプアイテムアイテムとしてP3_CONTENTを指定します。これ以外のパラメータは、パラメータからページ・アイテムが自動的に選択されるようにページ・アイテム名を選んでいるため、それぞれのパラメータとして適切なページ・アイテムが設定されています。

記述ミスなどもあり得るため、パラメータの設定は確認することを勧めます。


シークレットからWeb資格証明の値を取り出しが実装されました。反対にWeb資格証明の値よりシークレットを作成する処理を実装します。

プロセス・ビューを表示し、Web資格証明からシークレットを生成するプロセスを作成します。プロセスプロセス・フォームSecret Detailの上に配置します。

識別名前Create Secret from CredentialタイプAPIの呼出しを選択します。設定タイプPL/SQLパッケージパッケージとしてUTL_APEX_WEB_CREDENTIAL_MANAGERを選択します。プロシージャまたはファンクションとしてCREATE_SECRET_FROM_CREDENTIALを選択します。

サーバー側の条件のタイプとしてリクエストは値に含まれるを選択し、CREATE SAVEを指定します。ボタン作成または変更の適用を押したときに、このプロセスを実行します。


パラメータファンクションの結果アイテムP3_CONTENTを指定します。


以上で、OCI VaultのシークレットとしてWeb資格証明を保存すること、およびシークレットからWeb資格証明のデータを取り出すことができるようになりました。

対話モード・レポートにシークレットをAPEXのWeb資格証明としてインストールするボタンを作成します。

対話モード・レポートのローカル後処理タイプSQL問合せに変更し、SQL問合せにインストールボタンとなる列INSTALLを追加します。

select ID,
KEY_ID,
VAULT_ID,
SECRET_NAME,
CREATED_BY,
CREATED_ON,
DESCRIPTION,
TIME_CREATED,
COMPARTMENT_ID,
LIFECYCLE_STATE,
ROTATION_CONFIG,
TIME_OF_DELETION,
LIFECYCLE_DETAILS,
IS_AUTO_GENERATION_ENABLED,
SECRET_GENERATION_CONTEXT,
TIME_OF_CURRENT_VERSION_EXPIRY,
'INSTALL' as INSTALL
from #APEX$SOURCE_DATA#
where KEY_ID = :G_KEY_ID
and VAULT_ID = :G_VAULT_ID
and COMPARTMENT_ID = :G_COMPARTMENT_ID


追加された列INSTALL列の書式HTML式に以下を記述します。このボタンをクリックしたときに、列のID(その列のシークレットのOCID)を引数にしてAPEXアクションinstall-web-credentialを呼び出します。

<button type="button" class="t-Button" data-action="install-web-credential?secretId=#ID#">Install</button>


KEY_IDVAULT_IDおよびCOMPARTMENT_IDといったOCIDは、あまり表示したくないため、タイプ非表示に変更します。


シークレットのOCIDを引数にしてOCI Vaultよりシークレットを取り出し、取り出したシークレットからAPEXのWeb資格証明を作成するプロセスを、Ajaxコールバックとして作成します。

識別名前INSTALL_WEB_CREDENTIALタイプコードの実行です。ソースPL/SQLコードとして以下を記述します。

declare
l_key_id varchar2(255);
l_params apex_exec.t_parameters;
l_secret varchar2(4000);
begin
apex_exec.add_parameter( l_params, 'secretId', apex_application.g_x01 );
apex_exec.execute_rest_source(
p_static_id => 'vault_secret_retrieval',
p_operation => 'GET',
p_parameters => l_params );
l_secret := apex_exec.get_parameter_varchar2( l_params, 'CONTENT');
-- apex_debug.info('secret %s', l_secret);
utl_apex_web_credential_manager.create_credential_from_secret(
p_secret => l_secret
);
htp.p('{ "success": true }');
exception
when others then
htp.p('{ "success": false }');
end;


ページ・プロパティJavaScriptページ・ロード時に実行に、APEXアクションのinstall-web-credentialを定義します。以下のコードを記述します。

apex.actions.add([
{
name: "install-web-credential",
action: function( event, element, args) {
/* 確認のためのダイアログを表示する */
apex.message.confirm(
"Are you sure?", function( okPressed ) {
/* OCI VaultのシークレットからWeb資格証明を作成/更新する。 */
apex.server.process(
"INSTALL_WEB_CREDENTIAL",
{
x01: args.secretId
}
,{
success: function( data ) {
if (data.success) {
/* 成功メッセージの表示 */
apex.message.showPageSuccess( "Web Credential Created or Updated!" );
}
else
{
/* 失敗メッセージの表示 */
apex.message.showErrors([
{
type: "error",
location: "page",
message: "Web Credential Creation or Update Failed!",
unsafe: false
}
]);
}
}
}
);
}
);
}
}
]);

Web資格証明をAPEXアプリケーションから作成するには、アプリケーション定義セキュリティ詳細にある、ランタイムAPIの使用状況に含まれるワークスペース・リポジトリを変更チェックを入れる必要があります。


以上でアプリケーションは完成です。

動作の確認を行います。

対話モード・レポートのページから作成をクリックします。

以下ではSecret NameCredential NameCredential Static IdTEST_CRED01DescriptionCredential CommentテストでWeb資格証明を保存する。Authentication TypeBasicUsernamescottPasswordtigerとしています。

作成をクリックすると、シークレットが作成されます。


レポートに作成したシークレットが表示されます。


作成したシークレットの鉛筆アイコンをクリックし、編集ダイアログを開きます。

UsernamePasswordをぞれぞれscott4tiger4に変更し、変更の適用をクリックします。


Installを実行します。

Web資格証明の作成または更新が成功すると、成功メッセージが表示されます。


ワークスペース・ユーティリティWeb資格証明から、作成されたWeb資格証明TEST_CRED01の内容を確認します。パスワードは表示されないため確認できませんが、その他の情報はAPEXアプリケーションで設定した値になっていることが確認できます。


以上で、作成したAPEXアプリケーションの動作確認ができました。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/manage-secrets.zip

次の記事で最後になりますが、RESTデータ・ソースを扱うアプリケーションを作成するにあたって、考慮すべき点について説明します。

続く


create or replace package utl_apex_web_credential_manager
as
/**
* APEXのWeb資格証明に必要なデータを、OCI Vaultのシークレットに保存できる
* Base64エンコーディングされたJSONの文字列として返す。
*/
function create_secret_from_credential(
p_authentication_type in varchar2
,p_credential_static_id in varchar2
,p_credential_name in varchar2
,p_allowed_urls in varchar2
,p_prompt_on_install in boolean
,p_credential_comment in varchar2
/* Basic */
,p_username in varchar2
,p_password in varchar2
/* HTTP Header */
,p_header_name in varchar2
,p_header_value in varchar2
/* Query Parameter */
,p_parameter_name in varchar2
,p_parameter_value in varchar2
/* OAuth2 */
,p_client_id in varchar2
,p_client_secret in varchar2
,p_scope in varchar2
/* OCI */
,p_user_id in varchar2
,p_private_key in varchar2
,p_tenancy_id in varchar2
,p_fingerprint in varchar2
/* Secret Data */
,p_secret_data in varchar2
) return clob;
/**
* シークレットとして保存されていたBase64でエンコードされたJSONドキュメントより、
* Web資格証明の作成に必要なデータを取り出す。
*/
procedure extract_credential_from_secret(
p_secret in clob
,p_credential_name out varchar2
,p_credential_static_id out varchar2
,p_authentication_type out varchar2
,p_allowed_urls out varchar2
,p_prompt_on_install out boolean
,p_credential_comment out varchar2
/* Basic */
,p_username out varchar2
,p_password out varchar2
/* HTTP Header */
,p_header_name out varchar2
,p_header_value out varchar2
/* Query Parameter */
,p_parameter_name out varchar2
,p_parameter_value out varchar2
/* OAuth2 */
,p_client_id out varchar2
,p_client_secret out varchar2
,p_scope out varchar2
/* OCI */
,p_user_id out varchar2
,p_private_key out varchar2
,p_tenancy_id out varchar2
,p_fingerprint out varchar2
/* Raw Secret Data */
,p_secret_data out varchar2
);
/**
* OCI Vaultのシークレットとして保存した文字列より、APEXのWeb資格証明を作成する。
*
* APEX_CREDENTIAL.CREATE_CREDENTIALの呼び出し時に与える
* p_credential_name, p_credential_static_id, その他の引数の値を
* 設定できるのは、Web資格証明の作成時に限られる。そのため、これらの値を変更するには
* Web資格証明を作り直す必要がある。
*
* OCI Vaultのシークレットとして保存しているalllowed URLs、prompt on installや
* credential commentといった値はシークレットとしては変更できるが、その値を変更して
* APEX側に保存されている既存のWeb資格証明をアップデートしても、更新されるのは
* set_persistent_credentialで更新可能な値に限られる。
*/
procedure create_credential_from_secret(
p_secret in clob
,p_force_update in boolean default false
,p_workspace in varchar2 default null
);
end utl_apex_web_credential_manager;
/
create or replace package body utl_apex_web_credential_manager
as
/**
* Web資格証明に共通しているパラメータを、シークレットになるJSONに書き込む。
*
* APEX_CREDENTIAL.CREATE_CREDENTIALの引数に準ずる。
* Ref: https://docs.oracle.com/en/database/oracle/apex/23.2/aeapi/CREATE_CREDENTIAL-Procedure.html
*/
procedure set_common_attributes(
p_credential in out json_object_t
,p_credential_static_id in varchar2
,p_credential_name in varchar2 default null /* static_id if null */
,p_authentication_type in varchar2
,p_scope in varchar2 default null
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
)
as
begin
/* p_credentialの指定がなければ、オブジェクトを生成する。 */
if p_credential is null then
p_credential := json_object_t();
end if;
/* credential nameの指定がなければ静的IDを名前にする。 */
if p_credential_name is not null then
p_credential.put('credential_name', p_credential_name);
else
p_credential.put('credential_name', p_credential_static_id);
end if;
/* 必須パラメータ */
p_credential.put('credential_static_id', p_credential_static_id);
p_credential.put('authentication_type', p_authentication_type);
/* 任意パラメータ */
if p_scope is not null then
p_credential.put('scope', p_scope);
end if;
if p_allowed_urls is not null then
p_credential.put('allowed_urls', p_allowed_urls);
end if;
if p_prompt_on_install is not null then
p_credential.put('prompt_on_install', p_prompt_on_install);
end if;
if p_credential_comment is not null then
p_credential.put('credential_comment', p_credential_comment);
end if;
end set_common_attributes;
/**
* 基本認証よりシークレットを生成する。
*/
function create_secret_from_basic_cred(
p_credential_static_id in varchar2
,p_credential_name in varchar2 default null
,p_username in varchar2
,p_password in varchar2
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
) return clob
as
l_credential json_object_t := json_object_t();
begin
set_common_attributes(
p_credential => l_credential
,p_credential_name => p_credential_name
,p_credential_static_id => p_credential_static_id
,p_authentication_type => apex_credential.C_TYPE_BASIC
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
l_credential.put('username', p_username);
l_credential.put('password', p_password);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_basic_cred;
/**
* HTTPヘッダーよりシークレットを生成する。
*/
function create_secret_from_http_header_cred(
p_credential_static_id in varchar2
,p_credential_name in varchar2 default null
,p_header_name in varchar2
,p_header_value in varchar2
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
) return clob
as
l_credential json_object_t := json_object_t();
begin
set_common_attributes(
p_credential => l_credential
,p_credential_name => p_credential_name
,p_credential_static_id => p_credential_static_id
,p_authentication_type => apex_credential.C_TYPE_HTTP_HEADER
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
l_credential.put('header_name', p_header_name);
l_credential.put('header_value', p_header_value);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_http_header_cred;
/**
* 問合せパラメータよりシークレットを生成する。
*/
function create_secret_from_query_parameter_cred(
p_credential_static_id in varchar2
,p_credential_name in varchar2 default null
,p_parameter_name in varchar2
,p_parameter_value in varchar2
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
) return clob
as
l_credential json_object_t := json_object_t();
begin
set_common_attributes(
p_credential => l_credential
,p_credential_name => p_credential_name
,p_credential_static_id => p_credential_static_id
,p_authentication_type => apex_credential.C_TYPE_HTTP_QUERY_STRING
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
l_credential.put('parameter_name', p_parameter_name);
l_credential.put('parameter_value', p_parameter_value);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_query_parameter_cred;
/**
* OAuth2よりシークレットを生成する。
*/
function create_secret_from_oauth2_cred(
p_credential_static_id in varchar2
,p_credential_name in varchar2 default null
,p_client_id in varchar2
,p_client_secret in varchar2
,p_scope in varchar2 default null
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
) return clob
as
l_credential json_object_t := json_object_t();
begin
set_common_attributes(
p_credential => l_credential
,p_credential_name => p_credential_name
,p_credential_static_id => p_credential_static_id
,p_authentication_type => apex_credential.C_TYPE_HTTP_QUERY_STRING
,p_scope => p_scope
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
l_credential.put('client_id', p_client_id);
l_credential.put('client_secret', p_client_secret);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_oauth2_cred;
/**
* OCIよりシークレットを生成する。
*/
function create_secret_from_oci_cred(
p_credential_static_id in varchar2
,p_credential_name in varchar2 default null
,p_user_id in varchar2
,p_private_key in varchar2
,p_tenancy_id in varchar2
,p_fingerprint in varchar2
,p_allowed_urls in varchar2 default null
,p_prompt_on_install in boolean default false
,p_credential_comment in varchar2 default null
) return clob
as
l_credential json_object_t := json_object_t();
begin
set_common_attributes(
p_credential => l_credential
,p_credential_name => p_credential_name
,p_credential_static_id => p_credential_static_id
,p_authentication_type => apex_credential.C_TYPE_HTTP_QUERY_STRING
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
l_credential.put('user_id', p_user_id);
l_credential.put('private_key', p_private_key);
l_credential.put('tenancy_id', p_tenancy_id);
l_credential.put('finterprint', p_fingerprint);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_oci_cred;
/**
* 生のシークレットであるデータよりシークレットを生成する。
* これはAPEXのWeb資格証明にはならない。
*/
function create_secret_from_secret_data(
p_secret_data in varchar2
) return clob
as
l_credential json_object_t := json_object_t();
begin
l_credential.put('credential_type', 'SECRET_DATA');
l_credential.put('secret_data', p_secret_data);
return apex_web_service.blob2clobbase64(l_credential.to_blob());
end create_secret_from_secret_data;
/**
* APEXのWeb資格証明に必要なデータを、OCI Vaultのシークレットに保存できる
* Base64エンコーディングされたJSONの文字列として返す。
*/
function create_secret_from_credential(
p_authentication_type in varchar2
,p_credential_static_id in varchar2
,p_credential_name in varchar2
,p_allowed_urls in varchar2
,p_prompt_on_install in boolean
,p_credential_comment in varchar2
/* Basic */
,p_username in varchar2
,p_password in varchar2
/* HTTP Header */
,p_header_name in varchar2
,p_header_value in varchar2
/* Query Parameter */
,p_parameter_name in varchar2
,p_parameter_value in varchar2
/* OAuth2 */
,p_client_id in varchar2
,p_client_secret in varchar2
,p_scope in varchar2
/* OCI */
,p_user_id in varchar2
,p_private_key in varchar2
,p_tenancy_id in varchar2
,p_fingerprint in varchar2
/* Secret Data */
,p_secret_data in varchar2
) return clob
as
l_secret clob;
e_invalid_authentication_type exception;
begin
if p_authentication_type = apex_credential.C_TYPE_BASIC then
l_secret := utl_apex_web_credential_manager.create_secret_from_basic_cred(
p_credential_static_id => p_credential_static_id
,p_credential_name => p_credential_name
,p_username => p_username
,p_password => p_password
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
elsif p_authentication_type = apex_credential.C_TYPE_HTTP_HEADER then
l_secret := utl_apex_web_credential_manager.create_secret_from_http_header_cred(
p_credential_static_id => p_credential_static_id
,p_credential_name => p_credential_name
,p_header_name => p_header_name
,p_header_value => p_header_value
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
elsif p_authentication_type = apex_credential.C_TYPE_HTTP_QUERY_STRING then
l_secret := utl_apex_web_credential_manager.create_secret_from_query_parameter_cred(
p_credential_static_id => p_credential_static_id
,p_credential_name => p_credential_name
,p_parameter_name => p_parameter_name
,p_parameter_value => p_parameter_value
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
elsif p_authentication_type = apex_credential.C_TYPE_OAUTH_CLIENT_CRED then
l_secret := utl_apex_web_credential_manager.create_secret_from_oauth2_cred(
p_credential_static_id => p_credential_static_id
,p_credential_name => p_credential_name
,p_client_id => p_client_id
,p_client_secret => p_client_secret
,p_scope => p_scope
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
elsif p_authentication_type = apex_credential.C_TYPE_OCI then
l_secret := utl_apex_web_credential_manager.create_secret_from_oci_cred(
p_credential_static_id => p_credential_static_id
,p_credential_name => p_credential_name
,p_user_id => p_user_id
,p_private_key => p_private_key
,p_tenancy_id => p_tenancy_id
,p_fingerprint => p_fingerprint
,p_allowed_urls => p_allowed_urls
,p_prompt_on_install => p_prompt_on_install
,p_credential_comment => p_credential_comment
);
elsif p_authentication_type = 'SECRET_DATA' then
l_secret := utl_apex_web_credential_manager.create_secret_from_secret_data(
p_secret_data => p_secret_data
);
else
raise e_invalid_authentication_type;
end if;
return l_secret;
end create_secret_from_credential;
/**
* シークレットとして保存されていたBase64でエンコードされたJSONドキュメントより、
* Web資格証明の作成に必要なデータを取り出す。
*/
procedure extract_credential_from_secret(
p_secret in clob
,p_credential_name out varchar2
,p_credential_static_id out varchar2
,p_authentication_type out varchar2
,p_allowed_urls out varchar2
,p_prompt_on_install out boolean
,p_credential_comment out varchar2
/* Basic */
,p_username out varchar2
,p_password out varchar2
/* HTTP Header */
,p_header_name out varchar2
,p_header_value out varchar2
/* Query Parameter */
,p_parameter_name out varchar2
,p_parameter_value out varchar2
/* OAuth2 */
,p_client_id out varchar2
,p_client_secret out varchar2
,p_scope out varchar2
/* OCI */
,p_user_id out varchar2
,p_private_key out varchar2
,p_tenancy_id out varchar2
,p_fingerprint out varchar2
/* Raw - Secret Data */
,p_secret_data out varchar2
)
as
l_blob blob;
l_credential json_object_t;
begin
l_blob := apex_web_service.clobbase642blob(
p_clob => p_secret
);
l_credential := json_object_t.parse(l_blob);
/* 共通の属性を取り出す。 */
p_credential_name := l_credential.get_string('credential_name');
p_credential_static_id := l_credential.get_string('credential_static_id');
p_authentication_type := l_credential.get_string('authentication_type');
p_allowed_urls := l_credential.get_string('allowed_urls');
p_prompt_on_install := l_credential.get_boolean('prompt_on_install');
p_credential_comment := l_credential.get_string('credential_comment');
case p_authentication_type
when apex_credential.C_TYPE_BASIC then
p_username := l_credential.get_string('username');
p_password := l_credential.get_string('password');
when apex_credential.C_TYPE_HTTP_HEADER then
p_header_name := l_credential.get_string('header_name');
p_header_value := l_credential.get_string('header_value');
when apex_credential.C_TYPE_HTTP_QUERY_STRING then
p_parameter_name := l_credential.get_string('parameter_name');
p_parameter_value := l_credential.get_string('parameter_value');
when apex_credential.C_TYPE_OAUTH_CLIENT_CRED then
p_client_id := l_credential.get_string('client_id');
p_client_secret := l_credential.get_string('client_secret');
p_scope := l_credential.get_string('scope');
when apex_credential.C_TYPE_OCI then
p_user_id := l_credential.get_string('user_id');
p_private_key := l_credential.get_string('private_key');
p_tenancy_id := l_credential.get_string('tenancy_id');
p_fingerprint := l_credential.get_string('fingerprint');
else
p_secret_data := l_credential.get_string('secret_data');
end case;
end extract_credential_from_secret;
/**
* OCI Vaultのシークレットとして保存した文字列より、APEXのWeb資格証明を作成する。
*/
procedure create_credential_from_secret(
p_secret in clob
,p_force_update in boolean
,p_workspace in varchar2
)
as
l_blob blob;
l_credential json_object_t;
l_credential_name varchar2(400);
l_credential_static_id varchar2(400);
l_authentication_type varchar2(20);
l_allowed_urls varchar2(4000);
l_prompt_on_install boolean;
l_credential_comment varchar2(4000);
l_scope varchar2(4000);
l_credential_code_type apex_workspace_credentials.credential_type_code%type;
l_count number;
is_new boolean;
e_authenticantication_type_is_changed exception;
begin
/*
* 引数にワークスペース名が設定されていれば設定する。
* プロシージャーがSQLclなどから呼び出されたときの対応だが、
* ワークスペースを指定したときの動作は未確認。
*/
if p_workspace is not null then
apex_util.set_workspace( p_workspace => p_workspace );
end if;
/*
* Base64でエンコードされたシークレットをデコードしてJSONとして扱えるように変換する。
*/
l_blob := apex_web_service.clobbase642blob(
p_clob => p_secret
);
l_credential := json_object_t.parse(l_blob);
/*
* Web資格証明の有無を確認する。
*/
l_credential_static_id := l_credential.get_string('credential_static_id');
l_authentication_type := l_credential.get_string('authentication_type');
is_new := false;
begin
select credential_type_code into l_credential_code_type from apex_workspace_credentials
where static_id = l_credential_static_id;
exception
when no_data_found then
/* 新規作成 */
is_new := true;
end;
/*
* Web資格証明がすでに作成済みのときの対応。
*/
if not is_new then
if p_force_update then
/* 再作成の指定があれば、作成済みのWeb資格証明を削除する。 */
apex_credential.drop_credential( p_credential_static_id => l_credential_static_id );
elsif l_credential_code_type <> l_authentication_type then
/* Web資格証明のタイプの変更は許さない。 */
raise e_authenticantication_type_is_changed;
end if;
end if;
/*
* Web資格証明を新規作成する。
*/
if is_new then
/* 共通の属性を取り出す。 */
l_credential_name := l_credential.get_string('credential_name');
l_allowed_urls := l_credential.get_string('allowd_urls');
l_prompt_on_install := l_credential.get_boolean('prompt_on_install');
l_credential_comment := l_credential.get_string('credential_comment');
l_scope := l_credential.get_string('scope');
/* Web資格証明を作成する。 */
apex_credential.create_credential(
p_credential_name => l_credential_name
,p_credential_static_id => l_credential_static_id
,p_authentication_type => l_authentication_type
,p_scope => l_scope
,p_allowed_urls => apex_string.split(l_allowed_urls,',')
,p_prompt_on_install => l_prompt_on_install
,p_credential_comment => l_credential_comment
);
end if;
/* Web資格証明を更新する。 */
case l_authentication_type
when apex_credential.C_TYPE_BASIC then
apex_credential.set_persistent_credentials(
p_credential_static_id => l_credential_static_id
,p_username => l_credential.get_string('username')
,p_password => l_credential.get_string('password')
);
when apex_credential.C_TYPE_HTTP_HEADER then
apex_credential.set_persistent_credentials(
p_credential_static_id =>l_credential_static_id
,p_username => l_credential.get_string('header_name')
,p_password => l_credential.get_string('header_value')
);
when apex_credential.C_TYPE_HTTP_QUERY_STRING then
apex_credential.set_persistent_credentials(
p_credential_static_id => l_credential_static_id
,p_username => l_credential.get_string('parameter_name')
,p_password => l_credential.get_string('parameter_value')
);
when apex_credential.C_TYPE_OAUTH_CLIENT_CRED then
apex_credential.set_persistent_credentials(
p_credential_static_id => l_credential_static_id
,p_username => l_credential.get_string('client_id')
,p_password => l_credential.get_string('client_secret')
);
when apex_credential.C_TYPE_OCI then
apex_credential.set_persistent_credentials(
p_credential_static_id => l_credential_static_id
,p_client_id => l_credential.get_string('user_id')
,p_client_secret => l_credential.get_string('private_key')
,p_namespace => l_credential.get_string('tenancy_id')
,p_fingerprint => l_credential.get_string('finterprint')
);
end case;
end create_credential_from_secret;
end utl_apex_web_credential_manager;
/