以前にRS256を使ったJWTを生成するという記事を書いたのですが、最近Autonomous Databaseの19cでRSA暗号がサポートされていることに気がつきました。そうであればJavaのRSAの実装を使う必要はありません。
以前の記事のコードでJavaを使っている部分をDBMS_CRYTPO.SIGNを使うように書き直して動作を確認しました。
置き換えたコードは以下です。
declare
l_now timestamp;
l_secret varchar2(32767) := 'MIIEogIBA* PKCS#1形式の秘密鍵 *RsvCjBJo=';
l_username varchar2(32) := 'TESTUSER';
l_jwt varchar2(32767);
l_jwt_token apex_jwt.t_token;
l_jwt_t apex_t_varchar2;
l_header_json json_object_t;
l_header_str varchar2(200);
l_header_base64 varchar2(400);
l_payload_json json_object_t;
l_payload_str varchar2(200);
l_payload_base64 varchar2(800);
l_token varchar2(1000);
l_hmac varchar2(1000);
-- DBMS_CRYPTO.SIGNへの置き換えのために追加。
l_data varchar2(400); -- header.payload
l_hmac_raw raw(2000);
-- Unix時間の取得
function unixtime(p_timestamp in timestamp)
return pls_integer
is
l_date date;
l_epoc number;
begin
l_date := sys_extract_utc(p_timestamp);
l_epoc := l_date - date'1970-01-01';
return l_epoc * 24 * 60 * 60;
end unixtime;
-- Base64のデコード
function from_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
end from_base64;
-- Base64のエンコード
function to_base64(t in varchar2) return varchar2 is
l_base64 varchar2(32767);
begin
l_base64 := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
l_base64 := replace(l_base64, chr(13)||chr(10), '');
return l_base64;
end to_base64;
begin
-- 共通で使用する現在時刻
l_now := current_timestamp;
dbms_output.put_line('Current Timestamp = ' || l_now || ', unixtime = ' || unixtime(l_now));
-- ヘッダーを手作業で生成する。
dbms_output.put_line('Hand made ==================================');
l_header_json := json_object_t();
l_header_json.put('alg','RS256');
l_header_json.put('typ','JWT');
l_header_str := l_header_json.to_string();
l_header_base64 := to_base64(l_header_str);
dbms_output.put_line('Header = ' || l_header_str);
-- ペイロードを手作業で作成する。
l_payload_json := json_object_t();
l_payload_json.put('iss','sqlplus');
l_payload_json.put('sub',l_username);
l_payload_json.put('aud','APEX');
l_payload_json.put('iat',unixtime(l_now));
l_payload_json.put('exp',unixtime(l_now)+10);
l_payload_str := l_payload_json.to_string();
l_payload_base64 := to_base64(l_payload_str);
dbms_output.put_line('Payload = ' || l_payload_str);
-- シグネチャを手作業で作成する。
l_data := l_header_base64 || '.' || l_payload_base64;
l_hmac_raw := dbms_crypto.sign(
src => utl_i18n.string_to_raw(l_data,'AL32UTF8'),
prv_key => utl_i18n.string_to_raw(l_secret,'AL32UTF8'),
pubkey_alg => DBMS_CRYPTO.KEY_TYPE_RSA,
sign_alg => DBMS_CRYPTO.SIGN_SHA256_RSA
);
l_hmac := to_base64(utl_i18n.raw_to_char(l_hmac_raw,'AL32UTF8'));
l_hmac := trim(translate(l_hmac, '+/=', '-_ '));
dbms_output.put_line('JWT = ' || l_header_base64 || '.' || l_payload_base64 || '.' || l_hmac);
end;APEXのSQLコマンドより実行してみました。事前に、管理ユーザーのADMINにてパッケージDBMS_CRYPTOの実行権限をワークスペース・スキーマに与えておきます。
grant execute on dbms_crypto to <ワークスペース・スキーマ>;
出力されたJWTをjwt.ioで検証します。
以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完