From c048ed54e53fc4b2f3ee430b61cee6d35e38c7bf Mon Sep 17 00:00:00 2001
From: Dmitry Rodionov <d.rodionov@picodata.io>
Date: Tue, 12 Dec 2023 17:24:40 +0300
Subject: [PATCH] fix: allow user to change password without privileges on
 _pico_property

close: https://git.picodata.io/picodata/picodata/picodata/-/issues/449
---
 src/sql.rs           |  6 +++++-
 test/conftest.py     | 18 ++++++++++++++++++
 test/int/test_sql.py | 19 +++++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/sql.rs b/src/sql.rs
index d7203e56f7..4781c09f5d 100644
--- a/src/sql.rs
+++ b/src/sql.rs
@@ -530,7 +530,11 @@ fn check_password_min_length(
     }
 
     let storage = &node.storage;
-    let password_min_length = storage.properties.password_min_length()?;
+
+    // This check is called from user facing API.
+    // A user is not expected to have access to _pico_property
+    let password_min_length =
+        session::with_su(ADMIN_ID, || storage.properties.password_min_length())??;
     if password.len() < password_min_length {
         return Err(Error::Other(
             format!(
diff --git a/test/conftest.py b/test/conftest.py
index fb1c2836f7..2b9132ae75 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -463,6 +463,13 @@ class Connection(tarantool.Connection):  # type: ignore
         self.eval("box.session.su(...)", old_euid)
         return ret
 
+    def create_user(self, name: str, password: str):
+        self.sql(
+            f"""
+            CREATE USER "{name}" WITH PASSWORD '{password}' USING chap-sha1
+            """
+        )
+
 
 @dataclass
 class Instance:
@@ -630,6 +637,17 @@ class Instance:
         with self.connect(timeout, user=user, password=password) as conn:
             return conn.sudo_sql(sql, params)
 
+    def create_user(
+        self,
+        with_name: str,
+        with_password: str,
+        user: str | None = None,
+        password: str | None = None,
+        timeout: int | float = 1,
+    ):
+        with self.connect(timeout, user=user, password=password) as conn:
+            conn.create_user(name=with_name, password=with_password)
+
     def terminate(self, kill_after_seconds=10) -> int | None:
         """Terminate the instance gracefully with SIGTERM"""
         if self.process is None:
diff --git a/test/int/test_sql.py b/test/int/test_sql.py
index 528192325c..e3bfb62a68 100644
--- a/test/int/test_sql.py
+++ b/test/int/test_sql.py
@@ -1452,3 +1452,22 @@ def test_sql_privileges(cluster: Cluster):
     assert dml["row_count"] == 2
     dml = i1.sql(f""" delete from "{table_name}" """, user=username, password=alice_pwd)
     assert dml["row_count"] == 2
+
+
+def test_user_changes_password(cluster: Cluster):
+    i1, *_ = cluster.deploy(instance_count=1)
+    user_name = "U"
+    old_password = "12341234"
+    new_password = "11111111"
+
+    i1.create_user(with_name=user_name, with_password=old_password)
+
+    i1.sql(
+        f"""
+        ALTER USER "{user_name}" PASSWORD '{new_password}'
+        """,
+        user=user_name,
+        password=old_password,
+    )
+    # ensure we can authenticate with new password
+    i1.sql("SELECT * FROM (VALUES (1))", user=user_name, password=new_password)
-- 
GitLab