2023年2月14日火曜日

ORDS REST APIのOAuth2による保護とAPEXからの呼び出し

 Oracle REST Data ServicesのREST APIをOAuth2によって保護する手順と、保護されたREST APIをAPEXから呼び出す方法について確認します。

確認作業にはAlways FreeのAutonomous Databaseを使用します。

最終的に、OAuth2の認証で保護されたREST APIを呼び出すAPEXアプリケーションを作成します。

APEXでワークスペースを作成し、同時にワークスペース・スキーマも作成している(スキーマ名はWKSP_ワークスペース名)という環境を前提とします。

最初に呼び出すREST APIを準備します。サンプルのHRサービスをインストールします。

SQLワークショップRESTfulサービスを開きます。


初回アクセス時はORDSにスキーマが登録されていません。

ORDSにスキーマを登録をクリックし、スキーマを登録します。


ダイアログが開きます。

RESTfulサービスの有効化ONスキーマ別名として(WKSP_で始まるスキーマ名ではなく)ワークスペース名がデフォルトで設定されます。サンプル・サービスのインストールONにします。ここでインストールされるサンプル・サービスを使って、確認作業を行います。メタデータ・アクセスに必要な認可OFFから変更しません。

スキーマ属性の保存をクリックします。


スキーマが有効化され、サンプル・サービスがインストールされます。


REST APIの動作を確認します。

モジュールoracle.example.hr、テンプレートemployees/GETハンドラを開きます。


完全なURLをコピーし、ブラウザで呼び出します。JSON形式のレスポンスが表示されたら、サンプルのインストールは完了です。


ひとつ気になった点があります。

APEXより作成されたスキーマが持つ権限が、データベース・アクション(ORDS)から見ると足りないと報告されます。

データベース・アクションデータベース・ユーザーより該当するワークスペース・スキーマの編集を開きます。

CONNECTとRESOURCEのロールが無い、と言われます。


Oracle Databaseのドキュメント2日でデータベース管理者に、以下の記載があります。

7.2 ユーザー権限およびロールについて

ノート:

これらのロールに依存せずに、データベース・セキュリティ用に独自のロールを設計することをお薦めします。

これらのロールは、将来のリリースのOracle Databaseでは自動生成されない可能性があります。



なので、とりあえずこの警告は無視します。以前に作成したワークスペースでは、ワークスペース・スキーマの権限よりCREATE SESSIONが抜けている場合があるようです。そのような場合は、CREATE SESSIONの権限をワークスペース・スキーマに割り当てます。

GRANT CREATE SESSION TO ワークスペース・スキーマ;

これからロールや権限を定義します。APEXの画面とデータベース・アクションの両方から、同じ作業を実施できます。RESTサービス自体はOracle REST Data Servicesのチームが開発しているのですが、正直にいってAPEXの開発者にとってはAPEXのインターフェースの方が使いやすいです。

APEXからは、OAuth2のクライアントの作成とロールの割り当てを行うGUIは提供されていません。そのため、SQLコマンドよりパッケージOAUTHのプロシージャを呼び出す必要があります。OAuth2のクライアントの管理はデータベース・アクションの方が容易ですが、APEXのインターフェースを使って以降の作業を進めます。

まず、ロールを作成します。

左ペインのツリーからロールを選択し、右ペインのロールの作成をクリックします。


ロール名HR Example Roleとします。

ロールの作成をクリックします。


ロールHR Example Roleが作成されます。


次に権限を作成します。

左ペインのツリーから権限を選んで、右ペインの権限の作成をクリックします。


名前oracle.example.hrタイトルHR Exampleとします。

ロールHR Example Roleを選択し、保護されたモジュールとしてoracle.example.hrを選択します。

保護されたリソースとして、モジュール全体ではなく、個別のテンプレートごとに保護を設定することもできます。

権限の作成をクリックします。


権限oracle.example.hrが作成されます。


この時点でRESTモジュールのoracle.example.hrは、呼び出しの際にOAuth2による認証が必要になっています。

OAuth2のクライアントとしてHR Clientを作成します。作成したクライアントにロールHR Example Roleを割り当てます。OAUTH.CREATE_CLIENTの引数p_grant_typeはつねにclient_credentialsです。(APEXはclient_credentialsのみをサポートしているため)



クライアントが作成されたら、CLIENT_IDCLIENT_SECRETを確認します。USER_ORDS_CLIENTSビューを検索します。

select name, client_id, client_secret from user_ords_clients;

