使用存储过程创建新数据库用户后的身份验证错误

Authentication error after using stored procedure for creating new db user

我在 postgres 中遇到了这个问题,我找不到出路。

为了让我们的关键用户在我们的 postgres 数据库中创建用户帐户 (Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1074-azure x86_64)),我创建了一个使用密码创建用户的存储过程。

这是存储过程的代码:

CREATE OR REPLACE PROCEDURE geodata_create_user(
   username CHARACTER VARYING,
   password CHARACTER VARYING
)
LANGUAGE PLPGSQL SECURITY DEFINER
AS 
$$
DECLARE
    user_to_create CHARACTER VARYING;
BEGIN
    -- Check name and create user
    IF (username like 'user%') THEN
      user_to_create := username;
    ELSE
      user_to_create := 'user_' || username;
    END IF;

    PERFORM create_role_if_not_exists (user_to_create);

    -- Set password and assign geodata_user role to user
    EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD ''%I''', user_to_create, password);
    EXECUTE format('GRANT another_role TO %I', user_to_create);
end;
$$;

GRANT ALL ON PROCEDURE geodata_create_user TO some_group_role;

如果我测试它(我们有一个开发集群和一个 acc/prod 集群),它工作正常。

问题是,如果其中一位关键用户使用此过程创建新用户,则该用户已创建但无法使用提供的密码登录。

根据 中使用对等登录的建议,我尝试使用 psql -U newuser 命令登录 psql,它告诉我致命错误:用户对等身份验证失败

然后,按照 psql: FATAL: Peer authentication failed for user "dev" 中的建议使用 psql -U newuser -d mydbname -h 12.345.678.910 登录 psql 并回复(输入为用户创建的密码后):

用户newuser的密码: psql:错误:连接到位于“12.345.678.910”的服务器,端口 8765 失败:无法启动 GSSAPI 安全上下文:未指定的 GSS 失败。次要代码可能会提供更多信息:在 Kerberos 数据库中找不到服务器 postgres/12.345.678.910@CFSERVICES.COM 连接到位于“12.345.678.910”的服务器,端口 8765 失败:致命:用户“newuser”的密码验证失败 连接到位于“12.345.678.910”、端口 8765 的服务器失败:致命:主机“12.345.678.910”、用户“newuser”、数据库“mydbname”、SSL 关闭

没有 pg_hba.conf 条目

我确实有一点数据库经验,但是,这种东西超出了我的能力范围。有人知道这里出了什么问题吗?我的脚本中有明显的错误吗?或者这可能是一个安全问题(我们在直接通过 psql 访问数据库服务器时使用证书来访问数据库服务器,但通常我们使用 DBeaver 设置与数据库的连接,而无需使用 SSL 或 SSH 隧道或证书或所以)。

希望有人能帮我解决这个问题。 问候,Helmoet。

你的 format() 函数是错误的,因为密码不是 SQL 标识符(这是 %I 的用途)。至少在某些情况下,这将导致它被错误地转义。例如,如果密码中有 space 或破折号(或其他我想不起来的字符),这将导致整个密码被双引号括起来。然后密码就可以了,但是你需要指定双引号,这肯定不是你所期望的。

所以它应该看起来像这样,使用 %L 而不是 %I:

EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', user_to_create, password);

您的原始代码适用于其中没有任何特殊符号的密码,所以也许这就是它测试正常的原因。