diff options
| author | Andrey Zaspa <[email protected]> | 2026-07-13 14:51:08 +0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-07-13 14:51:08 +0400 |
| commit | 1cbcd27880ca8877cfd30386a2bff89dafa11a47 (patch) | |
| tree | da9c59a8ab65456d3d2be589537d1670143f9467 | |
| parent | ea4199e3c66d94f8a93ee71d84fcf5ccf1c31319 (diff) | |
Remove legacy password-hashing machinery from the login library (#46087)
30 files changed, 377 insertions, 1622 deletions
diff --git a/ydb/core/protos/counters_schemeshard.proto b/ydb/core/protos/counters_schemeshard.proto index 25d3a41d554..8917520bf0d 100644 --- a/ydb/core/protos/counters_schemeshard.proto +++ b/ydb/core/protos/counters_schemeshard.proto @@ -763,7 +763,7 @@ enum ETxTypes { TXTYPE_ADD_SHARDS_SHRED = 98 [(TxTypeOpts) = {Name: "TxAddShardsShred"}]; TXTYPE_CANCEL_SHARDS_SHRED = 99 [(TxTypeOpts) = {Name: "TxCancelShardsShred"}]; - TXTYPE_LOGIN_FINALIZE = 100 [(TxTypeOpts) = {Name: "TxLoginFinalize"}]; + TXTYPE_DEPRECATED_100 = 100 [(TxTypeOpts) = {Name: "TxDeprecated100"}]; // was TXTYPE_LOGIN_FINALIZE TXTYPE_PROGRESS_INCREMENTAL_RESTORE = 101 [(TxTypeOpts) = {Name: "TxProgressIncrementalRestore"}]; TXTYPE_INCREMENTAL_RESTORE_SHARD_RESPONSE = 102 [(TxTypeOpts) = {Name: "TxIncrementalRestoreShardResponse"}]; @@ -784,7 +784,7 @@ enum ETxTypes { TXTYPE_LIST_FORCED_COMPACTION = 114 [(TxTypeOpts) = {Name: "TxListForcedCompaction"}]; TXTYPE_PROGRESS_FORCED_COMPACTION = 115 [(TxTypeOpts) = {Name: "TxProgressForcedCompaction"}]; - TXTYPE_USER_HASHES_MIGRATION = 116 [(TxTypeOpts) = {Name: "TTxUserHashesMigration"}]; + TXTYPE_DEPRECATED_116 = 116 [(TxTypeOpts) = {Name: "TxDeprecated116"}]; // was TXTYPE_USER_HASHES_MIGRATION TXTYPE_TABLE_PARTITIONS_STORAGE_FORMAT_SWITCH = 117 [(TxTypeOpts) = {Name: "TxTablePartitionsFormatSwitch"}]; TXTYPE_TABLE_PARTITIONS_STORAGE_FORMAT_SWEEP_STEP = 118 [(TxTypeOpts) = {Name: "TxTablePartitionsFormatSweepStep"}]; diff --git a/ydb/core/security/ldap_auth_provider/ldap_auth_provider_ut.cpp b/ydb/core/security/ldap_auth_provider/ldap_auth_provider_ut.cpp index 10b72b07061..7efccbf1290 100644 --- a/ydb/core/security/ldap_auth_provider/ldap_auth_provider_ut.cpp +++ b/ydb/core/security/ldap_auth_provider/ldap_auth_provider_ut.cpp @@ -58,18 +58,18 @@ private: ui16 GrpcPort; }; -NLogin::TLoginProvider::TLoginUserResponse GetLoginResponse(TLdapKikimrServer& server, const TString& login, const TString& password) { +NLogin::TLoginProvider::TLoginUserResponse GetLoginResponse(TLdapKikimrServer& server, const TString& login) { TTestActorRuntime* runtime = server.GetRuntime(); NLogin::TLoginProvider provider; provider.Audience = "/Root"; provider.RotateKeys(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - return provider.LoginUser({.User = login, .Password = password, .ExternalAuth = "ldap"}); + return provider.LoginUser({.User = login, .ExternalAuth = "ldap"}); } -TAutoPtr<IEventHandle> LdapAuthenticate(TLdapKikimrServer& server, const TString& login, const TString& password) { - auto loginResponse = GetLoginResponse(server, login, password); +TAutoPtr<IEventHandle> LdapAuthenticate(TLdapKikimrServer& server, const TString& login) { + auto loginResponse = GetLoginResponse(server, login); TTestActorRuntime* runtime = server.GetRuntime(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -576,7 +576,8 @@ TCertStorage CertStorage; void CheckRequiredLdapSettings(std::function<void(NKikimrProto::TLdapAuthentication*, ui16, const TLdapClientOptions&)> initLdapSettings, const TString& expectedErrorMessage, - const ESecurityConnectionType& securityConnectionType = ESecurityConnectionType::NON_SECURE) { + const ESecurityConnectionType& securityConnectionType = ESecurityConnectionType::NON_SECURE) +{ TLdapKikimrServer ydbServer(initLdapSettings, { .CaCertFile = CertStorage.GetCaCertFileName(), .Type = securityConnectionType @@ -590,10 +591,9 @@ void CheckRequiredLdapSettings(std::function<void(NKikimrProto::TLdapAuthenticat }, LdapMock::TLdapMockResponses()); TString login = "ldapuser"; - TString password = "ldapUserPassword"; ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Expected return error message"); UNIT_ASSERT_STRINGS_EQUAL(ticketParserResult->Error.Message, expectedErrorMessage); @@ -601,7 +601,6 @@ void CheckRequiredLdapSettings(std::function<void(NKikimrProto::TLdapAuthenticat void LdapFetchGroupsWithDefaultGroupAttributeGood(const ESecurityConnectionType& secureType) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings, { .CaCertFile = CertStorage.GetCaCertFileName(), @@ -615,7 +614,7 @@ void LdapFetchGroupsWithDefaultGroupAttributeGood(const ESecurityConnectionType& .UseTls = secureType == ESecurityConnectionType::LDAPS_SCHEME }, TCorrectLdapResponse::GetResponses(login)); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -651,13 +650,12 @@ Y_UNIT_TEST(CanFetchGroupsWithDefaultGroupAttributeNonSecure) { Y_UNIT_TEST(CanFetchGroupsWithDefaultGroupAttributeDisableNestedGroups) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsDisableSearchNestedGroups); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login, true)); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -677,13 +675,12 @@ Y_UNIT_TEST(CanFetchGroupsWithDefaultGroupAttributeDisableNestedGroups) { Y_UNIT_TEST(CanFetchGroupsFromAdServer) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login)); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -703,13 +700,12 @@ Y_UNIT_TEST(CanFetchGroupsFromAdServer) { Y_UNIT_TEST(CanFetchGroupsWithDisabledRequestToAD) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsDisableSearchNestedGroups); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login, true)); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -729,13 +725,12 @@ Y_UNIT_TEST(CanFetchGroupsWithDisabledRequestToAD) { Y_UNIT_TEST(CanFetchGroupsWithDefaultGroupAttributeUseListOfHosts) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsWithListOfHosts); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login)); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -755,13 +750,12 @@ Y_UNIT_TEST(CanFetchGroupsWithDefaultGroupAttributeUseListOfHosts) { Y_UNIT_TEST(CanFetchGroupsWithCustomGroupAttribute) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsWithCustomGroupAttribute); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login, false, "groupDN")); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -781,7 +775,6 @@ Y_UNIT_TEST(CanFetchGroupsWithCustomGroupAttribute) { Y_UNIT_TEST(CanFetchGroupsWithDontExistGroupAttribute) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsWithCustomGroupAttribute); @@ -814,7 +807,7 @@ Y_UNIT_TEST(CanFetchGroupsWithDontExistGroupAttribute) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -827,7 +820,6 @@ Y_UNIT_TEST(CanFetchGroupsWithDontExistGroupAttribute) { Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserLogin) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; LdapMock::TLdapMockResponses responses; responses.BindResponses.push_back({{{.Login = "cn=invalidRobouser,dc=search,dc=yandex,dc=net", .Password = "robouserPassword"}}, {.Status = LdapMock::EStatus::INVALID_CREDENTIALS}}); @@ -836,7 +828,7 @@ Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserLogin) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Expected return error message"); UNIT_ASSERT_STRINGS_EQUAL(ticketParserResult->Error.Message, "Could not login via LDAP"); @@ -845,7 +837,6 @@ Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserLogin) { Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserPassword) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; LdapMock::TLdapMockResponses responses; responses.BindResponses.push_back({{{.Login = "cn=robouser,dc=search,dc=yandex,dc=net", .Password = "invalidPassword"}}, {.Status = LdapMock::EStatus::INVALID_CREDENTIALS}}); @@ -854,7 +845,7 @@ Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserPassword) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Expected return error message"); UNIT_ASSERT_STRINGS_EQUAL(ticketParserResult->Error.Message, "Could not login via LDAP"); @@ -863,7 +854,6 @@ Y_UNIT_TEST(CanNotFetchGroupsWithInvalidRobotUserPassword) { Y_UNIT_TEST(CanNotFetchGroupsWithRemovedUserCredentials) { TString removedUserLogin = "ldapuser"; - TString removedUserPassword = "ldapUserPassword"; LdapMock::TLdapMockResponses responses; responses.BindResponses.push_back({{{.Login = "cn=robouser,dc=search,dc=yandex,dc=net", .Password = "robouserPassword"}}, {.Status = LdapMock::EStatus::SUCCESS}}); @@ -888,7 +878,7 @@ Y_UNIT_TEST(CanNotFetchGroupsWithRemovedUserCredentials) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, removedUserLogin, removedUserPassword); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, removedUserLogin); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Expected return error message"); UNIT_ASSERT_STRINGS_EQUAL(ticketParserResult->Error.Message, "Could not login via LDAP"); @@ -896,7 +886,6 @@ Y_UNIT_TEST(CanNotFetchGroupsWithRemovedUserCredentials) { Y_UNIT_TEST(CanNotFetchGroupsUseInvalidSearchFilter) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; LdapMock::TLdapMockResponses responses; responses.BindResponses.push_back({{{.Login = "cn=robouser,dc=search,dc=yandex,dc=net", .Password = "robouserPassword"}}, {.Status = LdapMock::EStatus::SUCCESS}}); @@ -905,7 +894,7 @@ Y_UNIT_TEST(CanNotFetchGroupsUseInvalidSearchFilter) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Expected return error message"); UNIT_ASSERT_STRINGS_EQUAL(ticketParserResult->Error.Message, "Could not login via LDAP"); @@ -913,7 +902,6 @@ Y_UNIT_TEST(CanNotFetchGroupsUseInvalidSearchFilter) { Y_UNIT_TEST(CanRefreshGroupsInfo) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; auto responses = TCorrectLdapResponse::GetResponses(login); LdapMock::TLdapMockResponses updatedResponses = TCorrectLdapResponse::GetUpdatedResponses(login); @@ -923,7 +911,7 @@ Y_UNIT_TEST(CanRefreshGroupsInfo) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login)); ldapServer.Start(); - auto loginResponse = GetLoginResponse(ydbServer, login, password); + auto loginResponse = GetLoginResponse(ydbServer, login); TTestActorRuntime* runtime = ydbServer.GetRuntime(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -967,7 +955,6 @@ Y_UNIT_TEST(CanRefreshGroupsInfo) { Y_UNIT_TEST(CanRefreshGroupsInfoWithDisabledNestedGroups) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; auto responses = TCorrectLdapResponse::GetResponses(login, true); LdapMock::TLdapMockResponses updatedResponses = TCorrectLdapResponse::GetUpdatedResponses(login, true); @@ -977,7 +964,7 @@ Y_UNIT_TEST(CanRefreshGroupsInfoWithDisabledNestedGroups) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort(),}, responses); ldapServer.Start(); - auto loginResponse = GetLoginResponse(ydbServer, login, password); + auto loginResponse = GetLoginResponse(ydbServer, login); TTestActorRuntime* runtime = ydbServer.GetRuntime(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -1021,7 +1008,6 @@ Y_UNIT_TEST(CanRefreshGroupsInfoWithDisabledNestedGroups) { Y_UNIT_TEST(CanNotRefreshRemovedUser) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings); auto responses = TCorrectLdapResponse::GetResponses(login); @@ -1036,7 +1022,7 @@ Y_UNIT_TEST(CanNotRefreshRemovedUser) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - auto loginResponse = GetLoginResponse(ydbServer, login, password); + auto loginResponse = GetLoginResponse(ydbServer, login); TTestActorRuntime* runtime = ydbServer.GetRuntime(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -1072,7 +1058,6 @@ Y_UNIT_TEST(CanNotRefreshRemovedUser) { Y_UNIT_TEST(CanRefreshGroupsInfoWithError) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings); auto responses = TCorrectLdapResponse::GetResponses(login); @@ -1087,7 +1072,7 @@ Y_UNIT_TEST(CanRefreshGroupsInfoWithError) { LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, responses); ldapServer.Start(); - auto loginResponse = GetLoginResponse(ydbServer, login, password); + auto loginResponse = GetLoginResponse(ydbServer, login); TTestActorRuntime* runtime = ydbServer.GetRuntime(); TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -1147,7 +1132,6 @@ Y_UNIT_TEST(CanNotRequestWithEmptyBindPassword) { Y_UNIT_TEST(CanFetchGroupsWithDelayUpdateSecurityState) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login)); @@ -1159,7 +1143,7 @@ Y_UNIT_TEST(CanFetchGroupsWithDelayUpdateSecurityState) { provider.RotateKeys(); TActorId sender = runtime->AllocateEdgeActor(); - auto loginResponse = provider.LoginUser({.User = login, .Password = password, .ExternalAuth = "ldap"}); + auto loginResponse = provider.LoginUser({.User = login, .ExternalAuth = "ldap"}); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); Sleep(TDuration::Seconds(1)); // Send update security state in 1 second after send TEvAuthorizeTicket @@ -1186,7 +1170,6 @@ Y_UNIT_TEST(CanFetchGroupsWithDelayUpdateSecurityState) { Y_UNIT_TEST(CanGetErrorIfAppropriateLoginProviderIsAbsent) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettings); LdapMock::TSimpleServer ldapServer({.Port = ydbServer.GetLdapPort()}, TCorrectLdapResponse::GetResponses(login)); @@ -1198,7 +1181,7 @@ Y_UNIT_TEST(CanGetErrorIfAppropriateLoginProviderIsAbsent) { provider.RotateKeys(); TActorId sender = runtime->AllocateEdgeActor(); - auto loginResponse = provider.LoginUser({.User = login, .Password = password, .ExternalAuth = "ldap"}); + auto loginResponse = provider.LoginUser({.User = login, .ExternalAuth = "ldap"}); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); Sleep(TDuration::Seconds(1)); // Do no send update security state @@ -1215,7 +1198,6 @@ Y_UNIT_TEST(CanGetErrorIfAppropriateLoginProviderIsAbsent) { Y_UNIT_TEST(CanFetchGroupsWithValidCredentialsUseExternalSaslAuth) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsWithSaslExternalBind, { .CaCertFile = CertStorage.GetCaCertFileName(), @@ -1239,7 +1221,7 @@ Y_UNIT_TEST(CanFetchGroupsWithValidCredentialsUseExternalSaslAuth) { } }, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(!ticketParserResult->HasError(), ticketParserResult->Error); UNIT_ASSERT(ticketParserResult->Token != nullptr); @@ -1259,7 +1241,6 @@ Y_UNIT_TEST(CanFetchGroupsWithValidCredentialsUseExternalSaslAuth) { Y_UNIT_TEST(CanNotFetchGroupsOverSaslExternalWithoutClientCert) { TString login = "ldapuser"; - TString password = "ldapUserPassword"; TLdapKikimrServer ydbServer(InitLdapSettingsWithSaslExternalBind, { .CaCertFile = CertStorage.GetCaCertFileName(), @@ -1281,7 +1262,7 @@ Y_UNIT_TEST(CanNotFetchGroupsOverSaslExternalWithoutClientCert) { } }, responses); ldapServer.Start(); - TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login, password); + TAutoPtr<IEventHandle> handle = LdapAuthenticate(ydbServer, login); TEvTicketParser::TEvAuthorizeTicketResult* ticketParserResult = handle->Get<TEvTicketParser::TEvAuthorizeTicketResult>(); UNIT_ASSERT_C(ticketParserResult->HasError(), "Should be error"); UNIT_ASSERT_EQUAL_C(ticketParserResult->Error.Message, "Could not login via LDAP", ticketParserResult->Error); diff --git a/ydb/core/security/ticket_parser_ut.cpp b/ydb/core/security/ticket_parser_ut.cpp index a5ec40b0a82..6ca78ef2a75 100644 --- a/ydb/core/security/ticket_parser_ut.cpp +++ b/ydb/core/security/ticket_parser_ut.cpp @@ -37,6 +37,35 @@ using TAccessServiceMock = TTicketParserAccessServiceMock; using TAccessServiceMockV2 = TTicketParserAccessServiceMockV2; using TNebiusAccessServiceMock = TTicketParserNebiusAccessServiceMock; +// Precomputed argon2id + SCRAM-SHA-256 hashes from scram_ut.cpp +// Password: "password1" +static const TString PASSWORD1_HASHES = R"({ + "version": 1, + "argon2id": "flbr3YnA9kG67qegwDTaYg==$wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo=", + "scram-sha-256": "4096:s0QSrrFVkMTh3k2TTk860A==$LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=:eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" +})"; + +// The ServerKey of the SCRAM-SHA-256 hash above. +static const TString PASSWORD1_SCRAM_SERVER_KEY = "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc="; + +NLogin::TLoginProvider::TCreateUserRequest MakeCreateUserRequest(const TString& user) { + return { + .User = user, + .HashedPassword = Base64Encode(PASSWORD1_HASHES), + }; +} + +NLogin::TLoginProvider::TLoginUserRequest MakeLoginUserRequest(const TString& user) { + return { + .User = user, + .HashToValidate = NLogin::TLoginProvider::THashToValidate{ + .AuthMech = NLoginProto::ESaslAuthMech::Plain, + .HashType = NLoginProto::EHashType::ScramSha256, + .Hash = PASSWORD1_SCRAM_SERVER_KEY, + }, + }; +} + template <class TAccessServiceMock> void SetUseAccessService(NKikimrProto::TAuthConfig& authConfig); @@ -176,8 +205,8 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - provider.CreateUser({.User = "user1", .Password = "password1"}); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket(loginResponse.Token)), 0); @@ -217,12 +246,12 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); provider.CreateGroup({.Group = "group1"}); - provider.CreateUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); provider.AddGroupMembership({.Group = "group1", .Member = "user1"}); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -266,11 +295,11 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); loginProviderDb1.CreateGroup({.Group = "group1"}); - loginProviderDb1.CreateUser({.User = "user1", .Password = "password1"}); + loginProviderDb1.CreateUser(MakeCreateUserRequest("user1")); loginProviderDb1.AddGroupMembership({.Group = "group1", .Member = "user1"}); - auto loginResponse = loginProviderDb1.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = loginProviderDb1.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -297,11 +326,11 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); loginProviderDb2.CreateGroup({.Group = "group1"}); - loginProviderDb2.CreateUser({.User = "user1", .Password = "password1"}); + loginProviderDb2.CreateUser(MakeCreateUserRequest("user1")); loginProviderDb2.AddGroupMembership({.Group = "group1", .Member = "user1"}); - auto loginResponse = loginProviderDb2.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = loginProviderDb2.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -349,11 +378,11 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); loginProviderDb1.CreateGroup({.Group = "group1"}); - loginProviderDb1.CreateUser({.User = "user1", .Password = "password1"}); + loginProviderDb1.CreateUser(MakeCreateUserRequest("user1")); loginProviderDb1.AddGroupMembership({.Group = "group1", .Member = "user1"}); - auto loginResponse = loginProviderDb1.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = loginProviderDb1.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -438,12 +467,12 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); provider.CreateGroup({.Group = "group1"}); - provider.CreateUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); provider.AddGroupMembership({.Group = "group1", .Member = "user1"}); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -524,7 +553,7 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); provider.CreateGroup({.Group = "group1"}); - provider.CreateUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); provider.AddGroupMembership({.Group = "group1", .Member = "user1"}); NLogin::TLoginProvider emptyProvider; @@ -532,7 +561,7 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(emptyProvider.GetSecurityState())), 0); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -590,12 +619,12 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); provider.CreateGroup({.Group = "group1"}); - provider.CreateUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); provider.AddGroupMembership({.Group = "group1", .Member = "user1"}); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, ""); @@ -652,8 +681,8 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TActorId sender = runtime->AllocateEdgeActor(); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvUpdateLoginSecurityState(provider.GetSecurityState())), 0); - provider.CreateUser({.User = "user1", .Password = "password1"}); - auto loginResponse = provider.LoginUser({.User = "user1", .Password = "password1"}); + provider.CreateUser(MakeCreateUserRequest("user1")); + auto loginResponse = provider.LoginUser(MakeLoginUserRequest("user1")); TString emptyUserToken = ""; diff --git a/ydb/core/tx/schemeshard/schemeshard__init.cpp b/ydb/core/tx/schemeshard/schemeshard__init.cpp index b160e5599e8..3a950a672c2 100644 --- a/ydb/core/tx/schemeshard/schemeshard__init.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__init.cpp @@ -1406,13 +1406,6 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> { } { - ui64 isOldArgonHashFormatMigrationCompletedVal = 0; - RETURN_IF_NO_PRECHARGED(Self->ReadSysValue(db, Schema::SysParam_IsOldArgonHashFormatMigrationCompleted, - isOldArgonHashFormatMigrationCompletedVal)); - Self->IsOldArgonHashFormatMigrationCompleted = isOldArgonHashFormatMigrationCompletedVal; - } - - { ui64 sweepStatusVal = 0; RETURN_IF_NO_PRECHARGED(Self->ReadSysValue(db, Schema::SysParam_TablePartitionsFormatSweepStatus, sweepStatusVal)); switch (sweepStatusVal) { diff --git a/ydb/core/tx/schemeshard/schemeshard__login.cpp b/ydb/core/tx/schemeshard/schemeshard__login.cpp index 662ccf0c20b..a0e27c51bfe 100644 --- a/ydb/core/tx/schemeshard/schemeshard__login.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__login.cpp @@ -11,11 +11,9 @@ namespace NSchemeShard { struct TSchemeShard::TTxLogin : TSchemeShard::TRwTxBase { TEvSchemeShard::TEvLogin::TPtr Request; - NLogin::TLoginProvider::TLoginUserResponse Response; TPathId SubDomainPathId; bool NeedPublishOnComplete = false; - bool SendFinalizeEvent = false; - TString ErrMessage; + THolder<TEvSchemeShard::TEvLoginResult> Result = MakeHolder<TEvSchemeShard::TEvLoginResult>(); TTxLogin(TSelf *self, TEvSchemeShard::TEvLogin::TPtr &ev) : TRwTxBase(self) @@ -64,33 +62,19 @@ struct TSchemeShard::TTxLogin : TSchemeShard::TRwTxBase { const auto& loginRequest = GetLoginRequest(); if (!loginRequest.ExternalAuth.has_value()) { if (!AppData(ctx)->AuthConfig.GetEnableLoginAuthentication()) { - ErrMessage = "Login authentication is disabled"; - } else { - CheckLockOutUserAndSetErrorIfAny(loginRequest.User, db); + Result->Record.SetError("Login authentication is disabled"); + return; + } + if (CheckLockOutUserAndSetErrorIfAny(loginRequest.User, db)) { + return; } } - if (ErrMessage) { - SendError(); - return; - } - - TString hashValues; - if (Self->LoginProvider.NeedVerifyHash(loginRequest, &Response, &hashValues)) { - if (loginRequest.HashToValidate.has_value()) { - Self->LoginProvider.VerifyHashValues(loginRequest, &Response, hashValues); - SendFinalizeEvent = true; - } else if (loginRequest.Password.has_value()) { // for backward compatibility - ctx.Send( - Self->LoginHelper, - MakeHolder<TEvPrivate::TEvVerifyPassword>(loginRequest, Response, Request->Sender, hashValues), - 0, - Request->Cookie - ); - } - } else { - SendFinalizeEvent = true; + const auto response = Self->LoginProvider.LoginUser(loginRequest); + if (!loginRequest.ExternalAuth.has_value()) { + UpdateLoginSidsStats(response, db); } + FillResult(response); } void DoComplete(const TActorContext &ctx) override { @@ -98,23 +82,22 @@ struct TSchemeShard::TTxLogin : TSchemeShard::TRwTxBase { Self->PublishToSchemeBoard(TTxId(), {SubDomainPathId}, ctx); } - if (SendFinalizeEvent) { - auto event = MakeHolder<TEvPrivate::TEvLoginFinalize>( - GetLoginRequest(), Response, Request->Sender, "", /*needUpdateCache*/ false - ); - TEvPrivate::TEvLoginFinalize::TPtr eventPtr = (TEventHandle<TEvPrivate::TEvLoginFinalize>*) new IEventHandle( - Self->SelfId(), Self->SelfId(), event.Release() - ); - Self->Execute(Self->CreateTxLoginFinalize(eventPtr), ctx); - } - + const TString& error = Result->Record.GetError(); LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxLogin Complete" - << ", with " << (ErrMessage ? "error: " + ErrMessage : "no errors") + << ", with " << (error ? "error: " + error : "no errors") << ", at schemeshard: " << Self->TabletID()); -} + + Self->Send(Request->Sender, std::move(Result), 0, Request->Cookie); + } private: + bool IsAdmin() const { + const auto& user = Request->Get()->Record.GetUser(); + const auto userToken = NKikimr::BuildLocalUserToken(Self->LoginProvider, user); + return IsAdministrator(AppData(), &userToken); + } + void RotateKeys(const TActorContext& ctx, NIceDb::TNiceDb& db) { LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxLogin RotateKeys at schemeshard: " << Self->TabletID()); std::vector<ui64> keysExpired; @@ -141,14 +124,15 @@ private: } } - void CheckLockOutUserAndSetErrorIfAny(const TString& user, NIceDb::TNiceDb& db) { + // Returns true if the user is locked out and an error has been set into the result. + bool CheckLockOutUserAndSetErrorIfAny(const TString& user, NIceDb::TNiceDb& db) { using namespace NLogin; const TLoginProvider::TCheckLockOutResponse checkLockOutResponse = Self->LoginProvider.CheckLockOutUser({.User = user}); switch (checkLockOutResponse.Status) { case TLoginProvider::TCheckLockOutResponse::EStatus::SUCCESS: case TLoginProvider::TCheckLockOutResponse::EStatus::INVALID_USER: { - ErrMessage = checkLockOutResponse.Error; - return; + Result->Record.SetError(checkLockOutResponse.Error); + return true; } case TLoginProvider::TCheckLockOutResponse::EStatus::RESET: { const auto& sid = Self->LoginProvider.Sids[user]; @@ -160,17 +144,55 @@ private: break; } } + return false; } - void SendError() { - THolder<TEvSchemeShard::TEvLoginResult> result = MakeHolder<TEvSchemeShard::TEvLoginResult>(); - result->Record.SetError(ErrMessage); - Self->Send( - Request->Sender, - std::move(result), - 0, - Request->Cookie - ); + void FillResult(const NLogin::TLoginProvider::TLoginUserResponse& response) { + switch (response.Status) { + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS: { + if (response.ServerSignature.has_value()) { + Result->Record.SetServerSignature(*response.ServerSignature); + } + Result->Record.SetToken(response.Token); + Result->Record.SetSanitizedToken(response.SanitizedToken); + Result->Record.SetIsAdmin(IsAdmin()); + break; + } + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD: + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_USER: + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNAVAILABLE_KEY: + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_HASH_TYPE: + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNSUPPORTED_SASL_MECHANISM: + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNSPECIFIED: { + Result->Record.SetError(response.Error); + break; + } + } + } + + void UpdateLoginSidsStats(const NLogin::TLoginProvider::TLoginUserResponse& response, NIceDb::TNiceDb& db) { + const TString& user = Request->Get()->Record.GetUser(); + switch (response.Status) { + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS: { + const auto& sid = Self->LoginProvider.Sids[user]; + db.Table<Schema::LoginSids>() + .Key(user) + .Update<Schema::LoginSids::LastSuccessfulAttempt, Schema::LoginSids::FailedAttemptCount>( + ToMicroSeconds(sid.LastSuccessfulLogin), sid.FailedLoginAttemptCount + ); + break; + } + case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD: { + const auto& sid = Self->LoginProvider.Sids[user]; + db.Table<Schema::LoginSids>() + .Key(user) + .Update<Schema::LoginSids::LastFailedAttempt, Schema::LoginSids::FailedAttemptCount>( + ToMicroSeconds(sid.LastFailedLogin), sid.FailedLoginAttemptCount + ); + } + default: + break; + } } }; diff --git a/ydb/core/tx/schemeshard/schemeshard__login_finalize.cpp b/ydb/core/tx/schemeshard/schemeshard__login_finalize.cpp deleted file mode 100644 index 015f7278ea8..00000000000 --- a/ydb/core/tx/schemeshard/schemeshard__login_finalize.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "schemeshard_impl.h" -#include <ydb/library/security/util.h> -#include <ydb/core/protos/auth.pb.h> -#include <ydb/core/base/auth.h> -#include <ydb/core/base/local_user_token.h> - -namespace NKikimr { -namespace NSchemeShard { - -struct TSchemeShard::TTxLoginFinalize : TSchemeShard::TRwTxBase { -private: - TEvPrivate::TEvLoginFinalize::TPtr LoginFinalizeEventPtr; - TString ErrMessage; - -public: - TTxLoginFinalize(TSelf *self, TEvPrivate::TEvLoginFinalize::TPtr &ev) - : TRwTxBase(self) - , LoginFinalizeEventPtr(std::move(ev)) - {} - - TTxType GetTxType() const override { - return TXTYPE_LOGIN_FINALIZE; - } - - void DoExecute(TTransactionContext& txc, const TActorContext& ctx) override { - LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TTxLoginFinalize Execute" - << " at schemeshard: " << Self->TabletID()); - - const auto& event = *LoginFinalizeEventPtr->Get(); - if (event.NeedUpdateCache) { - const auto isSuccessVerifying = - event.CheckResult.Status == NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS; - Self->LoginProvider.UpdateCache( - event.Request, - event.PasswordHash, - isSuccessVerifying - ); - } - const auto response = Self->LoginProvider.LoginUser(event.Request, event.CheckResult); - - if (!LoginFinalizeEventPtr->Get()->Request.ExternalAuth.has_value()) { - UpdateLoginSidsStats(response, txc); - } - if (!response.Error.empty()) { - ErrMessage = response.Error; - SendError(response.Error); - return; - } - FillResult(response); - } - - void DoComplete(const TActorContext &ctx) override { - LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TTxLoginFinalize Completed" - << ", with " << (ErrMessage ? "error: " + ErrMessage : "no errors") - << " at schemeshard: " << Self->TabletID()); - } - -private: - bool IsAdmin(const TString& user) const { - const auto userToken = NKikimr::BuildLocalUserToken(Self->LoginProvider, user); - return IsAdministrator(AppData(), &userToken); - } - - void FillResult(const NLogin::TLoginProvider::TLoginUserResponse& response) { - THolder<TEvSchemeShard::TEvLoginResult> result = MakeHolder<TEvSchemeShard::TEvLoginResult>(); - switch (response.Status) { - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS: { - if (response.ServerSignature.has_value()) { - result->Record.SetServerSignature(*response.ServerSignature); - } - - result->Record.SetToken(response.Token); - result->Record.SetSanitizedToken(response.SanitizedToken); - result->Record.SetIsAdmin(IsAdmin(LoginFinalizeEventPtr->Get()->Request.User)); - break; - } - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD: - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_USER: - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNAVAILABLE_KEY: - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_HASH_TYPE: - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNSUPPORTED_SASL_MECHANISM: - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::UNSPECIFIED: { - result->Record.SetError(response.Error); - break; - } - } - Self->Send( - LoginFinalizeEventPtr->Get()->Source, - std::move(result), - 0, - LoginFinalizeEventPtr->Cookie - ); - } - - void SendError(const TString& error) { - auto result = MakeHolder<TEvSchemeShard::TEvLoginResult>(); - result->Record.SetError(error); - Self->Send( - LoginFinalizeEventPtr->Get()->Source, - std::move(result), - 0, - LoginFinalizeEventPtr->Cookie - ); - } - - void UpdateLoginSidsStats(const NLogin::TLoginProvider::TLoginUserResponse& response, TTransactionContext& txc) { - NIceDb::TNiceDb db(txc.DB); - switch (response.Status) { - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS: { - const auto& sid = Self->LoginProvider.Sids[LoginFinalizeEventPtr->Get()->Request.User]; - db.Table<Schema::LoginSids>() - .Key(LoginFinalizeEventPtr->Get()->Request.User) - .Update<Schema::LoginSids::LastSuccessfulAttempt, Schema::LoginSids::FailedAttemptCount>( - ToMicroSeconds(sid.LastSuccessfulLogin), sid.FailedLoginAttemptCount - ); - break; - } - case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD: { - const auto& sid = Self->LoginProvider.Sids[LoginFinalizeEventPtr->Get()->Request.User]; - db.Table<Schema::LoginSids>() - .Key(LoginFinalizeEventPtr->Get()->Request.User) - .Update<Schema::LoginSids::LastFailedAttempt, Schema::LoginSids::FailedAttemptCount>( - ToMicroSeconds(sid.LastFailedLogin), sid.FailedLoginAttemptCount - ); - } - default: - break; - } - } -}; - -NTabletFlatExecutor::ITransaction* TSchemeShard::CreateTxLoginFinalize(TEvPrivate::TEvLoginFinalize::TPtr &ev) { - return new TTxLoginFinalize(this, ev); -} - -}} diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp index 5cac29745f8..cee51ab22f5 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp @@ -99,10 +99,11 @@ public: } else { auto& sid = context.SS->LoginProvider.Sids[modifyUser.GetUser()]; db.Table<Schema::LoginSids>().Key(sid.Name).Update<Schema::LoginSids::SidType, + Schema::LoginSids::SidHash, // explicitly erase deprecated field Schema::LoginSids::PasswordHashes, Schema::LoginSids::IsEnabled, Schema::LoginSids::FailedAttemptCount>( - sid.Type, sid.PasswordHashes, sid.IsEnabled, sid.FailedLoginAttemptCount); + sid.Type, "", sid.PasswordHashes, sid.IsEnabled, sid.FailedLoginAttemptCount); result->SetStatus(NKikimrScheme::StatusSuccess); AddIsUserAdmin(modifyUser.GetUser(), context.SS->LoginProvider, additionalParts); diff --git a/ydb/core/tx/schemeshard/schemeshard__user_hashes_migration.cpp b/ydb/core/tx/schemeshard/schemeshard__user_hashes_migration.cpp deleted file mode 100644 index dd73d7486bb..00000000000 --- a/ydb/core/tx/schemeshard/schemeshard__user_hashes_migration.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "schemeshard_impl.h" - -#include <ydb/library/login/hashes_checker/hashes_checker.h> -#include <ydb/library/login/password_checker/password_checker.h> -#include <ydb/library/login/protos/login.pb.h> - -#include <util/generic/vector.h> -#include <util/random/random.h> -#include <algorithm> - - -namespace NKikimr { -namespace NSchemeShard { - -using namespace NTabletFlatExecutor; - -namespace { - -TString GenerateRandomPassword(const NLogin::TPasswordComplexity& complexity) { - static constexpr char lowerLetters[] = "abcdefghijklmnopqrstuvwxyz"; - static constexpr char upperLetters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - static constexpr char digits[] = "0123456789"; - static constexpr size_t lowerCount = sizeof(lowerLetters) - 1; - static constexpr size_t upperCount = sizeof(upperLetters) - 1; - static constexpr size_t digitsCount = sizeof(digits) - 1; - - - TVector<char> specialChars(complexity.SpecialChars.begin(), complexity.SpecialChars.end()); - - TVector<char> password; - - // Add required minimum counts for each character class - for (size_t i = 0; i < complexity.MinLowerCaseCount; ++i) { - password.push_back(lowerLetters[RandomNumber<size_t>(lowerCount)]); - } - for (size_t i = 0; i < complexity.MinUpperCaseCount; ++i) { - password.push_back(upperLetters[RandomNumber<size_t>(upperCount)]); - } - for (size_t i = 0; i < complexity.MinNumbersCount; ++i) { - password.push_back(digits[RandomNumber<size_t>(digitsCount)]); - } - for (size_t i = 0; i < complexity.MinSpecialCharsCount; ++i) { - password.push_back(specialChars[RandomNumber<size_t>(specialChars.size())]); - } - - size_t minLength = std::max(complexity.MinLength, static_cast<size_t>(8)); - // Fill remaining positions with random chars from all allowed categories - if (password.size() < minLength) { - - TVector<char> pool; - pool.insert(pool.end(), lowerLetters, lowerLetters + lowerCount); - pool.insert(pool.end(), upperLetters, upperLetters + upperCount); - pool.insert(pool.end(), digits, digits + digitsCount); - pool.insert(pool.end(), specialChars.begin(), specialChars.end()); - - while (password.size() < minLength) { - password.push_back(pool[RandomNumber<size_t>(pool.size())]); - } - } - - - // Shuffle to avoid predictable prefix pattern - for (size_t i = password.size() - 1; i > 0; --i) { - size_t j = RandomNumber<size_t>(i + 1); - std::swap(password[i], password[j]); - } - - return TString(password.begin(), password.end()); -} - -} // anonymous namespace - -struct TSchemeShard::TTxUserHashesMigration : public TTransactionBase<TSchemeShard> { - bool IsLoginProviderModified = false; - - TTxUserHashesMigration(TSelf* self) - : TTransactionBase<TSchemeShard>(self) - {} - - TTxType GetTxType() const override { - return TXTYPE_USER_HASHES_MIGRATION; - } - - bool Execute(TTransactionContext &txc, const TActorContext &ctx) override { - LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TTxUserHashesMigration Execute at schemeshard: " << Self->TabletID()); - - NIceDb::TNiceDb db(txc.DB); - for (const auto& [sidName, sid] : Self->LoginProvider.Sids) { - if (sid.Type == NLoginProto::ESidType::USER) { - if (!sid.PasswordHashes) { // change password for user with unsupported password hash format - auto response = Self->LoginProvider.ModifyUser({ - .User = sid.Name, - .Password = GenerateRandomPassword(Self->LoginProvider.GetPasswordCheckParameters()), - }); - - if (response.Error) { - LOG_ERROR_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxUserHashesMigration Execute" - << ", can't set generated password in place unacceptable argon hash: " - << response.Error << ", at schemeshard: "<< Self->TabletID()); - continue; - } - - IsLoginProviderModified = true; - } - - db.Table<Schema::LoginSids>().Key(sidName).Update<Schema::LoginSids::PasswordHashes>(sid.PasswordHashes); - } - } - - Self->IsOldArgonHashFormatMigrationCompleted = true; - db.Table<Schema::SysParams>().Key(Schema::SysParam_IsOldArgonHashFormatMigrationCompleted).Update( - NIceDb::TUpdate<Schema::SysParams::Value>("1")); - - if (IsLoginProviderModified) { - TPathId subDomainPathId = Self->GetCurrentSubDomainPathId(); - TSubDomainInfo::TPtr domainPtr = Self->ResolveDomainInfo(subDomainPathId); - domainPtr->UpdateSecurityState(Self->LoginProvider.GetSecurityState()); - domainPtr->IncSecurityStateVersion(); - Self->PersistSubDomainSecurityStateVersion(db, subDomainPathId, *domainPtr); - } - - return true; - } - - void Complete(const TActorContext &ctx) override { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "TTxUserHashesMigration Complete, at schemeshard: "<< Self->TabletID()); - - if (IsLoginProviderModified) { - Self->PublishToSchemeBoard(TTxId(), {Self->GetCurrentSubDomainPathId()}, ctx); - } - } -}; - -ITransaction* TSchemeShard::CreateTxUserHashesMigration() { - return new TTxUserHashesMigration(this); -} - -} // NSchemeShard -} // NKikimr diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index ce875b396d0..a7a62858333 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -1,6 +1,5 @@ #include "schemeshard_impl.h" #include "schemeshard__local_index_migration.h" -#include "schemeshard_login_helper.h" #include "schemeshard_svp_migration.h" #include "olap/bg_tasks/adapter/adapter.h" @@ -378,10 +377,6 @@ void TSchemeShard::ActivateAfterInitialization(const TActorContext& ctx, TActiva InitializeTabletMigrations(); } - if (!IsOldArgonHashFormatMigrationCompleted) { - Execute(CreateTxUserHashesMigration(), ctx); - } - ResumeExports(opts.ExportIds, ctx); ResumeImports(opts.ImportsIds, ctx); ResumeCdcStreamScans(opts.CdcStreamScans, ctx); @@ -5569,8 +5564,7 @@ TSchemeShard::TSchemeShard(const TActorId &tablet, TTabletStorageInfo *info) }), { .AttemptThreshold = AppData()->AuthConfig.GetAccountLockout().GetAttemptThreshold(), .AttemptResetDuration = AppData()->AuthConfig.GetAccountLockout().GetAttemptResetDuration() - }, - IsLoginCacheEnabled, {}) + }) { TabletCountersPtr.Reset(new TProtobufTabletCounters< ESimpleCounters_descriptor, @@ -5609,9 +5603,6 @@ NTabletPipe::TClientConfig TSchemeShard::GetPipeClientConfig() { return config; } -bool TSchemeShard::IsLoginCacheEnabled() { - return AppData()->FeatureFlags.GetEnableLoginCache(); -} void TSchemeShard::FillTableSchemaVersion(ui64 tableSchemaVersion, NKikimrSchemeOp::TTableDescription* tableDescr) const { tableDescr->SetTableSchemaVersion(tableSchemaVersion); @@ -5631,7 +5622,6 @@ void TSchemeShard::Die(const TActorContext &ctx) { ctx.Send(SchemeBoardPopulator, new TEvents::TEvPoisonPill()); ctx.Send(TxAllocatorClient, new TEvents::TEvPoisonPill()); ctx.Send(SysPartitionStatsCollector, new TEvents::TEvPoisonPill()); - ctx.Send(LoginHelper, new TEvents::TEvPoisonPill()); if (TabletMigrator) { ctx.Send(TabletMigrator, new TEvents::TEvPoisonPill()); @@ -5775,8 +5765,6 @@ void TSchemeShard::OnActivateExecutor(const TActorContext &ctx) { Execute(CreateTxInitSchema(), ctx); SubscribeConsoleConfigs(ctx); - - LoginHelper = Register(CreateLoginHelper(this->LoginProvider).Release()); } // This is overriden as noop in order to activate the table only at the end of Init transaction @@ -6087,7 +6075,6 @@ void TSchemeShard::StateWork(STFUNC_SIG) { HFuncTraced(TEvPrivate::TEvPersistTopicStats, Handle); HFuncTraced(TEvSchemeShard::TEvLogin, Handle); - HFuncTraced(TEvPrivate::TEvLoginFinalize, Handle); HFuncTraced(TEvSchemeShard::TEvListUsers, Handle); HFuncTraced(TEvDataShard::TEvProposeTransactionAttachResult, Handle); @@ -9164,10 +9151,6 @@ void TSchemeShard::Handle(TEvSchemeShard::TEvLogin::TPtr &ev, const TActorContex Execute(CreateTxLogin(ev), ctx); } -void TSchemeShard::Handle(TEvPrivate::TEvLoginFinalize::TPtr &ev, const TActorContext &ctx) { - Execute(CreateTxLoginFinalize(ev), ctx); -} - void TSchemeShard::Handle(TEvSchemeShard::TEvListUsers::TPtr &ev, const TActorContext &ctx) { Execute(CreateTxListUsers(ev), ctx); } diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.h b/ydb/core/tx/schemeshard/schemeshard_impl.h index 5a45ff03727..9785f93097a 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.h +++ b/ydb/core/tx/schemeshard/schemeshard_impl.h @@ -13,7 +13,6 @@ #include "schemeshard_forced_compaction.h" #include "schemeshard_import.h" #include "schemeshard_info_types.h" -#include "schemeshard_login_helper.h" #include "schemeshard_path.h" #include "schemeshard_path_element.h" #include "schemeshard_private.h" @@ -427,8 +426,6 @@ public: bool EnableExternalSourceSchemaInference = false; bool EnableMoveColumnTable = false; - bool IsOldArgonHashFormatMigrationCompleted = false; - TShardDeleter ShardDeleter; // Counter-strike stuff @@ -1116,9 +1113,6 @@ public: struct TTxCleanDroppedPaths; NTabletFlatExecutor::ITransaction* CreateTxCleanDroppedPaths(); - struct TTxUserHashesMigration; - NTabletFlatExecutor::ITransaction* CreateTxUserHashesMigration(); - void ScheduleCleanDroppedPaths(); void Handle(TEvPrivate::TEvCleanDroppedPaths::TPtr& ev, const TActorContext& ctx); @@ -1265,8 +1259,6 @@ public: struct TTxLogin; NTabletFlatExecutor::ITransaction* CreateTxLogin(TEvSchemeShard::TEvLogin::TPtr &ev); - struct TTxLoginFinalize; - NTabletFlatExecutor::ITransaction* CreateTxLoginFinalize(TEvPrivate::TEvLoginFinalize::TPtr &ev); struct TTxListUsers; NTabletFlatExecutor::ITransaction* CreateTxListUsers(TEvSchemeShard::TEvListUsers::TPtr &ev); @@ -1585,7 +1577,6 @@ public: void Handle(NConsole::TEvConsole::TEvConfigNotificationRequest::TPtr &ev, const TActorContext &ctx); void Handle(TEvSchemeShard::TEvLogin::TPtr& ev, const TActorContext& ctx); - void Handle(TEvPrivate::TEvLoginFinalize::TPtr& ev, const TActorContext& ctx); void Handle(TEvSchemeShard::TEvListUsers::TPtr& ev, const TActorContext& ctx); void Handle(TEvPrivate::TEvProgressTablePartitionsFormatSweep::TPtr& ev, const TActorContext& ctx); @@ -2211,7 +2202,6 @@ public: void SetShardsQuota(ui64 value) override; NLogin::TLoginProvider LoginProvider; - TActorId LoginHelper; THolder<TRootShredManager> RootShredManager = nullptr; THolder<TTenantShredManager> TenantShredManager = nullptr; @@ -2236,8 +2226,6 @@ private: NKikimrSubDomains::TProcessingParams CreateRootProcessingParams(const TActorContext &ctx); static NTabletPipe::TClientConfig GetPipeClientConfig(); - static bool IsLoginCacheEnabled(); - public: static const NKikimrConfig::TDomainsConfig& GetDomainsConfig(); diff --git a/ydb/core/tx/schemeshard/schemeshard_login_helper.cpp b/ydb/core/tx/schemeshard/schemeshard_login_helper.cpp deleted file mode 100644 index ea408f159c9..00000000000 --- a/ydb/core/tx/schemeshard/schemeshard_login_helper.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "schemeshard_login_helper.h" -#include "schemeshard_private.h" -#include <ydb/library/actors/core/actor_bootstrapped.h> -#include <ydb/library/actors/core/events.h> -#include <ydb/library/actors/core/hfunc.h> -#include <ydb/library/login/login.h> - -namespace NKikimr::NSchemeShard { - -class TLoginHelper : public NActors::TActorBootstrapped<TLoginHelper> { -public: - explicit TLoginHelper(const NLogin::TLoginProvider& loginProvider) - : LoginProvider_(loginProvider) - {} - - void Bootstrap() { - Become(&TThis::StateWork); - } - - STATEFN(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvPrivate::TEvVerifyPassword, VerifyPassword); - cFunc(NActors::TEvents::TEvPoison::EventType, PassAway); - } - } - -private: - void VerifyPassword(TEvPrivate::TEvVerifyPassword::TPtr& ev) { - const bool isSuccessVerifying = LoginProvider_.VerifyArgonHash(ev->Get()->Request, ev->Get()->PasswordHash); - if (!isSuccessVerifying) { - ev->Get()->CheckResult.Status = NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD; - ev->Get()->CheckResult.Error = "Invalid password"; - } - Send( - ev->Sender, - MakeHolder<TEvPrivate::TEvLoginFinalize>( - ev->Get()->Request, - ev->Get()->CheckResult, - ev->Get()->Source, - ev->Get()->PasswordHash, - /*needUpdateCache*/ true - ), - 0, - ev->Cookie - ); - } - -private: - const NLogin::TLoginProvider& LoginProvider_; -}; - -THolder<NActors::IActor> CreateLoginHelper(const NLogin::TLoginProvider& loginProvider) { - return MakeHolder<TLoginHelper>(loginProvider); -} - -} // namespace NKikimr::NSchemeShard diff --git a/ydb/core/tx/schemeshard/schemeshard_login_helper.h b/ydb/core/tx/schemeshard/schemeshard_login_helper.h deleted file mode 100644 index d17666bff73..00000000000 --- a/ydb/core/tx/schemeshard/schemeshard_login_helper.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include <ydb/library/actors/core/actor.h> - -namespace NLogin { - class TLoginProvider; -} - -namespace NKikimr::NSchemeShard { - -THolder<NActors::IActor> CreateLoginHelper(const NLogin::TLoginProvider& loginProvider); - -} // namespace NKikimr::NSchemeShard diff --git a/ydb/core/tx/schemeshard/schemeshard_private.h b/ydb/core/tx/schemeshard/schemeshard_private.h index ddb7bf9d61a..6478fd45c39 100644 --- a/ydb/core/tx/schemeshard/schemeshard_private.h +++ b/ydb/core/tx/schemeshard/schemeshard_private.h @@ -8,7 +8,6 @@ #include <ydb/library/actors/core/event_local.h> #include <ydb/library/actors/core/events.h> -#include <ydb/library/login/login.h> #include <util/datetime/base.h> @@ -49,8 +48,6 @@ namespace TEvPrivate { EvRunShred, EvRunTenantShred, EvAddNewShardToShred, - EvVerifyPassword, - EvLoginFinalize, EvContinuousBackupCleanerResult, EvTestNotifySubdomainCleanup, EvFlushConditionalEraseBatch, @@ -327,51 +324,6 @@ namespace TEvPrivate { {} }; - struct TEvVerifyPassword : public NActors::TEventLocal<TEvVerifyPassword, EvVerifyPassword> { - public: - TEvVerifyPassword( - const NLogin::TLoginProvider::TLoginUserRequest& request, - const NLogin::TLoginProvider::TPasswordCheckResult& checkResult, - const NActors::TActorId source, - const TString& passwordHash - ) - : Request(request) - , CheckResult(checkResult) - , Source(source) - , PasswordHash(passwordHash) - {} - - public: - const NLogin::TLoginProvider::TLoginUserRequest Request; - NLogin::TLoginProvider::TPasswordCheckResult CheckResult; - const NActors::TActorId Source; // actorId of the initial schemeshard client which requested user login - const TString PasswordHash; - }; - - struct TEvLoginFinalize : public NActors::TEventLocal<TEvLoginFinalize, EvLoginFinalize> { - public: - TEvLoginFinalize( - const NLogin::TLoginProvider::TLoginUserRequest& request, - const NLogin::TLoginProvider::TPasswordCheckResult& checkResult, - const NActors::TActorId source, - const TString& passwordHash, - const bool needUpdateCache - ) - : Request(request) - , CheckResult(checkResult) - , Source(source) - , PasswordHash(passwordHash) - , NeedUpdateCache(needUpdateCache) - {} - - public: - const NLogin::TLoginProvider::TLoginUserRequest Request; - const NLogin::TLoginProvider::TPasswordCheckResult CheckResult; - const NActors::TActorId Source; // actorId of the initial schemeshard client which requested user login - const TString PasswordHash; - const bool NeedUpdateCache; - }; - struct TEvContinuousBackupCleanerResult : public NActors::TEventLocal<TEvContinuousBackupCleanerResult, EvContinuousBackupCleanerResult> { public: TEvContinuousBackupCleanerResult(ui64 backupId, TPathId item, bool success, const TString& error = "") diff --git a/ydb/core/tx/schemeshard/schemeshard_schema.h b/ydb/core/tx/schemeshard/schemeshard_schema.h index 76c033ea986..40652564916 100644 --- a/ydb/core/tx/schemeshard/schemeshard_schema.h +++ b/ydb/core/tx/schemeshard/schemeshard_schema.h @@ -2838,7 +2838,7 @@ struct Schema : NIceDb::Schema { static constexpr ui64 SysParam_TenantInitState = 9; static constexpr ui64 SysParam_ServerlessStorageLastBillTime = 10; static constexpr ui64 SysParam_MaxIncompatibleChange = 11; - static constexpr ui64 SysParam_IsOldArgonHashFormatMigrationCompleted = 12; + // static constexpr ui64 SysParam_IsOldArgonHashFormatMigrationCompleted = 12; deprecated static constexpr ui64 SysParam_TablePartitionsFormatSweepStatus = 13; static constexpr ui64 SysParam_TablePartitionsFormatSweepTarget = 14; diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp index 46df8807e3f..9dc5438b889 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp @@ -2715,23 +2715,6 @@ namespace NSchemeShardUT_Private { return event->Record; } - NKikimrScheme::TEvLoginResult LoginFinalize( - TTestActorRuntime& runtime, - const NLogin::TLoginProvider::TLoginUserRequest& request, - const NLogin::TLoginProvider::TPasswordCheckResult& checkResult, - const TString& passwordHash, - const bool needUpdateCache - ) { - const auto evLoginFinalize = new NSchemeShard::TEvPrivate::TEvLoginFinalize( - request, checkResult, runtime.AllocateEdgeActor(), passwordHash, needUpdateCache - ); - AsyncSend(runtime, TTestTxConfig::SchemeShard, evLoginFinalize); - TAutoPtr<IEventHandle> handle; - const auto event = runtime.GrabEdgeEvent<TEvSchemeShard::TEvLoginResult>(handle); - UNIT_ASSERT(event); - return event->Record; - } - void ModifyUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, std::function<void(::NKikimrSchemeOp::TLoginModifyUser*)>&& initiator) { auto modifyTx = std::make_unique<TEvSchemeShard::TEvModifySchemeTransaction>(txId, TTestTxConfig::SchemeShard); auto transaction = modifyTx->Record.AddTransaction(); diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.h b/ydb/core/tx/schemeshard/ut_helpers/helpers.h index 553d8d4a596..becb5f7d0ca 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.h +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.h @@ -686,14 +686,6 @@ namespace NSchemeShardUT_Private { const TString& user, NLoginProto::ESaslAuthMech::SaslAuthMech authMech, NLoginProto::EHashType::HashType hashType, const TString& hash, const TString& authMessage = ""); - NKikimrScheme::TEvLoginResult LoginFinalize( - TTestActorRuntime& runtime, - const NLogin::TLoginProvider::TLoginUserRequest& request, - const NLogin::TLoginProvider::TPasswordCheckResult& checkResult, - const TString& passwordHash, - const bool needUpdateCache - ); - void ModifyUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, std::function<void(::NKikimrSchemeOp::TLoginModifyUser*)>&& initiator); void ChangeIsEnabledUser(TTestActorRuntime& runtime, ui64 txId, const TString& database, diff --git a/ydb/core/tx/schemeshard/ut_login/ut_login.cpp b/ydb/core/tx/schemeshard/ut_login/ut_login.cpp index 8a3bdb298ef..64f591924e0 100644 --- a/ydb/core/tx/schemeshard/ut_login/ut_login.cpp +++ b/ydb/core/tx/schemeshard/ut_login/ut_login.cpp @@ -61,6 +61,29 @@ void CheckToken(const TString& token, const NKikimrScheme::TEvDescribeSchemeResu UNIT_ASSERT_VALUES_EQUAL(validateResult.User, expectedUsername); } +void TestIsAdmin(const TVector<TString>& admins, const TString& testUser, bool isAdmin) { + TTestBasicRuntime runtime; + if (!admins.empty()) { + runtime.AddAppDataInit([&admins](ui32, NKikimr::TAppData& appData){ + for (const auto& admin : admins) { + appData.AdministrationAllowedSIDs.emplace_back(admin); + } + }); + } + TTestEnv env(runtime); + ui64 txId = 100; + + const auto userHashes = MakeTestPasswordHashes("password1"); + CreateAlterLoginCreateUser(runtime, ++txId, "/MyRoot", testUser, userHashes.HashedPassword); + + const auto resultLogin = Login(runtime, testUser, NLoginProto::ESaslAuthMech::Plain, + NLoginProto::EHashType::ScramSha256, userHashes.ScramServerKey); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), ""); + auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); + CheckToken(resultLogin.token(), describe, testUser); + UNIT_ASSERT_VALUES_EQUAL(resultLogin.GetIsAdmin(), isAdmin); +} + } // namespace NSchemeShardUT_Private Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { @@ -1036,77 +1059,10 @@ Y_UNIT_TEST_SUITE(TSchemeShardLoginTest) { reboot(); loginUser(""); } -} - -Y_UNIT_TEST_SUITE(TSchemeShardLoginFinalize) { - - void TestSuccess(const TVector<TString>& admins, const TString& testUser, bool isAdmin) { - TTestBasicRuntime runtime; - if (!admins.empty()) { - runtime.AddAppDataInit([&admins](ui32, NKikimr::TAppData& appData){ - for (const auto& admin : admins) { - appData.AdministrationAllowedSIDs.emplace_back(admin); - } - }); - } - TTestEnv env(runtime); - ui64 txId = 100; - - const auto userHashes = MakeTestPasswordHashes("password1"); - CreateAlterLoginCreateUser(runtime, ++txId, "/MyRoot", testUser, userHashes.HashedPassword); - - const auto check = NLogin::TLoginProvider::TPasswordCheckResult{.Status = - NLogin::TLoginProvider::TPasswordCheckResult::EStatus::SUCCESS}; - const auto request = NLogin::TLoginProvider::TLoginUserRequest({.User = testUser}); - // public keys are filled after the first login - UNIT_ASSERT_VALUES_EQUAL(Login(runtime, testUser, NLoginProto::ESaslAuthMech::Plain, NLoginProto::EHashType::ScramSha256, - MakeTestPasswordHashes("wrong-password1").ScramServerKey).error(), "Invalid password"); - const auto resultLogin = LoginFinalize(runtime, request, check, "", false); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), ""); - auto describe = DescribePath(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); - CheckToken(resultLogin.token(), describe, testUser); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.GetIsAdmin(), isAdmin); - } - - Y_UNIT_TEST(NoPublicKeys) { - TTestBasicRuntime runtime; - TTestEnv env(runtime); - ui64 txId = 100; - - const auto user1Hashes = MakeTestPasswordHashes("password1"); - CreateAlterLoginCreateUser(runtime, ++txId, "/MyRoot", "user1", user1Hashes.HashedPassword); - - NLogin::TLoginProvider::TPasswordCheckResult check; - check.FillInvalidPassword(); - const auto request = NLogin::TLoginProvider::TLoginUserRequest({.User = "user1"}); - const auto resultLogin = LoginFinalize(runtime, request, check, "", false); - // public keys are filled after the first login - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "No key to generate token"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.token(), ""); - } - - Y_UNIT_TEST(InvalidPassword) { - TTestBasicRuntime runtime; - TTestEnv env(runtime); - ui64 txId = 100; - - const auto user1Hashes = MakeTestPasswordHashes("password1"); - CreateAlterLoginCreateUser(runtime, ++txId, "/MyRoot", "user1", user1Hashes.HashedPassword); - - NLogin::TLoginProvider::TPasswordCheckResult check; - check.FillInvalidPassword(); - const auto request = NLogin::TLoginProvider::TLoginUserRequest({.User = "user1"}); - // public keys are filled after the first login - UNIT_ASSERT_VALUES_EQUAL(Login(runtime, "user1", NLoginProto::ESaslAuthMech::Plain, NLoginProto::EHashType::ScramSha256, - user1Hashes.ScramServerKey).error(), ""); - const auto resultLogin = LoginFinalize(runtime, request, check, "", false); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.error(), "Invalid password"); - UNIT_ASSERT_VALUES_EQUAL(resultLogin.token(), ""); - } - Y_UNIT_TEST(Success) { - TestSuccess({}, "user1", true); - TestSuccess({"user-admin"}, "user1", false); - TestSuccess({"user1"}, "user1", true); + Y_UNIT_TEST(AdminLogin) { + TestIsAdmin( /* admins */ {}, /* testUser */ "user1", /* isAdmin */ true); + TestIsAdmin( /* admins */ {"user-admin"}, /* testUser */ "user1", /* isAdmin */ false); + TestIsAdmin( /* admins */ {"user1"}, /* testUser */ "user1", /* isAdmin */ true); } } diff --git a/ydb/core/tx/schemeshard/ya.make b/ydb/core/tx/schemeshard/ya.make index 78d45debc4a..2e22cd9a506 100644 --- a/ydb/core/tx/schemeshard/ya.make +++ b/ydb/core/tx/schemeshard/ya.make @@ -113,7 +113,6 @@ SRCS( schemeshard__local_index_migration.cpp schemeshard__local_index_migration.h schemeshard__login.cpp - schemeshard__login_finalize.cpp schemeshard__make_access_database_no_inheritable.cpp schemeshard__monitoring.cpp schemeshard__monitoring.h @@ -243,7 +242,6 @@ SRCS( schemeshard__unmark_restore_tables.cpp schemeshard__upgrade_access_database.cpp schemeshard__upgrade_schema.cpp - schemeshard__user_hashes_migration.cpp schemeshard_audit_log.cpp schemeshard_audit_log_fragment.cpp schemeshard_backup.cpp @@ -300,8 +298,6 @@ SRCS( schemeshard_import_scheme_query_executor.cpp schemeshard_info_types.cpp schemeshard_info_types.h - schemeshard_login_helper.cpp - schemeshard_login_helper.h schemeshard_path.cpp schemeshard_path.h schemeshard_path_describer.cpp diff --git a/ydb/library/login/cache/lru.cpp b/ydb/library/login/cache/lru.cpp deleted file mode 100644 index 7d9e17c52bf..00000000000 --- a/ydb/library/login/cache/lru.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "lru.h" - -namespace NLogin { - -TLruCache::TLruCache(std::size_t capacity) - : Capacity(capacity) -{ - Index.reserve(Capacity); -} - -TLruCache::TIterator TLruCache::Find(const TKey& key) { - const auto indexIt = Index.find(key); - if (indexIt == Index.end()) { - return Data.end(); - } - - Promote(indexIt->second); - return indexIt->second; -} - -std::pair<TLruCache::TIterator, bool> TLruCache::Insert(const TKey& key, bool value) { - const auto indexIt = Index.find(key); - if (indexIt != Index.end()) { - Promote(indexIt->second); - return std::make_pair(indexIt->second, false); - } - - if (Capacity == 0) { - return std::make_pair(Data.end(), false); - } - - while (IsOverflow()) { - Evict(); - } - - Data.push_front(std::make_pair(key, value)); - Index.emplace(key, Data.begin()); - return std::make_pair(Data.begin(), true); -} - -std::size_t TLruCache::Size() const { - return Index.size(); -} - -TLruCache::TIterator TLruCache::End() { - return Data.end(); -} - -void TLruCache::Clear() { - Data.clear(); - Index.clear(); -} - -bool TLruCache::IsOverflow() const { - return Index.size() == Capacity; -} - -void TLruCache::Promote(const TIterator it) { - Data.splice(Data.begin(), Data, it); -} - -void TLruCache::Evict() { - const auto item = Data.back(); - Data.pop_back(); - Index.erase(item.first); -} - -void TLruCache::Resize(size_t capacity) { - Capacity = capacity; - while (Index.size() > Capacity) { - Evict(); - } -} - -} // NLogin diff --git a/ydb/library/login/cache/lru.h b/ydb/library/login/cache/lru.h deleted file mode 100644 index b64ccdf5b69..00000000000 --- a/ydb/library/login/cache/lru.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <list> -#include <unordered_map> - -#include <util/generic/string.h> -#include <util/string/builder.h> -#include <util/str_stl.h> - -namespace NLogin { - -class TLruCache { -public: - struct TKey { - TString User; - TString Password; - TString Hash; - - bool operator == (const TKey& other) const { - return ((this->User == other.User) && (this->Password == other.Password) && (this->Hash == other.Hash)); - } - }; - - struct TKeyHash { - size_t operator() (const TKey& key) const { - return THash<TString>()(TStringBuilder() << key.User << key.Password << key.Hash); - } - }; - - using TItem = std::pair<const TKey, bool>; - using TDataContainer = std::list<TItem>; - using TIterator = TDataContainer::iterator; - using TIndexContainer = std::unordered_map<TKey, const TIterator, TKeyHash>; - - TLruCache(std::size_t capacity); - - TIterator Find(const TKey& key); - std::pair<TIterator, bool> Insert(const TKey& key, bool value); - std::size_t Size() const; - TIterator End(); - void Clear(); - void Resize(size_t capacity); - -private: - bool IsOverflow() const; - void Promote(const TIterator it); - void Evict(); - -private: - std::size_t Capacity = 0; - TDataContainer Data; - TIndexContainer Index; -}; - -} // NLogin diff --git a/ydb/library/login/cache/lru_ut.cpp b/ydb/library/login/cache/lru_ut.cpp deleted file mode 100644 index d3f550129dc..00000000000 --- a/ydb/library/login/cache/lru_ut.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include <library/cpp/testing/unittest/registar.h> -#include "lru.h" - -Y_UNIT_TEST_SUITE(TCacheTest) { - Y_UNIT_TEST(TestLruCache) { - NLogin::TLruCache cache(2); - const NLogin::TLruCache::TKey user1 = {.User = "user1", .Password = "pass1", .Hash = "12345"}; - const NLogin::TLruCache::TKey user2 = {.User = "user2", .Password = "pass2", .Hash = "67890"}; - UNIT_ASSERT_EQUAL(cache.Size(), 0); - { - const auto insertResult = cache.Insert(user1, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - { - const auto insertResult = cache.Insert(user2, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - { - const auto it = cache.Find(user1); - UNIT_ASSERT(it != cache.End()); - UNIT_ASSERT_EQUAL(it->second, true); - } - const NLogin::TLruCache::TKey user3 = {.User = "user3", .Password = "pass3", .Hash = "abcd"}; - // user2 must be evicted - { - const auto insertResult = cache.Insert(user3, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - { - const auto it = cache.Find(user2); - UNIT_ASSERT(it == cache.End()); - } - { - const auto it = cache.Find(user3); - UNIT_ASSERT(it != cache.End()); - UNIT_ASSERT_EQUAL(it->second, true); - } - const NLogin::TLruCache::TKey user4 = {.User = "user4", .Password = "pass4", .Hash = "fedcba"}; - // user1 must be evicted - { - const auto insertResult = cache.Insert(user4, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - { - const auto it = cache.Find(user1); - UNIT_ASSERT(it == cache.End()); - } - { - const auto it = cache.Find(user4); - UNIT_ASSERT(it != cache.End()); - UNIT_ASSERT_EQUAL(it->second, true); - } - cache.Clear(); - UNIT_ASSERT_EQUAL(cache.Size(), 0); - } - - Y_UNIT_TEST(TestLruCacheWithEmptyCapacity) { - NLogin::TLruCache cache(0); - const NLogin::TLruCache::TKey user1 = {.User = "user1", .Password = "pass1", .Hash = "12345"}; - const NLogin::TLruCache::TKey user2 = {.User = "user2", .Password = "pass2", .Hash = "67890"}; - UNIT_ASSERT_EQUAL(cache.Size(), 0); - { - const auto insertResult = cache.Insert(user1, true); - UNIT_ASSERT_EQUAL(insertResult.second, false); - UNIT_ASSERT(insertResult.first == cache.End()); - } - { - const auto insertResult = cache.Insert(user2, true); - UNIT_ASSERT_EQUAL(insertResult.second, false); - UNIT_ASSERT(insertResult.first == cache.End()); - } - } - - Y_UNIT_TEST(TestLruCacheWithSameUserAndPassword) { - NLogin::TLruCache cache(2); - const NLogin::TLruCache::TKey key1 = {.User = "user1", .Password = "pass1", .Hash = "12345"}; - const NLogin::TLruCache::TKey key2 = {.User = "user1", .Password = "pass1", .Hash = "67890"}; - UNIT_ASSERT_EQUAL(cache.Size(), 0); - { - const auto insertResult = cache.Insert(key1, false); // Bad password - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - { - const auto insertResult = cache.Insert(key2, true); // Good password - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - } - - Y_UNIT_TEST(TestLruCacheWithDifferentPasswords) { - NLogin::TLruCache cache(2); - const NLogin::TLruCache::TKey key1 = {.User = "user1", .Password = "pass1", .Hash = "12345"}; - const NLogin::TLruCache::TKey key2 = {.User = "user1", .Password = "pass2", .Hash = "12345"}; - UNIT_ASSERT_EQUAL(cache.Size(), 0); - { - const auto insertResult = cache.Insert(key1, false); // Bad password - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - { - const auto insertResult = cache.Insert(key2, true); // Good password - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - } - - Y_UNIT_TEST(TestLruCacheResize) { - NLogin::TLruCache cache(2); - const NLogin::TLruCache::TKey user1 = {.User = "user1", .Password = "pass1", .Hash = "12345"}; - const NLogin::TLruCache::TKey user2 = {.User = "user2", .Password = "pass2", .Hash = "67890"}; - UNIT_ASSERT_EQUAL(cache.Size(), 0); - { - const auto insertResult = cache.Insert(user1, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - { - const auto insertResult = cache.Insert(user2, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - const NLogin::TLruCache::TKey user3 = {.User = "user3", .Password = "pass3", .Hash = "abcdef"}; - { - const auto insertResult = cache.Insert(user3, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 2); - - // Resize - cache.Resize(5); - { - // return user1 to cache - const auto insertResult = cache.Insert(user1, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - const NLogin::TLruCache::TKey user4 = {.User = "user4", .Password = "pass4", .Hash = "abcde4"}; - { - const auto insertResult = cache.Insert(user4, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - const NLogin::TLruCache::TKey user5 = {.User = "user5", .Password = "pass5", .Hash = "abcde5"}; - { - const auto insertResult = cache.Insert(user5, true); - UNIT_ASSERT_EQUAL(insertResult.second, true); - UNIT_ASSERT(insertResult.first != cache.End()); - } - UNIT_ASSERT_EQUAL(cache.Size(), 5); - - // Resize - cache.Resize(3); - UNIT_ASSERT_EQUAL(cache.Size(), 3); - { - const auto it = cache.Find(user3); - UNIT_ASSERT(it == cache.End()); - } - { - const auto it = cache.Find(user2); - UNIT_ASSERT(it == cache.End()); - } - } -} diff --git a/ydb/library/login/cache/ut/ya.make b/ydb/library/login/cache/ut/ya.make deleted file mode 100644 index c36c19ff5b6..00000000000 --- a/ydb/library/login/cache/ut/ya.make +++ /dev/null @@ -1,9 +0,0 @@ -UNITTEST_FOR(ydb/library/login/cache) - -PEERDIR() - -SRCS( - lru_ut.cpp -) - -END() diff --git a/ydb/library/login/cache/ya.make b/ydb/library/login/cache/ya.make deleted file mode 100644 index 65ded9a4884..00000000000 --- a/ydb/library/login/cache/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -LIBRARY() - -PEERDIR() - -SRCS( - lru.cpp -) - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/ydb/library/login/hashes_checker/hashes_checker.cpp b/ydb/library/login/hashes_checker/hashes_checker.cpp index 12bccaed676..23586018f90 100644 --- a/ydb/library/login/hashes_checker/hashes_checker.cpp +++ b/ydb/library/login/hashes_checker/hashes_checker.cpp @@ -54,39 +54,6 @@ TArgonSecret ParseArgonHash(const TStringBuf argonHash) { return { std::move(salt), std::move(hash) }; } -TMaybe<TString> ArgonHashToNewFormat(const TStringBuf oldArgonHash) { - NJson::TJsonValue json; - if (!NJson::ReadJsonTree(oldArgonHash, &json)) { - return Nothing(); - } - - if (!json.Has("type") || !json.Has("salt") || !json.Has("hash") || json["type"] != "argon2id") { - return Nothing(); - } - - return json["salt"].GetString() + "$" + json["hash"].GetString(); -} - -TString HashedPasswordFromNewArgonHashFormat(const TString& argonHash) { - NJson::TJsonValue hashes; - hashes["argon2id"] = argonHash; - hashes["version"] = HASHES_JSON_SCHEMA_VERSION; - return Base64Encode(NJson::WriteJson(hashes, false)); -} - -TMaybe<TString> ArgonHashToOldFormat(const TStringBuf newArgonHash) { - auto argonSecret = ParseArgonHash(newArgonHash); - if (argonSecret.Salt.empty() || argonSecret.Hash.empty()) { - return Nothing(); - } - - NJson::TJsonValue json; - json["type"] = "argon2id"; - json["salt"] = std::move(argonSecret.Salt); - json["hash"] = std::move(argonSecret.Hash); - return NJson::WriteJson(json, false); -} - bool IsOldFormatHash(const TString& hash) { return THashesChecker::OldFormatCheck(hash).Success; } diff --git a/ydb/library/login/hashes_checker/hashes_checker.h b/ydb/library/login/hashes_checker/hashes_checker.h index e61774fc7da..b7031c7b305 100644 --- a/ydb/library/login/hashes_checker/hashes_checker.h +++ b/ydb/library/login/hashes_checker/hashes_checker.h @@ -37,9 +37,6 @@ struct TScramSecret { TString ServerKey; }; -TMaybe<TString> ArgonHashToNewFormat(const TStringBuf oldArgonHash); -TString HashedPasswordFromNewArgonHashFormat(const TString& argonHash); -TMaybe<TString> ArgonHashToOldFormat(const TStringBuf newArgonHash); bool IsOldFormatHash(const TString& hash); TString ConvertOldFormatHash(const TString& oldFormatHash); diff --git a/ydb/library/login/login.cpp b/ydb/library/login/login.cpp index 4be301bcb73..39e28404904 100644 --- a/ydb/library/login/login.cpp +++ b/ydb/library/login/login.cpp @@ -34,19 +34,10 @@ namespace NLogin { struct TLoginProvider::TImpl { public: - TLruCache SuccessPasswordsCache; - TLruCache WrongPasswordsCache; - std::function<bool()> IsCacheUsed = [] () {return false;}; static const THolder<const NArgonish::IArgon2Base> ArgonHasher; public: - TImpl() : TImpl([] () {return false;}, {}) {} - - TImpl(const std::function<bool()>& isCacheUsed, const TLoginProvider::TCacheSettings& cacheSettings) - : SuccessPasswordsCache(cacheSettings.SuccessPasswordsCacheCapacity) - , WrongPasswordsCache(cacheSettings.WrongPasswordsCacheCapacity) - , IsCacheUsed(isCacheUsed) - {} + TImpl() = default; void GenerateKeyPair(TString& publicKey, TString& privateKey) const ; TString GenerateArgonHash(const TString& password) const; @@ -55,14 +46,6 @@ public: static bool SaslPlainVerifyScramHash(const TString& serverKeyToVerify, const TString& storedHashValues); static bool SaslScramVerifyHash(const TString& hashName, const TString& clientProof, const TString& authMessage, const TString& storedHashValues); static TString SaslScramComputeServerSignature(const TString& hashName, const TString& authMessage, const TString& storedHashValues); - bool VerifyHashValues(const TString& password, const TString& hash); - bool NeedVerifyHash(const TLruCache::TKey& key, TPasswordCheckResult* checkResult); - void UpdateCache(const TLruCache::TKey& key, const bool isSuccessVerifying); - - void UpdateCacheSettings(const TLoginProvider::TCacheSettings& cacheSettings); - -private: - void ClearCache(); }; const THolder<const NArgonish::IArgon2Base> TLoginProvider::TImpl::ArgonHasher = Default<NArgonish::TArgon2Factory>().Create( @@ -79,14 +62,12 @@ TLoginProvider::TLoginProvider() {} TLoginProvider::TLoginProvider(const TAccountLockout::TInitializer& accountLockoutInitializer) - : TLoginProvider(TPasswordComplexity(), accountLockoutInitializer, [] () {return false;}, {}) + : TLoginProvider(TPasswordComplexity(), accountLockoutInitializer) {} TLoginProvider::TLoginProvider(const TPasswordComplexity& passwordComplexity, - const TAccountLockout::TInitializer& accountLockoutInitializer, - const std::function<bool()>& isCacheUsed, - const TCacheSettings& cacheSettings) - : Impl(new TImpl(isCacheUsed, cacheSettings)) + const TAccountLockout::TInitializer& accountLockoutInitializer) + : Impl(new TImpl()) , PasswordChecker(passwordComplexity) , AccountLockout(accountLockoutInitializer) {} @@ -133,19 +114,11 @@ bool TLoginProvider::CheckHashes(const TString& hashedPassword, TString& error) return true; } -bool TLoginProvider::CheckPasswordOrArgonHash(bool IsHashedPassword, const TString& user, const TString& password, TString& error) const { - if (IsHashedPassword) { - auto hashCheckResult = THashesChecker::OldFormatCheck(password); - if (!hashCheckResult.Success) { - error = hashCheckResult.Error; - return false; - } - } else { - auto passwordCheckResult = PasswordChecker.Check(user, password); - if (!passwordCheckResult.Success) { - error = passwordCheckResult.Error; - return false; - } +bool TLoginProvider::CheckPassword(const TString& user, const TString& password, TString& error) const { + auto passwordCheckResult = PasswordChecker.Check(user, password); + if (!passwordCheckResult.Success) { + error = passwordCheckResult.Error; + return false; } return true; @@ -163,10 +136,10 @@ TLoginProvider::TBasicResponse TLoginProvider::CreateUser(const TCreateUserReque if (!CheckHashes(request.HashedPassword, response.Error)) { return response; } - } - - if (!CheckPasswordOrArgonHash(request.IsHashedPassword, request.User, request.Password, response.Error)) { - return response; + } else { + if (!CheckPassword(request.User, request.Password, response.Error)) { + return response; + } } auto itUserCreate = Sids.emplace(request.User, TSidRecord{.Type = NLoginProto::ESidType::USER}); @@ -183,11 +156,10 @@ TLoginProvider::TBasicResponse TLoginProvider::CreateUser(const TCreateUserReque user.Name = request.User; user.CreatedAt = std::chrono::system_clock::now(); user.IsEnabled = request.CanLogin; - user.ArgonHash = request.IsHashedPassword ? request.Password : Impl->GenerateArgonHash(request.Password); if (request.HashedPassword) { user.PasswordHashes = request.HashedPassword; } else { - user.PasswordHashes = HashedPasswordFromNewArgonHashFormat(*ArgonHashToNewFormat(user.ArgonHash)); + user.PasswordHashes = Impl->GenerateArgonHash(request.Password); } user.FillHashStorage(); @@ -222,23 +194,17 @@ TLoginProvider::TBasicResponse TLoginProvider::ModifyUser(const TModifyUserReque if (!CheckHashes(*request.HashedPassword, response.Error)) { return response; } - } - - if (request.Password.has_value()) { - if (!CheckPasswordOrArgonHash(request.IsHashedPassword, request.User, request.Password.value(), response.Error)) { + } else if (request.Password.has_value()) { + if (!CheckPassword(request.User, request.Password.value(), response.Error)) { return response; } } - if (request.Password.has_value()) { - user.ArgonHash = request.IsHashedPassword ? request.Password.value() : Impl->GenerateArgonHash(request.Password.value()); - } - if (request.HashedPassword.has_value()) { user.PasswordHashes = request.HashedPassword.value(); user.FillHashStorage(); } else if (request.Password.has_value()) { - user.PasswordHashes = HashedPasswordFromNewArgonHashFormat(*ArgonHashToNewFormat(user.ArgonHash)); + user.PasswordHashes = Impl->GenerateArgonHash(request.Password.value()); user.FillHashStorage(); } @@ -555,29 +521,24 @@ bool TLoginProvider::NeedVerifyHash(const TLoginUserRequest& request, TPasswordC return false; } - if (request.HashToValidate.has_value()) { - const auto& hashToValidate = *request.HashToValidate; - switch (hashToValidate.AuthMech) { - case NLoginProto::ESaslAuthMech::Plain: - case NLoginProto::ESaslAuthMech::Scram: { - auto itHashRecord = sid->HashStorage.find(hashToValidate.HashType); - if (itHashRecord == sid->HashStorage.end()) { - checkResult->FillInvalidHashType(); - return false; - } - - *hashValues = itHashRecord->second.HashValues; - return true; - } - default: { - checkResult->FillUnsupportedSaslMech(); + Y_ENSURE(request.HashToValidate.has_value()); + const auto& hashToValidate = *request.HashToValidate; + switch (hashToValidate.AuthMech) { + case NLoginProto::ESaslAuthMech::Plain: + case NLoginProto::ESaslAuthMech::Scram: { + auto itHashRecord = sid->HashStorage.find(hashToValidate.HashType); + if (itHashRecord == sid->HashStorage.end()) { + checkResult->FillInvalidHashType(); return false; } - } - } else if (request.Password.has_value()) { - *hashValues = sid->ArgonHash; - return Impl->NeedVerifyHash({.User = request.User, .Password = *request.Password, .Hash = sid->ArgonHash}, checkResult); + *hashValues = itHashRecord->second.HashValues; + return true; + } + default: { + checkResult->FillUnsupportedSaslMech(); + return false; + } } } @@ -611,7 +572,7 @@ void TLoginProvider::VerifyHashValues(const TLoginUserRequest& request, TPasswor return; } } - }; + } case NLoginProto::ESaslAuthMech::Scram: { const auto& hashTypeDescr = HashesRegistry.HashTypesMap.at(hashToValidate.HashType); if (!TImpl::SaslScramVerifyHash(hashTypeDescr.Name, hashToValidate.Hash, hashToValidate.AuthMessage, hashValues)) { @@ -629,14 +590,6 @@ void TLoginProvider::VerifyHashValues(const TLoginUserRequest& request, TPasswor } } -bool TLoginProvider::VerifyArgonHash(const TLoginUserRequest& request, const TString& passwordHash) { - return TImpl::VerifyArgonHash(*request.Password, passwordHash); -} - -void TLoginProvider::UpdateCache(const TLoginUserRequest& request, const TString& passwordHash, const bool isSuccessVerifying) { - Impl->UpdateCache({.User = request.User, .Password = *request.Password, .Hash = passwordHash}, isSuccessVerifying); -} - bool TLoginProvider::FillUnavailableKey(TPasswordCheckResult* checkResult) const { if (Keys.empty() || Keys.back().PrivateKey.empty()) { checkResult->FillUnavailableKey(); @@ -750,15 +703,8 @@ TLoginProvider::TLoginUserResponse TLoginProvider::LoginUser(const TLoginUserReq TPasswordCheckResult checkResult; TString hashValues; if (NeedVerifyHash(request, &checkResult, &hashValues)) { - if (request.HashToValidate.has_value()) { - VerifyHashValues(request, &checkResult, hashValues); - } else if (request.Password.has_value()) { // for backward compatibility - const auto isSuccessVerifying = VerifyArgonHash(request, hashValues); - UpdateCache(request, hashValues, isSuccessVerifying); - if (!isSuccessVerifying) { - checkResult.FillInvalidPassword(); - } - } + Y_ENSURE(request.HashToValidate.has_value()); + VerifyHashValues(request, &checkResult, hashValues); } return LoginUser(request, checkResult); @@ -964,43 +910,28 @@ void TLoginProvider::TImpl::GenerateKeyPair(TString& publicKey, TString& private } TString TLoginProvider::TImpl::GenerateArgonHash(const TString& password) const { - TString hashType = "argon2id"; + const TString hashType = "argon2id"; const auto& hashDescription = HashesRegistry.HashNamesMap.at(hashType); - char salt[hashDescription.SaltSize]; - char hash[hashDescription.HashSize]; - RAND_bytes(reinterpret_cast<unsigned char*>(salt), hashDescription.SaltSize); + std::string salt; + salt.resize(hashDescription.SaltSize); + std::string hash; + hash.resize(hashDescription.HashSize); + RAND_bytes(reinterpret_cast<unsigned char*>(salt.data()), salt.size()); ArgonHasher->Hash( reinterpret_cast<const ui8*>(password.data()), password.size(), - reinterpret_cast<ui8*>(salt), - hashDescription.SaltSize, - reinterpret_cast<ui8*>(hash), - hashDescription.HashSize); - NJson::TJsonValue json; - json["type"] = std::move(hashType); - json["salt"] = Base64Encode(TStringBuf(salt, hashDescription.SaltSize)); - json["hash"] = Base64Encode(TStringBuf(hash, hashDescription.HashSize)); - return NJson::WriteJson(json, false); -} - -bool TLoginProvider::TImpl::VerifyArgonHash(const TString& password, const TString& passwordHash) { - NJson::TJsonValue json; - if (!NJson::ReadJsonTree(passwordHash, &json)) { - return false; - } - TString type = json["type"].GetStringRobust(); - if (type != "argon2id") { - return false; - } - TString salt = Base64Decode(json["salt"].GetStringRobust()); - TString hash = Base64Decode(json["hash"].GetStringRobust()); - return ArgonHasher->Verify( - reinterpret_cast<const ui8*>(password.data()), - password.size(), - reinterpret_cast<const ui8*>(salt.data()), + reinterpret_cast<ui8*>(salt.data()), salt.size(), - reinterpret_cast<const ui8*>(hash.data()), + reinterpret_cast<ui8*>(hash.data()), hash.size()); + + std::stringstream secret; + secret << Base64Encode(salt) << '$' << Base64Encode(hash); + + NJson::TJsonValue hashes; + hashes[hashType] = secret.str(); + hashes["version"] = HASHES_JSON_SCHEMA_VERSION; + return Base64Encode(NJson::WriteJson(hashes, false)); } bool TLoginProvider::TImpl::SaslPlainVerifyArgonHash(const TString& hashToVerify, const TString& storedHashValue) { @@ -1036,50 +967,6 @@ TString TLoginProvider::TImpl::SaslScramComputeServerSignature(const TString& ha return Base64Encode(serverSignature); } -bool TLoginProvider::TImpl::NeedVerifyHash(const TLruCache::TKey& key, TPasswordCheckResult* checkResult) { - Y_ENSURE(checkResult); - - if (!IsCacheUsed()) { - ClearCache(); - return true; - } - - if (SuccessPasswordsCache.Find(key) != SuccessPasswordsCache.End()) { - checkResult->Status = TLoginUserResponse::EStatus::SUCCESS; - return false; - } - - if (WrongPasswordsCache.Find(key) != WrongPasswordsCache.End()) { - checkResult->FillInvalidPassword(); - return false; - } - - return true; -} - -void TLoginProvider::TImpl::UpdateCache(const TLruCache::TKey& key, const bool isSuccessVerifying) { - if (isSuccessVerifying) { - SuccessPasswordsCache.Insert(key, true); - } else { - WrongPasswordsCache.Insert(key, false); - } - -} - -void TLoginProvider::TImpl::UpdateCacheSettings(const TCacheSettings& cacheSettings) { - SuccessPasswordsCache.Resize(cacheSettings.SuccessPasswordsCacheCapacity); - WrongPasswordsCache.Resize(cacheSettings.WrongPasswordsCacheCapacity); -} - -void TLoginProvider::TImpl::ClearCache() { - if (SuccessPasswordsCache.Size() > 0) { - SuccessPasswordsCache.Clear(); - } - if (WrongPasswordsCache.Size() > 0) { - WrongPasswordsCache.Clear(); - } -} - NLoginProto::TSecurityState TLoginProvider::GetSecurityState() const { NLoginProto::TSecurityState state; state.SetAudience(Audience); @@ -1145,14 +1032,8 @@ void TLoginProvider::UpdateSecurityState(const NLoginProto::TSecurityState& stat TSidRecord& sid = Sids[pbSid.GetName()]; sid.Type = pbSid.GetType(); sid.Name = pbSid.GetName(); - sid.ArgonHash = pbSid.GetArgonHash(); if (pbSid.GetPasswordHashes()) { sid.PasswordHashes = pbSid.GetPasswordHashes(); - } else if (pbSid.GetArgonHash()) { - // ignore old hash format because we can't parse it - if (const auto argonHashInNewFormat = ArgonHashToNewFormat(pbSid.GetArgonHash())) { - sid.PasswordHashes = HashedPasswordFromNewArgonHashFormat(*argonHashInNewFormat); - } } sid.FillHashStorage(); @@ -1189,8 +1070,4 @@ void TLoginProvider::UpdateAccountLockout(const TAccountLockout::TInitializer& a AccountLockout.Update(accountLockoutInitializer); } -void TLoginProvider::UpdateCacheSettings(const TCacheSettings& settings) { - Impl->UpdateCacheSettings(settings); -} - } diff --git a/ydb/library/login/login.h b/ydb/library/login/login.h index 8611de5eb10..6baa5d03367 100644 --- a/ydb/library/login/login.h +++ b/ydb/library/login/login.h @@ -6,7 +6,6 @@ #include <deque> #include <util/generic/string.h> #include <ydb/library/login/account_lockout/account_lockout.h> -#include <ydb/library/login/cache/lru.h> #include <ydb/library/login/hashes_checker/hash_types.h> #include <ydb/library/login/protos/login.pb.h> #include <ydb/library/login/password_checker/password_checker.h> @@ -26,9 +25,6 @@ public: static constexpr const char* EXTERNAL_AUTH_CLAIM_NAME = "external_authentication"; static constexpr auto MAX_TOKEN_EXPIRE_TIME = std::chrono::hours(12); - static constexpr size_t SUCCESS_PASSWORDS_CACHE_CAPACITY = 20; - static constexpr size_t WRONG_PASSWORDS_CACHE_CAPACITY = 20; - struct TBasicRequest {}; struct TBasicResponse { @@ -67,7 +63,6 @@ public: }; TString User; - std::optional<TString> Password; std::optional<THashToValidate> HashToValidate; std::optional<TString> ExternalAuth; TOptions Options; @@ -138,7 +133,6 @@ public: TString User; TString Password; TString HashedPassword; - bool IsHashedPassword = false; bool CanLogin = true; }; @@ -146,7 +140,6 @@ public: TString User; std::optional<TString> Password; std::optional<TString> HashedPassword; - bool IsHashedPassword = false; std::optional<bool> CanLogin; }; @@ -210,7 +203,6 @@ public: ESidType::SidType Type = ESidType::UNKNOWN; TString Name; - TString ArgonHash; TString PasswordHashes; THashMap<NLoginProto::EHashType::HashType, THashRecord> HashStorage; @@ -224,11 +216,6 @@ public: void FillHashStorage(); }; - struct TCacheSettings { - size_t SuccessPasswordsCacheCapacity = SUCCESS_PASSWORDS_CACHE_CAPACITY; - size_t WrongPasswordsCacheCapacity = WRONG_PASSWORDS_CACHE_CAPACITY; - }; - // our current audience (database name) TString Audience; @@ -251,11 +238,8 @@ public: // Login TLoginUserResponse LoginUser(const TLoginUserRequest& request); - // The next four methods are used (all together combined) when it's needed to separate hash verification which is quite cpu-intensive bool NeedVerifyHash(const TLoginUserRequest& request, TPasswordCheckResult* checkResult, TString* hashValues); void VerifyHashValues(const TLoginUserRequest& request, TPasswordCheckResult* checkResult, const TString& hashValues); - static bool VerifyArgonHash(const TLoginUserRequest& request, const TString& passwordHash); // it's made static to be thread-safe - void UpdateCache(const TLoginUserRequest& request, const TString& passwordHash, const bool isSuccessVerifying); TLoginProvider::TLoginUserResponse LoginUser(const TLoginUserRequest& request, const TPasswordCheckResult& checkResult); TValidateTokenResponse ValidateToken(const TValidateTokenRequest& request); @@ -275,14 +259,11 @@ public: void UpdatePasswordCheckParameters(const TPasswordComplexity& passwordComplexity); const TPasswordComplexity& GetPasswordCheckParameters() const; void UpdateAccountLockout(const TAccountLockout::TInitializer& accountLockoutInitializer); - void UpdateCacheSettings(const TCacheSettings& settings); TLoginProvider(); TLoginProvider(const TAccountLockout::TInitializer& accountLockoutInitializer); TLoginProvider(const TPasswordComplexity& passwordComplexity, - const TAccountLockout::TInitializer& accountLockoutInitializer, - const std::function<bool()>& isCacheUsed, - const TCacheSettings& cacheSettings); + const TAccountLockout::TInitializer& accountLockoutInitializer); ~TLoginProvider(); std::vector<TString> GetGroupsMembership(const TString& member) const; @@ -305,7 +286,7 @@ private: bool ShouldResetFailedAttemptCount(const TSidRecord& sid) const; bool ShouldUnlockAccount(const TSidRecord& sid) const; bool CheckHashes(const TString& hashedPassword, TString& error) const; - bool CheckPasswordOrArgonHash(bool IsHashedPassword, const TString& user, const TString& password, TString& error) const; + bool CheckPassword(const TString& user, const TString& password, TString& error) const; TSidRecord* GetUserSid(const TString& user); bool FillUnavailableKey(TPasswordCheckResult* checkResult) const; bool FillInvalidUser(const TSidRecord* sid, TPasswordCheckResult* checkResult) const; diff --git a/ydb/library/login/login_ut.cpp b/ydb/library/login/login_ut.cpp index 47872b2113b..b1ff60804c0 100644 --- a/ydb/library/login/login_ut.cpp +++ b/ydb/library/login/login_ut.cpp @@ -12,49 +12,53 @@ using namespace NLogin; Y_UNIT_TEST_SUITE(Login) { void none() {} - Y_UNIT_TEST(TestSuccessfulLogin1) { - TLoginProvider provider; - provider.Audience = "test_audience1"; - provider.RotateKeys(); - TLoginProvider::TCreateUserRequest request1; - request1.User = "user1"; - request1.Password = "password1"; - auto response1 = provider.CreateUser(request1); - UNIT_ASSERT(!response1.Error); - TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.Password = request1.Password; - auto response2 = provider.LoginUser(request2); - UNIT_ASSERT_VALUES_EQUAL(response2.Error, ""); - TLoginProvider::TValidateTokenRequest request3; - request3.Token = response2.Token; - auto response3 = provider.ValidateToken(request3); - UNIT_ASSERT_VALUES_EQUAL(response3.Error, ""); - UNIT_ASSERT(response3.User == request1.User); + // Precomputed argon2id + SCRAM-SHA-256 hashes from scram_ut.cpp + // Password: "password1" + // Salt (base64): "s0QSrrFVkMTh3k2TTk860A==" + // Iterations: 4096 + // StoredKey (base64): "LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=" + // ServerKey (base64): "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" + static const TString PASSWORD1_HASHES = R"({ + "version": 1, + "argon2id": "flbr3YnA9kG67qegwDTaYg==$wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo=", + "scram-sha-256": "4096:s0QSrrFVkMTh3k2TTk860A==$LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=:eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" + })"; + + // The ServerKey of the SCRAM-SHA-256 hash above + static const TString PASSWORD1_SCRAM_SERVER_KEY = "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc="; + + // The Hash of the Argon2Id hash above + static const TString PASSWORD1_ARGON_HASH = "wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo="; + + static const TString AUTH_MESSAGE = "n=user,r=clientnonce,r=clientservernonce,s=s0QSrrFVkMTh3k2TTk860A==,i=4096,c=biws,r=clientservernonce"; + + // Precomputed ClientProof of the SCRAM-SHA-256 hash above and AUTH_MESSAGE + static const TString CLIENT_PROOF = "AJgthTHWf0jz/bMHwrWDOHk9SQPpPpvGx937mEzFnCQ="; + + // Precomputed ServerSignature of the SCRAM-SHA-256 hash above and AUTH_MESSAGE + static const TString SERVER_SIGNATURE = "RBEDP7XfP9zTpxx+++HZSiw7kB7MDtfZ5mlBcMSxRQY="; + + TLoginProvider::TLoginUserRequest MakeScramPlainLoginRequest(const TString& user, const TString& scramServerKey) { + TLoginProvider::TLoginUserRequest request; + request.User = user; + + TLoginProvider::THashToValidate hashToValidate; + hashToValidate.AuthMech = NLoginProto::ESaslAuthMech::Plain; + hashToValidate.HashType = NLoginProto::EHashType::ScramSha256; + hashToValidate.Hash = scramServerKey; + request.HashToValidate = hashToValidate; + + return request; } - Y_UNIT_TEST(TestSuccessfulLogin2) { + Y_UNIT_TEST(TestSuccessfulLogin1) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); - // Using precomputed SCRAM-SHA-256 values from scram_ut.cpp - // Password: "password1" - // Salt (base64): "s0QSrrFVkMTh3k2TTk860A==" - // Iterations: 4096 - // StoredKey (base64): "LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=" - // ServerKey (base64): "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" - - TString hashes = R"( - { - "version": 1, - "argon2id": "flbr3YnA9kG67qegwDTaYg==$wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo=", - "scram-sha-256": "4096:s0QSrrFVkMTh3k2TTk860A==$LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=:eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" - } - )"; TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.HashedPassword = Base64Encode(hashes); + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); @@ -62,7 +66,7 @@ Y_UNIT_TEST_SUITE(Login) { TLoginProvider::THashToValidate hashToValidate1; hashToValidate1.AuthMech = NLoginProto::ESaslAuthMech::Plain; hashToValidate1.HashType = NLoginProto::EHashType::Argon; - hashToValidate1.Hash = "wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo="; + hashToValidate1.Hash = PASSWORD1_ARGON_HASH; TLoginProvider::TLoginUserRequest request2; request2.User = request1.User; request2.HashToValidate = hashToValidate1; @@ -70,38 +74,27 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(response2.Error, ""); // Test SCRAM-SHA-256 authentication with Plain mechanism (ServerKey validation) - TLoginProvider::THashToValidate hashToValidate2; - hashToValidate2.AuthMech = NLoginProto::ESaslAuthMech::Plain; - hashToValidate2.HashType = NLoginProto::EHashType::ScramSha256; - hashToValidate2.Hash = "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc="; TLoginProvider::TLoginUserRequest request3; - request3.User = request1.User; - request3.HashToValidate = hashToValidate2; + request3 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); auto response3 = provider.LoginUser(request3); UNIT_ASSERT_VALUES_EQUAL(response3.Error, ""); - // Test SCRAM-SHA-256 authentication with SCRAM mechanism using precomputed ClientProof - TString authMessage = "n=user,r=clientnonce,r=clientservernonce,s=s0QSrrFVkMTh3k2TTk860A==,i=4096,c=biws,r=clientservernonce"; - TString clientProof = "AJgthTHWf0jz/bMHwrWDOHk9SQPpPpvGx937mEzFnCQ="; - - TLoginProvider::THashToValidate hashToValidate3; - hashToValidate3.AuthMech = NLoginProto::ESaslAuthMech::Scram; - hashToValidate3.HashType = NLoginProto::EHashType::ScramSha256; - hashToValidate3.Hash = clientProof; - hashToValidate3.AuthMessage = authMessage; - + // Test SCRAM-SHA-256 authentication with SCRAM mechanism (ClientProof validation) + TLoginProvider::THashToValidate hashToValidate2; + hashToValidate2.AuthMech = NLoginProto::ESaslAuthMech::Scram; + hashToValidate2.HashType = NLoginProto::EHashType::ScramSha256; + hashToValidate2.Hash = CLIENT_PROOF; + hashToValidate2.AuthMessage = AUTH_MESSAGE; TLoginProvider::TLoginUserRequest request4; request4.User = request1.User; - request4.HashToValidate = hashToValidate3; + request4.HashToValidate = hashToValidate2; auto response4 = provider.LoginUser(request4); UNIT_ASSERT_VALUES_EQUAL(response4.Error, ""); - - // Verify server signature is also correct (from scram_ut.cpp) - TString expectedServerSignature = "RBEDP7XfP9zTpxx+++HZSiw7kB7MDtfZ5mlBcMSxRQY="; - UNIT_ASSERT_VALUES_EQUAL(response4.ServerSignature.value(), expectedServerSignature); + // Verify server signature is also correct + UNIT_ASSERT_VALUES_EQUAL(response4.ServerSignature.value(), SERVER_SIGNATURE); } - Y_UNIT_TEST(TestSuccessfulLogin3) { + Y_UNIT_TEST(TestSuccessfulLogin2) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); @@ -116,6 +109,7 @@ Y_UNIT_TEST_SUITE(Login) { request1.HashedPassword = Base64Encode(hashes); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); + TLoginProvider::THashToValidate hashToValidate; hashToValidate.AuthMech = NLoginProto::ESaslAuthMech::Plain; hashToValidate.HashType = NLoginProto::EHashType::Argon; @@ -203,75 +197,48 @@ Y_UNIT_TEST_SUITE(Login) { } } - Y_UNIT_TEST(TestWrongPassword1) { - TLoginProvider provider; - provider.RotateKeys(); - TLoginProvider::TCreateUserRequest request1; - request1.User = "user1"; - request1.Password = "password1"; - auto response1 = provider.CreateUser(request1); - UNIT_ASSERT(!response1.Error); - TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.Password = "wrong password"; - auto response2 = provider.LoginUser(request2); - UNIT_ASSERT(response2.Error == "Invalid password"); - } - - Y_UNIT_TEST(TestWrongPassword2) { + Y_UNIT_TEST(TestWrongPassword) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); - TString hashes1 = R"( - { - "version": 1, - "argon2id": "flbr3YnA9kG67qegwDTaYg==$wsTryyX+vdkLiZ4PfYabvgVwHf8tbxBVVtDluhiz3fo=", - "scram-sha-256": "4096:s0QSrrFVkMTh3k2TTk860A==$LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo=:eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc=" - } - )"; TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.HashedPassword = Base64Encode(hashes1); + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); - // Test with wrong Argon hash (using ServerKey instead of Argon hash) - TLoginProvider::THashToValidate hashToValidate; - hashToValidate.AuthMech = NLoginProto::ESaslAuthMech::Plain; - hashToValidate.HashType = NLoginProto::EHashType::Argon; - hashToValidate.Hash = "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc="; + // Test with wrong Argon hash (using SCRAM-SHA-256 ServerKey instead of Argon hash) + TLoginProvider::THashToValidate hashToValidate1; + hashToValidate1.AuthMech = NLoginProto::ESaslAuthMech::Plain; + hashToValidate1.HashType = NLoginProto::EHashType::Argon; + hashToValidate1.Hash = PASSWORD1_SCRAM_SERVER_KEY; TLoginProvider::TLoginUserRequest request2; request2.User = request1.User; - request2.HashToValidate = hashToValidate; + request2.HashToValidate = hashToValidate1; auto response2 = provider.LoginUser(request2); UNIT_ASSERT(response2.Error == "Invalid password"); // Test Plain authentication with wrong SCRAM-SHA-256 hash (using StoredKey instead of ServerKey) - TLoginProvider::THashToValidate hashToValidate2; - hashToValidate2.AuthMech = NLoginProto::ESaslAuthMech::Plain; - hashToValidate2.HashType = NLoginProto::EHashType::ScramSha256; - hashToValidate2.Hash = "LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo="; + const TString wrongServerKey = "LmCubRpIYV1zHMLucTtu7XjhB+PgWwH8ABCYGyVF1mo="; + TLoginProvider::TLoginUserRequest request3; - request3.User = request1.User; - request3.HashToValidate = hashToValidate2; + request3 = MakeScramPlainLoginRequest(request1.User, wrongServerKey); auto response3 = provider.LoginUser(request3); UNIT_ASSERT(response3.Error == "Invalid password"); // Test SCRAM authentication with wrong ClientProof // Using ClientProof for "password2" instead of "password1" - TString authMessage = "n=user,r=clientnonce,r=clientservernonce,s=s0QSrrFVkMTh3k2TTk860A==,i=4096,c=biws,r=clientservernonce"; - TString wrongClientProof = "onCT9KAMiTb4vvJzBQM0w1nXLW3hJiZIJuc9Jz71pV8="; - - TLoginProvider::THashToValidate hashToValidate3; - hashToValidate3.AuthMech = NLoginProto::ESaslAuthMech::Scram; - hashToValidate3.HashType = NLoginProto::EHashType::ScramSha256; - hashToValidate3.Hash = wrongClientProof; - hashToValidate3.AuthMessage = authMessage; + const TString wrongClientProof = "onCT9KAMiTb4vvJzBQM0w1nXLW3hJiZIJuc9Jz71pV8="; + TLoginProvider::THashToValidate hashToValidate2; + hashToValidate2.AuthMech = NLoginProto::ESaslAuthMech::Scram; + hashToValidate2.HashType = NLoginProto::EHashType::ScramSha256; + hashToValidate2.Hash = wrongClientProof; + hashToValidate2.AuthMessage = AUTH_MESSAGE; TLoginProvider::TLoginUserRequest request4; request4.User = request1.User; - request4.HashToValidate = hashToValidate3; + request4.HashToValidate = hashToValidate2; auto response4 = provider.LoginUser(request4); UNIT_ASSERT(response4.Error == "Invalid password"); } @@ -280,6 +247,7 @@ Y_UNIT_TEST_SUITE(Login) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); + TString hashes1 = R"( { "version": 1, @@ -291,39 +259,36 @@ Y_UNIT_TEST_SUITE(Login) { request1.HashedPassword = Base64Encode(hashes1); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); - TLoginProvider::THashToValidate hashToValidate; - hashToValidate.AuthMech = NLoginProto::ESaslAuthMech::Plain; - hashToValidate.HashType = NLoginProto::EHashType::ScramSha256; - hashToValidate.Hash = "eUrie0C98tEFgygSOtom/fwPmgnMxeq53l7YTFfYncc="; + TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.HashToValidate = hashToValidate; + request2 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); auto response2 = provider.LoginUser(request2); UNIT_ASSERT_VALUES_EQUAL(response2.Error, "Invalid hash type"); + TLoginProvider::THashToValidate hashToValidate; hashToValidate.AuthMech = NLoginProto::ESaslAuthMech::Scram; hashToValidate.HashType = NLoginProto::EHashType::ScramSha256; hashToValidate.Hash = "clientproof"; hashToValidate.AuthMessage = "n=user1,r=nonce,r=nonceserver,c=biws,r=nonceserver"; - TLoginProvider::TLoginUserRequest request3; request3.User = request1.User; request3.HashToValidate = hashToValidate; - auto loginResponse = provider.LoginUser(request3); - UNIT_ASSERT_VALUES_EQUAL(loginResponse.Error, "Invalid hash type"); + auto response3 = provider.LoginUser(request3); + UNIT_ASSERT_VALUES_EQUAL(response3.Error, "Invalid hash type"); } Y_UNIT_TEST(TestUnknownUser) { TLoginProvider provider; provider.RotateKeys(); + TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.Password = "password1"; + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); + TLoginProvider::TLoginUserRequest request2; - request2.User = "wrong user"; - request2.Password = request1.Password; + request2 = MakeScramPlainLoginRequest("wrong user", PASSWORD1_SCRAM_SERVER_KEY); auto response2 = provider.LoginUser(request2); UNIT_ASSERT(response2.Error == "Invalid user"); } @@ -331,21 +296,23 @@ Y_UNIT_TEST_SUITE(Login) { Y_UNIT_TEST(TestRemovedUser) { TLoginProvider provider; provider.RotateKeys(); + TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.Password = "password1"; + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); + TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.Password = request1.Password; + request2 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); auto response2 = provider.LoginUser(request2); UNIT_ASSERT_VALUES_EQUAL(response2.Error, ""); + provider.RemoveUser(request1.User); + TLoginProvider::TLoginUserRequest request3; - request3.User = request2.User; - request3.Password = request2.Password; - auto response3 = provider.LoginUser(request2); + request3 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); + auto response3 = provider.LoginUser(request3); UNIT_ASSERT(response3.Error == "Invalid user"); } @@ -353,16 +320,18 @@ Y_UNIT_TEST_SUITE(Login) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); + TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.Password = "password1"; + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); + TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.Password = request1.Password; + request2 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); auto response2 = provider.LoginUser(request2); UNIT_ASSERT(response2.Error.empty()); + TLoginProvider::TValidateTokenRequest request3; request3.Token = response2.Token; provider.Audience = "test_audience2"; @@ -374,24 +343,23 @@ Y_UNIT_TEST_SUITE(Login) { TLoginProvider provider; provider.Audience = "test_audience1"; provider.RotateKeys(); - TLoginProvider::TCreateUserRequest createUser1Request { - .User = "user1", - .Password = "password1" - }; - auto createUser1Response = provider.CreateUser(createUser1Request); - UNIT_ASSERT(!createUser1Response.Error); - TLoginProvider::TLoginUserRequest loginUser1Request1 { - .User = createUser1Request.User, - .Password = createUser1Request.Password - }; - auto loginUser1Response1 = provider.LoginUser(loginUser1Request1); - UNIT_ASSERT_VALUES_EQUAL(loginUser1Response1.Error, ""); - TLoginProvider::TValidateTokenRequest validateUser1TokenRequest1 { - .Token = loginUser1Response1.Token - }; - auto validateUser1TokenResponse1 = provider.ValidateToken(validateUser1TokenRequest1); - UNIT_ASSERT_VALUES_EQUAL(validateUser1TokenResponse1.Error, ""); - UNIT_ASSERT(validateUser1TokenResponse1.User == createUser1Request.User); + + TLoginProvider::TCreateUserRequest request1; + request1.User = "user1"; + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); + auto response1 = provider.CreateUser(request1); + UNIT_ASSERT(!response1.Error); + + TLoginProvider::TLoginUserRequest request2; + request2 = MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY); + auto response2 = provider.LoginUser(request2); + UNIT_ASSERT_VALUES_EQUAL(response2.Error, ""); + + TLoginProvider::TValidateTokenRequest request3; + request3.Token = response2.Token; + auto response3 = provider.ValidateToken(request3); + UNIT_ASSERT_VALUES_EQUAL(response3.Error, ""); + UNIT_ASSERT(response3.User == request1.User); TPasswordComplexity passwordComplexity({ .MinLength = 8, @@ -403,35 +371,18 @@ Y_UNIT_TEST_SUITE(Login) { provider.UpdatePasswordCheckParameters(passwordComplexity); - TLoginProvider::TModifyUserRequest modifyUser1RequestBad { - .User = createUser1Request.User, - .Password = "UserPassword1" - }; - - TLoginProvider::TBasicResponse modifyUser1ResponseBad = provider.ModifyUser(modifyUser1RequestBad); - UNIT_ASSERT(!modifyUser1ResponseBad.Error.empty()); - UNIT_ASSERT_STRINGS_EQUAL(modifyUser1ResponseBad.Error, "Incorrect password format: should contain at least 2 number, should contain at least 2 special character"); - - TLoginProvider::TModifyUserRequest modifyUser1Request { - .User = createUser1Request.User, - .Password = "paS*sw1oR#d7" - }; - - TLoginProvider::TBasicResponse modifyUser1Response = provider.ModifyUser(modifyUser1Request); - UNIT_ASSERT_VALUES_EQUAL(modifyUser1Response.Error, ""); + TLoginProvider::TModifyUserRequest request4; + request4.User = request1.User; + request4.Password = "UserPassword1"; + auto response4 = provider.ModifyUser(request4); + UNIT_ASSERT(!response4.Error.empty()); + UNIT_ASSERT_STRINGS_EQUAL(response4.Error, "Incorrect password format: should contain at least 2 number, should contain at least 2 special character"); - TLoginProvider::TLoginUserRequest loginUser1Request2 = { - .User = modifyUser1Request.User, - .Password = modifyUser1Request.Password.value() - }; - TLoginProvider::TLoginUserResponse loginUser1Response2 = provider.LoginUser(loginUser1Request2); - UNIT_ASSERT_VALUES_EQUAL(loginUser1Response2.Error, ""); - TLoginProvider::TValidateTokenRequest validateUser1TokenRequest2 = { - .Token = loginUser1Response2.Token - }; - TLoginProvider::TValidateTokenResponse validateUser1TokenResponse2 = provider.ValidateToken(validateUser1TokenRequest2); - UNIT_ASSERT_VALUES_EQUAL(validateUser1TokenResponse2.Error, ""); - UNIT_ASSERT(validateUser1TokenResponse2.User == createUser1Request.User); + TLoginProvider::TModifyUserRequest request5; + request5.User = request1.User; + request5.Password = "paS*sw1oR#d7"; + auto response5 = provider.ModifyUser(request5); + UNIT_ASSERT_VALUES_EQUAL(response5.Error, ""); } Y_UNIT_TEST(TestGroups) { @@ -588,7 +539,7 @@ Y_UNIT_TEST_SUITE(Login) { provider.Audience = "test_audience1"; provider.RotateKeys(); { - auto response1 = provider.CreateUser({.User = "user1", .Password = "password1"}); + auto response1 = provider.CreateUser({.User = "user1", .HashedPassword = Base64Encode(PASSWORD1_HASHES)}); UNIT_ASSERT(!response1.Error); } { @@ -600,7 +551,9 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT(!response1.Error); } { - auto response1 = provider.LoginUser({.User = "user1", .Password = "password1", .Options = {.WithUserGroups = true}}); + auto loginRequest = MakeScramPlainLoginRequest("user1", PASSWORD1_SCRAM_SERVER_KEY); + loginRequest.Options.WithUserGroups = true; + auto response1 = provider.LoginUser(loginRequest); UNIT_ASSERT(!response1.Error); auto response2 = provider.ValidateToken({.Token = response1.Token}); UNIT_ASSERT(!response2.Error); @@ -616,7 +569,7 @@ Y_UNIT_TEST_SUITE(Login) { provider.RotateKeys(); TLoginProvider::TCreateUserRequest request1; request1.User = "user1"; - request1.Password = "password1"; + request1.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto response1 = provider.CreateUser(request1); UNIT_ASSERT(!response1.Error); { @@ -634,10 +587,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT(response3.ExternalAuth == request2.ExternalAuth); } { - TLoginProvider::TLoginUserRequest request2; - request2.User = request1.User; - request2.Password = request1.Password; - auto response2 = provider.LoginUser(request2); + auto response2 = provider.LoginUser(MakeScramPlainLoginRequest(request1.User, PASSWORD1_SCRAM_SERVER_KEY)); UNIT_ASSERT_VALUES_EQUAL(response2.Error, ""); TLoginProvider::TValidateTokenRequest request3; request3.Token = response2.Token; @@ -719,10 +669,9 @@ Y_UNIT_TEST_SUITE(Login) { provider.Audience = "test_audience1"; provider.RotateKeys(); - TLoginProvider::TCreateUserRequest createUserRequest { - .User = "user1", - .Password = "password1" - }; + TLoginProvider::TCreateUserRequest createUserRequest; + createUserRequest.User = "user1"; + createUserRequest.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto createUserResponse = provider.CreateUser(createUserRequest); UNIT_ASSERT(!createUserResponse.Error); @@ -731,7 +680,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = TStringBuilder() << "wrongpassword" << attempt}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, TStringBuilder() << "wronghash" << attempt)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -746,7 +695,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::RESET); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = TStringBuilder() << "wrongpassword" << accountLockoutInitializer.AttemptThreshold}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, TStringBuilder() << "wronghash" << accountLockoutInitializer.AttemptThreshold)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -755,7 +704,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = createUserRequest.Password}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, PASSWORD1_SCRAM_SERVER_KEY)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::SUCCESS); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, ""); @@ -771,10 +720,9 @@ Y_UNIT_TEST_SUITE(Login) { provider.Audience = "test_audience1"; provider.RotateKeys(); - TLoginProvider::TCreateUserRequest createUserRequest { - .User = "user1", - .Password = "password1" - }; + TLoginProvider::TCreateUserRequest createUserRequest; + createUserRequest.User = "user1"; + createUserRequest.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto createUserResponse = provider.CreateUser(createUserRequest); UNIT_ASSERT(!createUserResponse.Error); @@ -783,7 +731,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = TStringBuilder() << "wrongpassword" << attempt}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, TStringBuilder() << "wronghash" << attempt)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -798,7 +746,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::RESET); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = "wrongpassword1"}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, "wronghash1")); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -808,7 +756,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = TStringBuilder() << "wrongpassword1" << attempt}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, TStringBuilder() << "wronghash1" << attempt)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -821,7 +769,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[createUserRequest.User]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = createUserRequest.User}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = createUserRequest.User, .Password = createUserRequest.Password}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(createUserRequest.User, PASSWORD1_SCRAM_SERVER_KEY)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::SUCCESS); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, ""); @@ -838,13 +786,10 @@ Y_UNIT_TEST_SUITE(Login) { provider.RotateKeys(); TString userName = "user1"; - TString userPassword = "password1"; - - TLoginProvider::TCreateUserRequest createUserRequest { - .User = userName, - .Password = userPassword - }; + TLoginProvider::TCreateUserRequest createUserRequest; + createUserRequest.User = userName; + createUserRequest.HashedPassword = Base64Encode(PASSWORD1_HASHES); auto createUserResponse = provider.CreateUser(createUserRequest); UNIT_ASSERT(!createUserResponse.Error); @@ -852,7 +797,7 @@ Y_UNIT_TEST_SUITE(Login) { UNIT_ASSERT_VALUES_EQUAL(provider.IsLockedOut(provider.Sids[userName]), false); auto checkLockoutResponse = provider.CheckLockOutUser({.User = userName}); UNIT_ASSERT_EQUAL(checkLockoutResponse.Status, TLoginProvider::TCheckLockOutResponse::EStatus::UNLOCKED); - auto loginUserResponse = provider.LoginUser({.User = userName, .Password = TStringBuilder() << "wrongpassword" << attempt}); + auto loginUserResponse = provider.LoginUser(MakeScramPlainLoginRequest(userName, TStringBuilder() << "wronghash" << attempt)); UNIT_ASSERT_EQUAL(loginUserResponse.Status, TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD); UNIT_ASSERT_VALUES_EQUAL(loginUserResponse.Error, "Invalid password"); } @@ -879,221 +824,8 @@ Y_UNIT_TEST_SUITE(Login) { } } - Y_UNIT_TEST(CreateAlterUserWithHashOldFormat) { - TLoginProvider provider; - provider.RotateKeys(); - - { - TString user = "user1"; - TString password = "password1"; - TString hash = R"( - { - "hash":"ZO37rNB37kP9hzmKRGfwc4aYrboDt4OBDsF1TBn5oLw=", - "salt":"HTkpQjtVJgBoA0CZu+i3zg==", - "type":"argon2id" - } - )"; - - { - TLoginProvider::TCreateUserRequest createRequest; - createRequest.User = user; - createRequest.Password = hash; - createRequest.IsHashedPassword = true; - auto createResponse = provider.CreateUser(createRequest); - UNIT_ASSERT(!createResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest; - loginRequest.User = user; - loginRequest.Password = password; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - } - - { - TString user = "user2"; - TString hash = R"( - { - "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=", - "salt": "Not in base64 format =) ", - "type": "argon2id" - } - )"; - - { - TLoginProvider::TCreateUserRequest createRequest; - createRequest.User = user; - createRequest.Password = hash; - createRequest.IsHashedPassword = true; - auto createResponse = provider.CreateUser(createRequest); - UNIT_ASSERT_STRING_CONTAINS(createResponse.Error, "Field \'salt\' must be in base64 format"); - } - - { - TLoginProvider::TLoginUserRequest loginRequest; - loginRequest.User = user; - loginRequest.Password = "somePassword"; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid user"); - - auto sids = provider.Sids; - UNIT_ASSERT(!sids.contains(user)); - } - } - - { - TString user = "user3"; - TString tempPassword = "password0"; - TString password = "password1"; - TString hash = R"( - { - "hash":"ZO37rNB37kP9hzmKRGfwc4aYrboDt4OBDsF1TBn5oLw=", - "salt":"HTkpQjtVJgBoA0CZu+i3zg==", - "type":"argon2id" - } - )"; - - { - TLoginProvider::TCreateUserRequest createRequest; - createRequest.User = user; - createRequest.Password = tempPassword; - auto createResponse = provider.CreateUser(createRequest); - UNIT_ASSERT(!createResponse.Error); - } - - { - TLoginProvider::TModifyUserRequest alterRequest; - alterRequest.User = user; - alterRequest.Password = hash; - alterRequest.IsHashedPassword = true; - auto alterResponse = provider.ModifyUser(alterRequest); - UNIT_ASSERT(!alterResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest; - loginRequest.User = user; - loginRequest.Password = password; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest; - loginRequest.User = user; - loginRequest.Password = tempPassword; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid password"); - } - } - } - - Y_UNIT_TEST(CheckThatCacheDoesNotHoldOldPassword) { - TLoginProvider provider(TPasswordComplexity(), TAccountLockout::TInitializer(), [] () {return true;}, {}); - provider.RotateKeys(); - - { - TLoginProvider::TCreateUserRequest createRequest { - .User = "user1", - .Password = "password1" - }; - auto createResponse = provider.CreateUser(createRequest); - UNIT_ASSERT(!createResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "password1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "pass1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid password"); - } - - // Try login with credentials from cache - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "password1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "pass1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid password"); - } - - // Change password for user1 - { - TLoginProvider::TModifyUserRequest alterRequest { - .User = "user1", - .Password = "pass1" - }; - auto alterResponse = provider.ModifyUser(alterRequest); - UNIT_ASSERT(!alterResponse.Error); - } - - // Cannot login with old password - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "password1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid password"); - } - - // Can login with new password - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "pass1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - - // Try login with credentials from cache - // Cannot login with old password - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "password1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT_STRING_CONTAINS(loginResponse.Error, "Invalid password"); - } - - // Can login with new password - { - TLoginProvider::TLoginUserRequest loginRequest { - .User = "user1", - .Password = "pass1" - }; - auto loginResponse = provider.LoginUser(loginRequest); - UNIT_ASSERT(!loginResponse.Error); - } - } - Y_UNIT_TEST(NotIgnoreCheckErrors) { - TLoginProvider provider(TPasswordComplexity(), TAccountLockout::TInitializer(), [] () {return true;}, {}); + TLoginProvider provider{TPasswordComplexity(), TAccountLockout::TInitializer()}; provider.RotateKeys(); TLoginProvider::TPasswordCheckResult checkResult; diff --git a/ydb/library/login/protos/login.proto b/ydb/library/login/protos/login.proto index 1841008635b..84127d545cf 100644 --- a/ydb/library/login/protos/login.proto +++ b/ydb/library/login/protos/login.proto @@ -43,7 +43,7 @@ message THashInitParams { message TSid { string Name = 1; ESidType.SidType Type = 2; - string ArgonHash = 3 [deprecated = true]; + reserved 3; reserved "ArgonHash"; repeated string Members = 4; uint64 CreatedAt = 5; // microseconds uint64 LastSuccessfulLogin = 6; // microseconds diff --git a/ydb/library/login/ya.make b/ydb/library/login/ya.make index bde0cdce0c0..32b0e8c26da 100644 --- a/ydb/library/login/ya.make +++ b/ydb/library/login/ya.make @@ -7,7 +7,6 @@ PEERDIR( library/cpp/json library/cpp/string_utils/base64 ydb/library/login/account_lockout - ydb/library/login/cache ydb/library/login/hashes_checker ydb/library/login/protos ydb/library/login/password_checker @@ -27,7 +26,6 @@ RECURSE_FOR_TESTS( RECURSE( account_lockout - cache hashes_checker password_checker sasl |