これらの値は、APEX側からREST APIを呼び出す際に使用します。コピーして保存しておきます。


クライアントに割り当てられたロールは、USER_ORDS_CLIENT_ROLESビューを検索して確認できます。

select * from user_ords_client_roles;


以上でREST API側の準備は完了です。

これより作成したREST APIを呼び出すAPEXアプリケーションを作成します。

最初にWeb資格証明を作成します。

アプリケーション・ビルダーワークスペース・ユーティリティを開きます。


Web資格証明を開きます。


作成済みのWeb資格証明が一覧されます。作成をクリックします。


名前HR Example Cred静的識別子HR_EXAMPLE_CREDとします。

認証タイプとしてOAuth2クライアント資格証明フローを選択し、クライアントIDまたはユーザー名に、USER_OAUTH_CLIENTSビューの列CLIENT_IDとして取得した値、クライアント・シークレットまたはパスワードに、列CLIENT_SECRETとして取得した値を設定します。

以上で作成をクリックします。


Web資格証明HR Example Credが作成されます。


アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前ORDS REST Testとします。


アプリケーションが作成されたら、共有コンポーネントRESTデータ・ソースを開きます。

リモート表EMPを一覧するRESTデータ・ソースを作成します。


作成をクリックします。


RESTデータ・ソースの作成最初からを選びます。

へ進みます。


RESTデータ・ソース・タイプとしてOracle REST Data Servicesを選択します。名前Remote EMP Tableとします。

URLエンドポイントとして、モジュールoracle.example.hr、テンプレートemployees/完全なURL(REST APIのテストに使用したURL)を入力します。

へ進みます。


リモート・サーバーベースURLサービスURLパスは自動で検出されます。変更は不要です。

へ進みます。


認証が必要です。ONにします。資格証明として先ほど作成したHR Example Credを選択します。

OAuthトークンURLは自動的に設定されます。APEX_WEB_SERVICE.MAKE_REST_REQUESTを使ってPL/SQLからREST APIを呼び出す際に、このOAuthトークンURLを引数p_token_urlに指定します。そのため、この値は後で使用します。

検出をクリックします。


REST APIが呼び出されデータが表示されます。

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


RESTデータ・ソースRemote EMP Tableが作成されました。


このRESTデータ・ソースをソースとした対話モード・レポートを作成します。

ページの作成を実行します。


対話モード・レポートを選択します。


ページ定義名前EMPページ・モード標準とします。データ・ソースとしてRESTデータ・ソースを選択し、RESTデータ・ソースとしてRemote EMP Tableを選びます。

ページの作成を実行します。


対話モード・レポートのページが作成されます。


ページを実行すると、OAuth2の認証で保護されたRESTサービスが呼び出せていることが確認できます。


REST APIをPL/SQLコードより呼び出してみます。

ホーム・ページにサンプルを実装します。

従業員番号を指定するページ・アイテムを作成します。

識別名前P1_EMPNOタイプテキスト・フィールドラベルEmpnoとします。


REST APIを呼び出し、JSONの応答を出力するリージョンを作成します。

識別タイトルEMPタイプとして動的コンテンツを選択します。

ソースCLOBを返すPL/SQLファンクション本体として以下を記述します。

APEX_WEB_SERVICE.MAKE_REST_REQUESTに引数p_token_urlが指定されている場合、内部の処理としてAPEX_CREDENTIAL.SET_SESSION_TOKENが呼び出されているようです。トークンURLを呼び出して得られたOAuth2のアクセス・トークンはキャッシュされ、トークンがエクスパイアすると再度トークンURLが呼び出されます。

送信するページ・アイテムとしてP1_EMPNOを指定します。

プリティ・プリントを適用したJSON出力の改行を表示させるため、ヘッダーおよびフッターヘッダー・テキストとして<pre>フッター・テキストとして</pre>を記述します。


動的コンテンツをリフレッシュするボタンを作成します。

識別ボタン名FINDラベルFind動作アクションとして動的アクションで定義を選択します。


ボタンFINDに動的アクションを作成します。

識別名前Refresh EMPとします。タイミングはデフォルトでイベントクリック選択タイプボタンボタンFINDになります。


TRUEアクションとしてリフレッシュを選択します。影響を受ける要素選択タイプリージョンとし、リージョンにはJSONを出力する動的コンテンツであるEMPを指定します。


以上でOAuth2の認証で保護されたREST APIを呼び出す、確認アプリケーションは完成です。

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

Oracle APEXのアプリケーション作成の参考になれば幸いです。