以前に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のアプリケーション作成の参考になれば幸いです。
完