Oracle Application Container Cloudで作ったREST APIに対して、Oracle Databaseから PL/SQLでUTL_HTTPパッケージを使ってアクセスするプログラムを書いたとき、HTTPSでアクセスするための設定がいろいろ必要だったので、備忘録です。ちなみに、Windows上のOracle DBで試しました。
#dbms_network_acl_adminの設定
Oracle DBからHTTPSリクエストを発行する場合、dbms_network_acl_adminで接続先に対してポート443でアクセスするための設定を行う必要があります。dbms_network_acl_adminは、11gと12cでは設定が少し違います。
今回、12cR2の PDBからアクセスしてみたので、その手順で書きます。
dbms_network_acl_adminの設定は、SQL*PlusからSYSDBAでログインしてPDB上で実行します。
connect sys/Password as sysdba
ALTER SESSION SET CONTAINER = orclpdb;
declare
host_name varchar2(100) := '{アクセス先のDNS名}';
begin
dbms_network_acl_admin.append_host_ace (
host => host_name,
lower_port => 443,
upper_port => 443,
ace => xs$ace_type(privilege_list => xs$name_list('http'),
principal_name => '{DBユーザー名}',
principal_type => xs_acl.ptype_db));
end;
/
declare
host_name varchar2(100) := '{アクセス先のDNS名}';
begin
dbms_network_acl_admin.append_host_ace (
host => host_name,
lower_port => 443,
upper_port => 443,
ace => xs$ace_type(privilege_list => xs$name_list('http_proxy'),
principal_name => '{DBユーザー名}',
principal_type => xs_acl.ptype_db));
end;
/
#Oracle WalletにCA登録
Oracle DBから外部にHTTPSでアクセスするには、Oracle WalletにCA認証書を登録する必要があります。この手順は以下の記事を参考にさせていただきました。
http://cosol.jp/techdb/2015/12/https-using-utl-http-how-to-aviod-ora-29024.html
Windowsでは以下のようにやってみました。
###Oracle Walletの作成
orapki wallet createコマンドで、空のOracleウォレットを作成します。
set ORACLE_WALLET_PATH={Oracle Walletのディレクトリ}
set ORACLE_WALLET_PWD={Walletのパスワード}
call orapki wallet create -wallet %ORACLE_WALLET_PATH% -pwd %ORACLE_WALLET_PWD% -auto_login
###CA証明書の準備
テスト用に試したので、
http://curl.haxx.se/ca/cacert.pem
にアクセスして、ルートCA証明書cacert.pemをダウンロードしたものを使いました。
このままでは適切に Oracle Walletに組み込めないため、インポート可能な形式に変換します。
Windowsの場合、gawkをインストールして以下を実行します。
gawk " split_after == 1 { n++; split_after=0 } /-----END CERTIFICATE-----/ { split_after=1 } { print > \"cert\" n \".pem\" }" < cacert.pem
これにより多数のpemファイルが生成されます。
###CA証明書を追加
次に orapki wallet add -trusted_cert -cert
コマンドでOracleウォレットにルートCA証明書を追加します。
バッチファイルで、たとえば以下を実行します。
for %%f in (*.pem) do (
orapki wallet add -wallet %ORACLE_WALLET_PATH% -trusted_cert -cert %%f -pwd %ORACLE_WALLET_PWD%
echo %%f
)
#PL/SQLからのHTTPSアクセス
PL/SQLでのSSLの有効化
PL/SQLでHTTPSアクセスするには、まず
UTL_HTTP.SET_WALLET('Oracle Walletのパス', 'Walletのパスワード')
を行います。
実際にアクセスする
以下は、dbms_network_acl_adminに登録したDBユーザーから登録したアクセス先に対し、HTTPSでPUTメソッドを使ってJSONを送る例です。DBのキャラクタセットはAL32UTF8を使っています。
connect c##adm/test
ALTER SESSION SET CONTAINER = orclpdb;
DECLARE
v_walletpath VARCHAR2(4000) := 'file:d:\app\test\wallet'; -- 「file:」を入れるのを忘れずに
v_walletpwd VARCHAR2(100) := 'WalletPasswd123';
v_req UTL_HTTP.REQ;
v_resp UTL_HTTP.RESP;
v_json VARCHAR2(4000) := '{ "id" : "1234", "name" : "テスト"}';
v_buf VARCHAR2(4000);
BEGIN
-- Walletを指定
UTL_HTTP.SET_WALLET(v_walletpath, v_walletpwd);
-- HTTPリクエスト
v_req := UTL_HTTP.BEGIN_REQUEST('https://{登録したホスト名}/cache/1234', 'PUT', UTL_HTTP.HTTP_VERSION_1_1);
UTL_HTTP.SET_HEADER(v_req, 'Content-Type', 'application/json; charset=utf-8');
UTL_HTTP.SET_HEADER(v_req, 'Content-Length', LENGTHB(v_json)); -- LENGTHBにする
UTL_HTTP.WRITE_RAW(v_req, UTL_RAW.CAST_TO_RAW(v_json)); -- JSONは文字列ではなくRAWにすること
-- レスポンスを取得
v_resp := UTL_HTTP.GET_RESPONSE(v_req);
DBMS_OUTPUT.PUT_LINE('Status Code: ' || TO_CHAR(v_resp.STATUS_CODE));
DBMS_OUTPUT.PUT_LINE('Message: ' || v_resp.REASON_PHRASE);
BEGIN
LOOP
UTL_HTTP.READ_LINE(v_resp, v_buf);
DBMS_OUTPUT.PUT_LINE(v_buf);
end LOOP;
UTL_HTTP.END_RESPONSE(v_resp);
EXCEPTION
WHEN UTL_HTTP.END_OF_BODY
THEN
UTL_HTTP.END_RESPONSE(v_resp);
END;
END;
/
- Walletのパスには「file:」を入れること。
- Content-Lengthにセットする送信データのサイズは、LENGTH(文字数)ではなくLENGTHB(バイト数)を使うこと。あまりに久々にPL/SQL使ったので、忘れてて文字化けしました...。
- あと、送信データはRAW型に変換してから送るようにします。
これを実行した後、以下のようにアクセスすると、登録したデータを取得できました。
SQL> SELECT UTL_HTTP.REQUEST('https://{ホスト名}/cache/1234') FROM DUAL;
UTL_HTTP.REQUEST('HTTPS://{ホスト名}/CACHE/
--------------------------------------------------------------------------------
{"id":"1234","name":"テスト"}