python-oracledb 로 접속할 때 나오는 오류다.
DPY-3015: password verifier type 0x939 is not supported by python-oracledb in thin mode
Oracle 은 계정 비밀번호를 평문이 아니라 verifier 라는 해시 형태로 보관하고, 세대별로 10G · 11G · 12C 타입이 있다. python-oracledb 의 thin 모드는 Oracle Client 라이브러리 없이 프로토콜을 직접 구현하므로 옛 세대 verifier 를 지원하지 않는다. 계정에 11G 이상 verifier 가 하나도 없으면 이 오류가 난다.
해당 계정이 어떤 verifier 를 갖고 있는지 본다.
SELECT username, password_versions
FROM dba_users
WHERE username = 'APPUSER';
10G 만 있거나 10G HTTP 처럼 옛 항목만 보이면 원인이 확정된다. 11G 또는 12C 가 함께 있으면 다른 원인을 봐야 한다.
같은 비밀번호로 다시 설정해도 현재 서버 설정에 맞는 verifier 가 새로 생성된다. 서비스 영향이 가장 작다.
ALTER USER appuser IDENTIFIED BY "<새 비밀번호>";
재설정 뒤 password_versions 를 다시 조회해 11G 이상이 생겼는지 확인한다. 생기지 않으면 서버 쪽 설정이 옛 verifier 만 만들도록 되어 있는 것이다. sqlnet.ora 의 SQLNET.ALLOWED_LOGON_VERSION_SERVER 값이 8 이나 10 이면 새 verifier 가 만들어지지 않으므로 12 이상으로 올린 뒤 다시 설정한다. 이 값을 올리면 옛 클라이언트가 접속하지 못하게 되므로 다른 연동을 먼저 확인한다.
Oracle Instant Client 를 설치할 수 있는 환경이면 thick 모드가 옛 verifier 를 지원한다. 계정을 건드리지 않아도 된다.
import oracledb
oracledb.init_oracle_client(lib_dir="/opt/oracle/instantclient_21_13")
conn = oracledb.connect(user="appuser", password=pw, dsn="host:1521/svc")
init_oracle_client() 는 접속 전에, 프로세스당 한 번만 호출한다. 리눅스에서는 lib_dir 를 주는 대신 LD_LIBRARY_PATH 나 ldconfig 로 경로를 잡아도 된다. Instant Client 가 요구하는 glibc 버전을 만족하는지 미리 본다.
ldd --version | head -1
계정마다 verifier 가 다르므로, 한 계정만 실패하고 다른 계정은 되는 상황이 정상이다. 데이터베이스 전체 설정을 의심하기 전에 실패한 계정의 password_versions 부터 본다.
sec_case_sensitive_logon 을 FALSE 로 둔 환경도 옛 verifier 만 쓰게 만드는 원인이 될 수 있다. 다만 이 파라미터는 Oracle 12.1 에서 deprecated 됐고 이후 버전에서는 제거됐으므로, 현행 버전에서는 SQLNET.ALLOWED_LOGON_VERSION_SERVER 쪽을 본다.