From e8abd58b6b4a48454c2e7fcb18d05a6181e71c67 Mon Sep 17 00:00:00 2001 From: Vartan Babayan <v.babayan@picodata.io> Date: Fri, 6 Sep 2024 17:06:14 +0400 Subject: [PATCH] feat: use md5 auth by default --- CHANGELOG.md | 4 +- sbroad | 2 +- src/access_control.rs | 4 +- src/bootstrap_entries.rs | 26 +++++++++++- src/cli/args.rs | 11 ++++- src/cli/expel.rs | 2 +- src/schema.rs | 17 ++++---- test/conftest.py | 17 +++++--- test/int/test_access_control.py | 8 ++-- test/int/test_acl.py | 17 ++++---- test/int/test_audit.py | 8 ++-- test/int/test_basics.py | 5 ++- test/int/test_cli_connect.py | 46 ++++++++++++++++++-- test/int/test_ddl.py | 74 ++++++++++++++++----------------- test/int/test_gostech_audit.py | 6 ++- test/int/test_sql.py | 27 +++++++----- test/pgproto/auth_test.py | 37 ++++++++++++++++- test/pgproto/types_test.py | 8 ++-- 18 files changed, 222 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e8ecada3c..939968285a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,13 @@ with the `YY.MINOR.MICRO` scheme. - Order of columns in `_pico_service_route` table has changed. +- Default authorization method changed from chap-sha to md5 both for user creation and in connect CLI. + - Support human numbers to configure memtx.memory Supported suffixes: K, M, G, T, 1K = 1024 (e.g picodata run --memtx-memory 10G) -- - Replace the use of `localhost` with `127.0.0.1` in `picodata run --listen` default value +- Replace the use of `localhost` with `127.0.0.1` in `picodata run --listen` default value and everywhere across documentation and examples to reduce ambiguity. - New rpc entrypoint: `.proc_get_vshard_config` which returns the vshard configuration of tier. diff --git a/sbroad b/sbroad index 97d2b81478..c87bf3d8d4 160000 --- a/sbroad +++ b/sbroad @@ -1 +1 @@ -Subproject commit 97d2b81478414c154cfa10c30c303f5ce0c8e0b7 +Subproject commit c87bf3d8d4feaed22018a20413dfbcddff42e4a9 diff --git a/src/access_control.rs b/src/access_control.rs index ad9cd17ecc..e1d4703838 100644 --- a/src/access_control.rs +++ b/src/access_control.rs @@ -743,8 +743,8 @@ mod tests { fn dummy_auth_def() -> AuthDef { AuthDef::new( - AuthMethod::ChapSha1, - AuthData::new(&AuthMethod::ChapSha1, "", "").into_string(), + AuthMethod::Md5, + AuthData::new(&AuthMethod::Md5, "", "").into_string(), ) } diff --git a/src/bootstrap_entries.rs b/src/bootstrap_entries.rs index a976862a41..324aaa8226 100644 --- a/src/bootstrap_entries.rs +++ b/src/bootstrap_entries.rs @@ -8,7 +8,7 @@ use crate::config::PicodataConfig; use crate::instance::Instance; use crate::replicaset::Replicaset; use crate::schema; -use crate::schema::ADMIN_ID; +use crate::schema::{ADMIN_ID, GUEST_ID}; use crate::storage; use crate::storage::PropertyName; use crate::storage::{Clusterwide, ClusterwideTable}; @@ -282,7 +282,7 @@ pub(super) fn prepare( )) })?; - let method = AuthMethod::ChapSha1; + let method = AuthMethod::Md5; let name = "admin"; validate_password(&password, &method, storage)?; let data = AuthData::new(&method, name, &password); @@ -309,6 +309,28 @@ pub(super) fn prepare( tlog!(Info, "Password for user=admin has been set successfully"); } + let op_elem = op::Op::Acl(op::Acl::ChangeAuth { + user_id: GUEST_ID, + auth: AuthDef::new( + AuthMethod::Md5, + AuthData::new(&AuthMethod::Md5, "guest", "").into_string(), + ), + initiator: ADMIN_ID, + schema_version: 1, + }); + + let context = traft::EntryContext::Op(op_elem); + init_entries.push( + traft::Entry { + entry_type: raft::EntryType::EntryNormal, + index: (init_entries.len() + 1) as _, + term: traft::INIT_RAFT_TERM, + data: vec![], + context, + } + .into(), + ); + // // Populate "_pico_table" & "_pico_index" with definitions of builtins // diff --git a/src/cli/args.rs b/src/cli/args.rs index a86d871ffd..1cf78ca5fc 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -369,6 +369,15 @@ pub struct Expel { /// Path to a plain-text file with the `admin` password. /// If this option isn't provided, the password is prompted from the terminal. pub password_file: Option<String>, + + #[clap( + short = 'a', + long = "auth-type", + value_name = "METHOD", + default_value = AuthMethod::Md5.as_str(), + )] + /// The preferred authentication method. + pub auth_method: AuthMethod, } impl Expel { @@ -454,7 +463,7 @@ pub struct Connect { short = 'a', long = "auth-type", value_name = "METHOD", - default_value = AuthMethod::ChapSha1.as_str(), + default_value = AuthMethod::Md5.as_str(), )] /// The preferred authentication method. pub auth_method: AuthMethod, diff --git a/src/cli/expel.rs b/src/cli/expel.rs index 002ad97ec5..bb80361a1d 100644 --- a/src/cli/expel.rs +++ b/src/cli/expel.rs @@ -12,7 +12,7 @@ pub async fn tt_expel(args: args::Expel) -> Result<(), Error> { &args.peer_address, Some("admin"), args.password_file.as_deref(), - tarantool::auth::AuthMethod::ChapSha1, + args.auth_method, )?; let req = ExpelRequest { diff --git a/src/schema.rs b/src/schema.rs index 9cccde3c45..cb2dd25814 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -848,10 +848,7 @@ impl UserDef { id: 69, name: "david".into(), schema_version: 421, - auth: Some(AuthDef::new( - tarantool::auth::AuthMethod::ChapSha1, - "".into(), - )), + auth: Some(AuthDef::new(AuthMethod::Md5, "".into())), owner: 42, ty: UserMetadataKind::User, } @@ -1236,7 +1233,7 @@ pub fn system_user_definitions() -> Vec<(UserDef, Vec<PrivilegeDef>)> { // // User "guest" // - // equivalent SQL expression: CREATE USER 'guest' WITH PASSWORD '' USING chap-sha1 + // equivalent SQL expression: CREATE USER 'guest' WITH PASSWORD '' USING md5 { let user_def = UserDef { id: GUEST_ID, @@ -1244,8 +1241,8 @@ pub fn system_user_definitions() -> Vec<(UserDef, Vec<PrivilegeDef>)> { // This means the local schema is already up to date and main loop doesn't need to do anything schema_version: INITIAL_SCHEMA_VERSION, auth: Some(AuthDef::new( - AuthMethod::ChapSha1, - AuthData::new(&AuthMethod::ChapSha1, DEFAULT_USERNAME, "").into_string(), + AuthMethod::Md5, + AuthData::new(&AuthMethod::Md5, DEFAULT_USERNAME, "").into_string(), )), owner: initiator, ty: UserMetadataKind::User, @@ -1287,7 +1284,7 @@ pub fn system_user_definitions() -> Vec<(UserDef, Vec<PrivilegeDef>)> { // MP_MAP. Here for simplicity given available module api we // use ChapSha with invalid password (its impossible to get // empty string as output of sha1) - auth: Some(AuthDef::new(AuthMethod::ChapSha1, "".into())), + auth: Some(AuthDef::new(AuthMethod::Md5, "".into())), owner: initiator, ty: UserMetadataKind::User, }; @@ -1318,7 +1315,7 @@ pub fn system_user_definitions() -> Vec<(UserDef, Vec<PrivilegeDef>)> { schema_version: INITIAL_SCHEMA_VERSION, auth: Some(AuthDef::new( AuthMethod::ChapSha1, - tarantool::auth::AuthData::new( + AuthData::new( &AuthMethod::ChapSha1, PICO_SERVICE_USER_NAME, pico_service_password(), @@ -2553,7 +2550,7 @@ mod tests { id: ADMIN_ID, name: String::from("admin"), schema_version: 0, - auth: Some(AuthDef::new(AuthMethod::ChapSha1, String::from(""))), + auth: Some(AuthDef::new(AuthMethod::Md5, String::from(""))), owner: ADMIN_ID, ty: UserMetadataKind::User, }) diff --git a/test/conftest.py b/test/conftest.py index 56f28ce34a..25adf0912d 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -835,14 +835,16 @@ class Instance: self, with_name: str, with_password: str, + with_auth: str | None = None, user: str | None = None, password: str | None = None, timeout: int | float = 10, ): + sql = f"CREATE USER\"{with_name}\" WITH PASSWORD '{with_password}'" + ( + ("USING " + with_auth) if with_auth else "" + ) self.sql( - f""" - CREATE USER "{with_name}" WITH PASSWORD '{with_password}' USING chap-sha1 - """, + sql=sql, user=user, password=password, timeout=timeout, @@ -1698,7 +1700,11 @@ class Cluster: def remove_data(self): shutil.rmtree(self.data_dir) - def expel(self, target: Instance, peer: Instance | None = None): + def expel( + self, + target: Instance, + peer: Instance | None = None, + ): peer = peer if peer else target assert self.service_password_file, "cannot expel without pico_service password" assert target.instance_id, "cannot expel without target instance_id" @@ -1709,6 +1715,7 @@ class Cluster: "--peer", f"pico_service@{peer.listen}", "--cluster-id", target.cluster_id or "", "--password-file", self.service_password_file, + "--auth-type", "chap-sha1", target.instance_id, ] # fmt: on @@ -2347,7 +2354,7 @@ instance: # Exists for debugging purposes only. When you're debugging a single test it is # simpler to configure wireshark (or other tools) for particular port. -# Shouldnt be used when multiple tests are run (will result in address already in use errors) +# Shouldn't be used when multiple tests are run (will result in address already in use errors) PG_LISTEN = os.getenv("PG_LISTEN") diff --git a/test/int/test_access_control.py b/test/int/test_access_control.py index c8b1e525dd..a22a3e0572 100644 --- a/test/int/test_access_control.py +++ b/test/int/test_access_control.py @@ -24,8 +24,8 @@ _3_SEC = 3 def test_access_global_table(cluster: Cluster): (i1,) = cluster.deploy(instance_count=1) - i1.sql("""create user "alice" with password 'T0psecret'""") - i1.sql("""create user "bob" with password 'T0tallysecret'""") + i1.sql("""create user "alice" with password 'T0psecret' using chap-sha1""") + i1.sql("""create user "bob" with password 'T0tallysecret' using chap-sha1""") create_table_friends_of_peppa = """ create table "friends_of_peppa" ( @@ -87,8 +87,8 @@ def test_access_global_table(cluster: Cluster): def test_access_sharded_table(cluster: Cluster): (i1,) = cluster.deploy(instance_count=1) - i1.sql("""create user "alice" with password 'T0psecret'""") - i1.sql("""create user "bob" with password 'T0tallysecret'""") + i1.sql("""create user "alice" with password 'T0psecret' using chap-sha1""") + i1.sql("""create user "bob" with password 'T0tallysecret' using chap-sha1""") create_table_wonderland = """ create table "wonderland" ( diff --git a/test/int/test_acl.py b/test/int/test_acl.py index db21aafaa6..a34b683053 100644 --- a/test/int/test_acl.py +++ b/test/int/test_acl.py @@ -93,7 +93,7 @@ def test_acl_basic(cluster: Cluster): i1, *_ = cluster.deploy(instance_count=4, init_replication_factor=2) user = "Bobby" - v = 0 + v = 1 # Initial state. for i in cluster.instances: @@ -103,7 +103,7 @@ def test_acl_basic(cluster: Cluster): # # # Create user. - i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}'") + i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}' using chap-sha1") index = i1.call(".proc_get_index") cluster.raft_wait_index(index) v += 1 @@ -209,7 +209,7 @@ def test_acl_basic(cluster: Cluster): # Change user's password. old_password = VALID_PASSWORD new_password = "L0ng$3kr3T" - i1.sql(f"ALTER USER \"{user}\" WITH PASSWORD '{new_password}'") + i1.sql(f"ALTER USER \"{user}\" WITH PASSWORD '{new_password}' using chap-sha1") index = i1.call(".proc_get_index") cluster.raft_wait_index(index) v += 1 @@ -263,7 +263,7 @@ def test_acl_roles_basic(cluster: Cluster): user = "Steven" # Create user. - i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}'") + i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}' using chap-sha1") index = i1.call(".proc_get_index") cluster.raft_wait_index(index) @@ -343,7 +343,7 @@ def test_cas_permissions(cluster: Cluster): user = "Steven" # Create user. - i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}'") + i1.sql(f"CREATE USER \"{user}\" WITH PASSWORD '{VALID_PASSWORD}' using chap-sha1") index = i1.call(".proc_get_index") cluster.raft_wait_index(index) @@ -561,7 +561,7 @@ def test_builtin_users_and_roles(cluster: Cluster): def test_create_table_smoke(cluster: Cluster): i1, *_ = cluster.deploy(instance_count=1) - i1.sql(f"CREATE USER \"Dave\" WITH PASSWORD '{VALID_PASSWORD}'") + i1.sql(f"CREATE USER \"Dave\" WITH PASSWORD '{VALID_PASSWORD}' using chap-sha1") index = i1.call(".proc_get_index") cluster.raft_wait_index(index) with pytest.raises( @@ -755,7 +755,9 @@ def test_submit_sql_after_revoke_login(cluster: Cluster): password = "Validpa55word" - acl = i1.sql(f"create user \"alice\" with password '{password}'", sudo=True) + acl = i1.sql( + f"create user \"alice\" with password '{password}' using chap-sha1", sudo=True + ) assert acl["row_count"] == 1 acl = i1.sql('grant create table to "alice"', sudo=True) @@ -807,6 +809,7 @@ def test_admin_set_password(cluster: Cluster): i1.wait_online() password = os.getenv("PICODATA_ADMIN_PASSWORD") + i1.sql(f"ALTER USER admin WITH PASSWORD '{password}' USING chap-sha1") with i1.connect(timeout=5, user="admin", password=password) as conn: query = conn.sql( 'select * from "_pico_user"', diff --git a/test/int/test_audit.py b/test/int/test_audit.py index 1f5f20c033..38fb75f1be 100644 --- a/test/int/test_audit.py +++ b/test/int/test_audit.py @@ -210,7 +210,7 @@ def test_user(instance_with_audit_file: Instance): # https://git.picodata.io/picodata/picodata/picodata/-/issues/449 instance.sql( """ - alter user "ymir" password 'Topsecre1' + alter user "ymir" password 'Topsecre1' using chap-sha1 """, sudo=True, ) @@ -519,7 +519,9 @@ def test_access_denied(instance_with_audit_file: Instance): instance = instance_with_audit_file instance.start() - instance.create_user(with_name="ymir", with_password="T0psecret") + instance.create_user( + with_name="ymir", with_password="T0psecret", with_auth="chap-sha1" + ) audit = AuditFile(instance.audit_flag_value) for _ in audit.events(): @@ -553,7 +555,7 @@ def test_grant_revoke(instance_with_audit_file: Instance): user = "ymir" password = "T0psecret" - instance.create_user(with_name=user, with_password=password) + instance.create_user(with_name=user, with_password=password, with_auth="chap-sha1") instance.sql(f'GRANT CREATE ROLE TO "{user}"', sudo=True) diff --git a/test/int/test_basics.py b/test/int/test_basics.py index 6872adcefa..d67d20740a 100644 --- a/test/int/test_basics.py +++ b/test/int/test_basics.py @@ -397,10 +397,10 @@ Insert(_pico_property, ["max_pg_portals",1024]), Insert(_pico_property, ["snapshot_chunk_max_size",16777216]), Insert(_pico_property, ["snapshot_read_view_close_timeout",86400.0]))| | 0 | 1 |BatchDml( -Insert(_pico_user, [0,"guest",0,["chap-sha1","vhvewKp0tNyweZQ+cFKAlsyphfg="],1,"user"]), +Insert(_pico_user, [0,"guest",0,["md5","md5084e0343a0486ff05530df6c705c8bb4"],1,"user"]), Insert(_pico_privilege, [1,0,"login","universe",0,0]), Insert(_pico_privilege, [1,0,"execute","role",2,0]), -Insert(_pico_user, [1,"admin",0,["chap-sha1",""],1,"user"]), +Insert(_pico_user, [1,"admin",0,["md5",""],1,"user"]), Insert(_pico_privilege, [1,1,"read","universe",0,0]), Insert(_pico_privilege, [1,1,"write","universe",0,0]), Insert(_pico_privilege, [1,1,"execute","universe",0,0]), @@ -420,6 +420,7 @@ Insert(_pico_privilege, [1,32,"execute","role",3,0]), Insert(_pico_user, [2,"public",0,null,1,"role"]), Insert(_pico_user, [31,"super",0,null,1,"role"]), Insert(_pico_user, [3,"replication",0,null,1,"role"]))| +| 0 | 1 |ChangeAuth(1, 0, 1)| | 0 | 1 |BatchDml( Insert(_pico_table, [{_pico_table},"_pico_table",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"id"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"map","is_nullable":false,"name":"distribution"}},{{"field_type":"array","is_nullable":false,"name":"format"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}},{{"field_type":"boolean","is_nullable":false,"name":"operable"}},{{"field_type":"string","is_nullable":false,"name":"engine"}},{{"field_type":"unsigned","is_nullable":false,"name":"owner"}},{{"field_type":"string","is_nullable":false,"name":"description"}}],0,true,"memtx",1,"Stores metadata of all the cluster tables in picodata."]), Insert(_pico_index, [{_pico_table},0,"_pico_table_id","tree",[{{"unique":true}}],[["id","unsigned",null,false,null]],true,0]), diff --git a/test/int/test_cli_connect.py b/test/int/test_cli_connect.py index c012e45d2c..1ba64f1f65 100644 --- a/test/int/test_cli_connect.py +++ b/test/int/test_cli_connect.py @@ -39,7 +39,12 @@ def test_connect_testuser(i1: Instance): def test_connect_user_host_port(i1: Instance): cli = pexpect.spawn( command=i1.binary_path, - args=["connect", f"testuser@{i1.host}:{i1.port}", "-u", "overridden"], + args=[ + "connect", + f"testuser@{i1.host}:{i1.port}", + "-u", + "overridden", + ], encoding="utf-8", timeout=1, ) @@ -149,7 +154,7 @@ def test_connection_refused(binary_path: str): def test_connect_auth_type_ok(i1: Instance): cli = pexpect.spawn( command=i1.binary_path, - args=["connect", f"{i1.host}:{i1.port}", "-u", "testuser", "-a", "chap-sha1"], + args=["connect", f"{i1.host}:{i1.port}", "-u", "testuser"], encoding="utf-8", timeout=1, ) @@ -384,6 +389,41 @@ def test_admin_empty_path(binary_path: str): cli.expect_exact(pexpect.EOF) +def test_admin_with_password(cluster: Cluster): + import os + + os.environ["PICODATA_ADMIN_PASSWORD"] = "#AdminX12345" + + i1 = cluster.add_instance(wait_online=False) + i1.env.update(os.environ) + i1.start() + i1.wait_online() + + cli = pexpect.spawn( + command=i1.binary_path, + args=[ + "connect", + f"{i1.host}:{i1.port}", + "-u", + "admin", + ], + env={"NO_COLOR": "1"}, + encoding="utf-8", + timeout=1, + ) + cli.logfile = sys.stdout + cli.expect_exact("Enter password for admin: ") + + password = os.getenv("PICODATA_ADMIN_PASSWORD") + cli.sendline(password) + + cli.expect_exact("picodata> ") + + eprint("^D") + cli.sendcontrol("d") + cli.expect_exact(pexpect.EOF) + + def test_connect_unix_ok_via_default_sock(cluster: Cluster): i1 = cluster.add_instance(wait_online=False) i1.start() @@ -499,7 +539,7 @@ def test_connect_with_password_from_file(i1: Instance, binary_path: str): def test_connect_connection_info_and_help(i1: Instance): cli = pexpect.spawn( command=i1.binary_path, - args=["connect", f"{i1.host}:{i1.port}", "-u", "testuser", "-a", "chap-sha1"], + args=["connect", f"{i1.host}:{i1.port}", "-u", "testuser"], encoding="utf-8", timeout=1, ) diff --git a/test/int/test_ddl.py b/test/int/test_ddl.py index a0c55b6515..b36d4b3f45 100644 --- a/test/int/test_ddl.py +++ b/test/int/test_ddl.py @@ -22,17 +22,17 @@ def test_ddl_abort(cluster: Cluster): def test_ddl_create_table_bulky(cluster: Cluster): i1, i2, i3, i4 = cluster.deploy(instance_count=4, init_replication_factor=2) - # At cluster boot schema version is 0 - assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - - # And next schema version will be 1 - assert i1.next_schema_version() == 1 - assert i2.next_schema_version() == 1 - assert i3.next_schema_version() == 1 - assert i4.next_schema_version() == 1 + # At cluster boot schema version is 1 + assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + + # And next schema version will be 2 + assert i1.next_schema_version() == 2 + assert i2.next_schema_version() == 2 + assert i3.next_schema_version() == 2 + assert i4.next_schema_version() == 2 ############################################################################ # Propose a space creation which will fail @@ -66,16 +66,16 @@ def test_ddl_create_table_bulky(cluster: Cluster): assert i4.call("box.space._space:get", space_id) is None # Schema version hasn't changed - assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 0 - assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 0 + assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 1 + assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 1 # But next schema version did change - assert i1.next_schema_version() == 2 - assert i2.next_schema_version() == 2 - assert i3.next_schema_version() == 2 - assert i4.next_schema_version() == 2 + assert i1.next_schema_version() == 3 + assert i2.next_schema_version() == 3 + assert i3.next_schema_version() == 3 + assert i4.next_schema_version() == 3 ############################################################################ # Propose a space creation which will succeed @@ -92,16 +92,16 @@ def test_ddl_create_table_bulky(cluster: Cluster): space_id = i1.eval("return box.space.stuff.id") # This time schema version did change - assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 2 - assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 2 - assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 2 - assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 2 + assert i1.call("box.space._pico_property:get", "global_schema_version")[1] == 3 + assert i2.call("box.space._pico_property:get", "global_schema_version")[1] == 3 + assert i3.call("box.space._pico_property:get", "global_schema_version")[1] == 3 + assert i4.call("box.space._pico_property:get", "global_schema_version")[1] == 3 # And so did next schema version obviously - assert i1.next_schema_version() == 3 - assert i2.next_schema_version() == 3 - assert i3.next_schema_version() == 3 - assert i4.next_schema_version() == 3 + assert i1.next_schema_version() == 4 + assert i2.next_schema_version() == 4 + assert i3.next_schema_version() == 4 + assert i4.next_schema_version() == 4 # Space was created and is operable initiator_id = PICO_SERVICE_ID @@ -110,7 +110,7 @@ def test_ddl_create_table_bulky(cluster: Cluster): "stuff", {"Global": None}, [{"field_type": "unsigned", "is_nullable": False, "name": "id"}], - 2, + 3, True, "memtx", initiator_id, @@ -146,7 +146,7 @@ def test_ddl_create_table_bulky(cluster: Cluster): [dict(unique=True)], [["id", "unsigned", None, False, None]], True, - 2, + 3, ] assert i1.call("box.space._pico_index:get", [space_id, 0]) == pico_pk_def assert i2.call("box.space._pico_index:get", [space_id, 0]) == pico_pk_def @@ -171,8 +171,8 @@ def test_ddl_create_table_bulky(cluster: Cluster): i5 = cluster.add_instance(wait_online=True, replicaset_id="r3") - assert i5.call("box.space._pico_property:get", "global_schema_version")[1] == 2 - assert i5.next_schema_version() == 3 + assert i5.call("box.space._pico_property:get", "global_schema_version")[1] == 3 + assert i5.next_schema_version() == 4 assert i5.call("box.space._pico_table:get", space_id) == pico_space_def assert i5.call("box.space._pico_index:get", [space_id, 0]) == pico_pk_def assert i5.call("box.space._space:get", space_id) == tt_space_def @@ -181,8 +181,8 @@ def test_ddl_create_table_bulky(cluster: Cluster): i6 = cluster.add_instance(wait_online=True, replicaset_id="r3") # It's schema was updated automatically as well - assert i6.call("box.space._pico_property:get", "global_schema_version")[1] == 2 - assert i6.next_schema_version() == 3 + assert i6.call("box.space._pico_property:get", "global_schema_version")[1] == 3 + assert i6.next_schema_version() == 4 assert i6.call("box.space._pico_table:get", space_id) == pico_space_def assert i6.call("box.space._pico_index:get", [space_id, 0]) == pico_pk_def assert i6.call("box.space._space:get", space_id) == tt_space_def @@ -619,14 +619,14 @@ def test_ddl_create_table_from_snapshot_at_boot(cluster: Cluster): assert i3.call("box.space._space:get", space_id) == tt_space_def assert i3.call("box.space._index:get", [space_id, 0]) == tt_pk_def assert i3.call("box.space._index:get", [space_id, 1]) == tt_bucket_id_def - assert i3.call("box.space._schema:get", "local_schema_version")[1] == 1 + assert i3.call("box.space._schema:get", "local_schema_version")[1] == 2 # A replicaset follower boots up from snapshot i4 = cluster.add_instance(wait_online=True, replicaset_id="R2") assert i4.call("box.space._space:get", space_id) == tt_space_def assert i4.call("box.space._index:get", [space_id, 0]) == tt_pk_def assert i4.call("box.space._index:get", [space_id, 1]) == tt_bucket_id_def - assert i4.call("box.space._schema:get", "local_schema_version")[1] == 1 + assert i4.call("box.space._schema:get", "local_schema_version")[1] == 2 ################################################################################ @@ -690,7 +690,7 @@ def test_ddl_create_table_from_snapshot_at_catchup(cluster: Cluster): # A replica catches up by snapshot assert i3.call("box.space._space:get", space_id) == tt_space_def assert i3.call("box.space._index:get", [space_id, 0]) == tt_pk_def - assert i3.call("box.space._schema:get", "local_schema_version")[1] == 1 + assert i3.call("box.space._schema:get", "local_schema_version")[1] == 2 ################################################################################ @@ -1329,7 +1329,7 @@ cluster: i2.start() i2.wait_online() - i2.create_user(with_name="andy", with_password="Testpa55") + i2.create_user(with_name="andy", with_password="Testpa55", with_auth="chap-sha1") i2.sql('GRANT CREATE TABLE TO "andy"', sudo=True) read_only = i2.eval("return box.cfg.read_only") diff --git a/test/int/test_gostech_audit.py b/test/int/test_gostech_audit.py index 083d4bfee4..27313dee62 100644 --- a/test/int/test_gostech_audit.py +++ b/test/int/test_gostech_audit.py @@ -319,7 +319,9 @@ def test_gostech_access_denied( ) -> None: instance, audit = instance_with_gostech_audit - instance.create_user(with_name="ymir", with_password="T0psecret") + instance.create_user( + with_name="ymir", with_password="T0psecret", with_auth="chap-sha1" + ) expected_error = "Create access to role 'R' is denied for user 'ymir'" @@ -343,7 +345,7 @@ def test_gostech_grant_revoke( user = "ymir" password = "T0psecret" - instance.create_user(with_name=user, with_password=password) + instance.create_user(with_name=user, with_password=password, with_auth="chap-sha1") instance.sql(f'GRANT CREATE ROLE TO "{user}"', sudo=True) instance.sql(f'GRANT CREATE TABLE TO "{user}"', sudo=True) diff --git a/test/int/test_sql.py b/test/int/test_sql.py index fb9403cc28..41e29a8a8f 100644 --- a/test/int/test_sql.py +++ b/test/int/test_sql.py @@ -610,7 +610,7 @@ vtable_max_rows = 5000""" # test user with write permession can do global dml user = "user" password = "PaSSW0RD" - acl = i1.sql(f"create user {user} with password '{password}'") + acl = i1.sql(f"create user {user} with password '{password}' using chap-sha1") assert acl["row_count"] == 1 # check we can't write yet with pytest.raises( @@ -2402,7 +2402,8 @@ def test_sql_alter_login(cluster: Cluster): owner_password = "PA5sWORD" acl = i1.sql( - f"create user {owner_username} with password '{owner_password}'", sudo=True + f"create user {owner_username} with password '{owner_password}' using chap-sha1", + sudo=True, ) assert acl["row_count"] == 1 @@ -2413,7 +2414,7 @@ def test_sql_alter_login(cluster: Cluster): password = "PA5sWORD" # Create user. acl = i1.sql( - f"create user {username} with password '{password}'", + f"create user {username} with password '{password}' using chap-sha1", user=owner_username, password=owner_password, ) @@ -2456,7 +2457,8 @@ def test_sql_alter_login(cluster: Cluster): other_username = "other_user" other_password = "PA5sWORD" acl = i1.sql( - f"create user {other_username} with password '{other_password}'", sudo=True + f"create user {other_username} with password '{other_password}' using chap-sha1", + sudo=True, ) assert acl["row_count"] == 1 with pytest.raises( @@ -2497,9 +2499,11 @@ def test_sql_acl_privileges(cluster: Cluster): another_rolename = "another_role" # Create users. - acl = i1.sql(f"create user {username} with password '{password}'") + acl = i1.sql(f"create user {username} with password '{password}' using chap-sha1") assert acl["row_count"] == 1 - acl = i1.sql(f"create user {another_username} with password '{password}'") + acl = i1.sql( + f"create user {another_username} with password '{password}' using chap-sha1 " + ) assert acl["row_count"] == 1 # Create roles. acl = i1.sql(f"create role {rolename}") @@ -3044,11 +3048,12 @@ def test_user_changes_password(cluster: Cluster): old_password = "Passw0rd" new_password = "Pa55word" - i1.create_user(with_name=user_name, with_password=old_password) - + i1.create_user( + with_name=user_name, with_password=old_password, with_auth="chap-sha1" + ) i1.sql( f""" - ALTER USER "{user_name}" PASSWORD '{new_password}' + ALTER USER "{user_name}" PASSWORD '{new_password}' USING chap-sha1 """, user=user_name, password=old_password, @@ -3879,8 +3884,8 @@ def test_rename_user(cluster: Cluster): boba = "boba" password = "Passw0rd" - i1.create_user(with_name=biba, with_password=password) - i1.create_user(with_name=boba, with_password=password) + i1.create_user(with_name=biba, with_password=password, with_auth="chap-sha1") + i1.create_user(with_name=boba, with_password=password, with_auth="chap-sha1") with pytest.raises(TarantoolError, match=f"user {boba} does not exist"): data = i1.sql( diff --git a/test/pgproto/auth_test.py b/test/pgproto/auth_test.py index 96a7613804..9b95adbb13 100644 --- a/test/pgproto/auth_test.py +++ b/test/pgproto/auth_test.py @@ -1,6 +1,6 @@ import pytest import pg8000.dbapi as pg # type: ignore -from conftest import Postgres +from conftest import Postgres, Cluster def test_auth(postgres: Postgres): @@ -41,3 +41,38 @@ def test_auth(postgres: Postgres): pg.DatabaseError, match=f"authentication failed for user '{sha_user}'" ): pg.Connection(sha_user, password="aaa", host=postgres.host, port=postgres.port) + + +def test_admin_auth(cluster: Cluster): + import os + + os.environ["PICODATA_ADMIN_PASSWORD"] = "#AdminX12345" + + cluster.set_config_file( + yaml=""" + cluster: + cluster_id: test + tier: + default: + instance: + pg: + listen: "127.0.0.1:5432" + ssl: False + """ + ) + i1 = cluster.add_instance(wait_online=False) + i1.env.update(os.environ) + i1.start() + i1.wait_online() + + user = "admin" + password = os.getenv("PICODATA_ADMIN_PASSWORD") + + # test authentication with a wrong password + with pytest.raises( + pg.DatabaseError, match=f"authentication failed for user '{user}'" + ): + pg.Connection(user, password="wrong password", host="127.0.0.1", port=5432) + + conn = pg.Connection(user=user, password=password, host="127.0.0.1", port=5432) + conn.close() diff --git a/test/pgproto/types_test.py b/test/pgproto/types_test.py index 07b0f3243b..028bf4a34a 100644 --- a/test/pgproto/types_test.py +++ b/test/pgproto/types_test.py @@ -308,13 +308,13 @@ def test_arrays(postgres: Postgres): cur = conn.execute( """ SELECT \"auth\" FROM \"_pico_user\" WHERE \"id\" = 0; """, binary=False ) - assert cur.fetchall() == [(["chap-sha1", "vhvewKp0tNyweZQ+cFKAlsyphfg="],)] + assert cur.fetchall() == [(["md5", "md5084e0343a0486ff05530df6c705c8bb4"],)] # test binary encoding cur = conn.execute( """ SELECT \"auth\" FROM \"_pico_user\" WHERE \"id\" = 0; """, binary=True ) - assert cur.fetchall() == [(["chap-sha1", "vhvewKp0tNyweZQ+cFKAlsyphfg="],)] + assert cur.fetchall() == [(["md5", "md5084e0343a0486ff05530df6c705c8bb4"],)] # text array parameters should throw an error with pytest.raises( @@ -343,14 +343,14 @@ def test_arrays(postgres: Postgres): """ SELECT \"auth\" FROM \"_pico_user\" WHERE \"name\" = 'admin'; """, binary=False, ) - assert cur.fetchall() == [(["chap-sha1", ""],)] + assert cur.fetchall() == [(["md5", ""],)] # bin repr case cur = conn.execute( """ SELECT \"auth\" FROM \"_pico_user\" WHERE \"name\" = 'admin'; """, binary=True, ) - assert cur.fetchall() == [(["chap-sha1", ""],)] + assert cur.fetchall() == [(["md5", ""],)] def test_map(postgres: Postgres): -- GitLab