パスワード・チェック関数の所有ユーザーを変える（Oracle Database 21c）

本記事は公式なドキュメントに記載された内容ではありません。動作についても保障しません。

# パスワード・チェック関数
Oracle Databaseではユーザーが指定するパスワードの強度を設定するために、PROFILE にパスワードのチェック機能を提供しています。具体的には PASSWORD_VERIFY_FUNCTION 属性に以下のインターフェースを持つ関数を指定します。関数が TRUE を返せばチェックに合致し、FALSE を返せばチェックに不合格であったことになります。

|パラメーター|データ型|説明|
|:---|:---|:---|
|username|VARCHAR2|パスワードを変更するユーザー名|
|password|VARCHAR2|旧パスワード|
|old_password|VARCHAR2|新パスワード|

Oracle Database 21c には標準で以下の関数が提供されています。

|関数名|所有者|説明|
|:---|:---|:---|
|ORA12C_VERIFY_FUNCTION|SYS|Oracle Database 12c で追加されたチェック関数|
|ORA12C_STIG_VERIFY_FUNCTION|SYS| STIG 仕様を満たすチェック関数|

# SYS スキーマ以外の関数指定
 パスワード・チェック関数を SYS ユーザー以外の所有者として作成すると ORA-28220 エラーになります。下記の例では ADMIN ユーザーと ADMIN ユーザーが所有するファンクション test_verify_function1 を作成し、プロファイルに指定しようとしています。


```SQL:
SQL> CREATE USER admin IDENTIFIED BY password;

ユーザーが作成されました。

SQL> CREATE OR REPLACE FUNCTION admin.test_verify_function1
(username     varchar2,
 password     varchar2,
 old_password varchar2)
RETURN boolean IS
BEGIN
  RETURN true;
END;
/

ファンクションが作成されました。

SQL> CREATE PROFILE profile2 LIMIT password_verify_function admin.test_verify_function1;
CREATE PROFILE profile2 LIMIT password_verify_function admin.test_verify_function1
*
行1でエラーが発生しました。:
ORA-28220:
スキーマ名ADMINまたはパスワード検証ファンクションTEST_VERIFY_FUNCTION1が無効で
す
```

エラー・メッセージの詳細を見ると、見慣れないパラメーター ALLOWED_PVF_OWNERS が出てきます。

```Shell
$ oerr ora 28220
28220, 00000, "invalid schema name %s or password verification function %s"
// *Cause:  A nonexistent or invalid schema name or password verification
//          function was specified. This occurred when you attempted to create
//          or alter a profile with PASSWORD_VERIFY_FUNCTION parameter value
//          containing a non-SYS user owned schema qualified function and
//          either of the following was true:
//            - The ALLOWED_PVF_OWNERS system parameter was not configured to
//              allow schema qualified password verification function.
//            - The user schema was not allowed to own the password
//              verification function.
//            - The password verification function was created as an INVOKER
//              rights PL/SQL function.
// *Action: Specify a valid schema name or password verification function for
//          PASSWORD_VERIFY_FUNCTION parameter. Depending on the error, either
//          one of the following should be done:
//            - If the ALLOWED_PVF_OWNERS system parameter is set to NULL
//              (default value), please contact your database administrator
//              to have it set it to an appropriate value (comma separated
//              list of database users) to allow schema qualified password
//              verification function.
//            - If the user schema is not allowed to own the password
//              verification function, please contact your database
//              administrator to add the user as part of ALLOWED_PVF_OWNERS
//              system parameter value. Only users specified as
//              ALLOWED_PVF_OWNERS system parameter value are allowed to own
//              password verification function.
//            - If the password verification function is created as an INVOKER
//              rights PL/SQL function, please create it as DEFINER rights
//              PL/SQL function and retry {CREATE|ALTER} PROFILE operation.
//              INVOKER rights PL/SQL functions are not allowed as password
//              verification function due to security reasons.
```

このパラメーターは通常の初期化パラメーターには存在せず、隠しパラメーターとして提供されています。

```SQL:
SQL> SELECT a.KSPPINM AS PARAMETER, b.KSPPSTVL AS VALUE
  2  FROM X$KSPPI a, X$KSPPCV b
  3  WHERE a.INDX = b.indx
  4        and a.KSPPINM like '%pvf%';

PARAMETER                      VALUE
------------------------------ ------------------------------
_allowed_pvf_owners            null
```
該当のパラメーターをファンクション所有者に設定することで、CREATE PROFILE 文にエラーが発生しなくなりました。

```SQL:
SQL> ALTER SYSTEM SET "_allowed_pvf_owners" = 'ADMIN';

システムが変更されました。

SQL> CREATE PROFILE profile3 LIMIT password_verify_function ADMIN.test_verify_function1;

プロファイルが作成されました。
```

# Autonomous Database の対応
当初、Autonomous Database は PROFILE の作成や変更に対応していませんでしたが、[2020年10月の更新](https://docs.oracle.com/en/cloud/paas/autonomous-database/adbsn/index.html#ADBSN-GUID-75C344E0-544F-4AE2-B08D-7F8F0D201351) でユーザー定義の PROFILE を利用できるようになりました。

Autonomous Databaseではオンプレミス環境と異なり、管理ユーザー（ADMIN）の権限でファンクションを作成し、PASSWORD_VERIFY_FUNCTION に指定することができます。

```SQL:
SQL> SELECT USERNAME, PROFILE FROM DBA_USERS WHERE USERNAME='USER1';

USERNAME                       PROFILE
------------------------------ ------------------------------
USER1                          PROFILE1

SQL> SELECT LIMIT FROM DBA_PROFILES WHERE PROFILE='PROFILE1' AND RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION';

LIMIT
--------------------------------------------------------------------------------
ADMIN.TEST_VERIFY_FUNCTION1
```

上記の test_verify_function1 ファンクションはどのようなパスワードも受け付けます。しかし、Autonomous Database 環境では最小パスワード長等の制約が追加で付与されます。下記は USER1 ユーザーが自分のパスワードを変更しようとしています。本来すべてのパスワードを受け入れるはずが、最小パスワード長が不足、大文字を含む必要があるというエラーになっています。

```SQL:
SQL> SELECT USER FROM DUAL;

USER
--------------------------------------------------------------------------------
USER1

SQL> PASSWORD
ADMINに対するパスワードを変更しています。
旧パスワード:
新規パスワード:
新規パスワードを再入力してください:
ERROR:
ORA-28219: password verification failed for mandatory profile
ORA-20000: password length less than 8 bytes

パスワードが変更されませんでした。

SQL> PASSWORD
USER1に対するパスワードを変更しています。
旧パスワード:
新規パスワード:
新規パスワードを再入力してください:
ERROR:
ORA-28219: password verification failed for mandatory profile
ORA-20000: password must contain 1 or more uppercase characters

パスワードが変更されませんでした。
```