Skip to content

Commit 179f412

Browse files
authored
Add account_type parameter for audit logs (#13269)
1 parent b7192f6 commit 179f412

File tree

6 files changed

+65
-9
lines changed

6 files changed

+65
-9
lines changed

ydb/core/grpc_services/audit_logins.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
namespace NKikimr {
1212
namespace NGRpcService {
1313

14-
void AuditLogLogin(IAuditCtx* ctx, const TString& database, const Ydb::Auth::LoginRequest& request, const Ydb::Auth::LoginResponse& response, const TString& errorDetails, const TString& sanitizedToken)
14+
void AuditLogLogin(IAuditCtx* ctx, const TString& database, const Ydb::Auth::LoginRequest& request,
15+
const Ydb::Auth::LoginResponse& response, const TString& errorDetails,
16+
const TString& sanitizedToken, bool isAdmin)
1517
{
1618
static const TString GrpcLoginComponentName = "grpc-login";
1719
static const TString LoginOperationName = "LOGIN";
20+
static const TString AdminAccountType = "admin";
1821

1922
//NOTE: EmptyValue couldn't be an empty string as AUDIT_PART() skips parts with an empty values
2023
static const TString EmptyValue = "{none}";
@@ -50,6 +53,7 @@ void AuditLogLogin(IAuditCtx* ctx, const TString& database, const Ydb::Auth::Log
5053
// Login
5154
AUDIT_PART("login_user", (!request.user().empty() ? request.user() : EmptyValue))
5255
AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EmptyValue))
56+
AUDIT_PART("account_type", AdminAccountType, (isAdmin && status == Ydb::StatusIds::SUCCESS))
5357

5458
//TODO: (?) it is possible to show masked version of the resulting token here
5559
);

ydb/core/grpc_services/audit_logins.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ namespace NKikimr::NGRpcService {
1313
class IAuditCtx;
1414

1515
// logins log
16-
void AuditLogLogin(IAuditCtx* ctx, const TString& database, const Ydb::Auth::LoginRequest& request, const Ydb::Auth::LoginResponse& response, const TString& errorDetails, const TString& sanitizedToken);
16+
void AuditLogLogin(IAuditCtx* ctx, const TString& database, const Ydb::Auth::LoginRequest& request,
17+
const Ydb::Auth::LoginResponse& response, const TString& errorDetails,
18+
const TString& sanitizedToken, bool isAdmin = false);
1719

1820
} // namespace NKikimr::NGRpcService

ydb/core/grpc_services/rpc_login.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include <ydb/core/security/ldap_auth_provider/ldap_auth_provider.h>
1313
#include <ydb/core/security/login_shared_func.h>
1414

15+
#include <ydb/library/aclib/aclib.h>
16+
#include <ydb/library/login/login.h>
17+
1518
#include <ydb/public/api/protos/ydb_auth.pb.h>
1619

1720
namespace NKikimr {
@@ -88,7 +91,7 @@ class TLoginRPC : public TRpcRequestActor<TLoginRPC, TEvLoginRequest, true> {
8891
ReplyErrorAndPassAway(Ydb::StatusIds::INTERNAL_ERROR, "Failed to produce a token");
8992
} else {
9093
// success = token + no errors
91-
ReplyAndPassAway(loginResult.GetToken(), loginResult.GetSanitizedToken());
94+
ReplyAndPassAway(loginResult);
9295
}
9396
}
9497

@@ -113,9 +116,12 @@ class TLoginRPC : public TRpcRequestActor<TLoginRPC, TEvLoginRequest, true> {
113116
}
114117
}
115118

116-
void ReplyAndPassAway(const TString& resultToken, const TString& sanitizedToken) {
117-
TResponse response;
119+
void ReplyAndPassAway(const NKikimrScheme::TEvLoginResult& loginResult) {
120+
const auto& resultToken = loginResult.GetToken();
121+
const auto& sanitizedToken = loginResult.GetSanitizedToken();
122+
const auto& isAdmin = loginResult.GetIsAdmin();
118123

124+
TResponse response;
119125
Ydb::Operations::Operation& operation = *response.mutable_operation();
120126
operation.set_ready(true);
121127
operation.set_status(Ydb::StatusIds::SUCCESS);
@@ -126,7 +132,7 @@ class TLoginRPC : public TRpcRequestActor<TLoginRPC, TEvLoginRequest, true> {
126132
operation.mutable_result()->PackFrom(result);
127133
}
128134

129-
AuditLogLogin(Request.Get(), PathToDatabase, *GetProtoRequest(), response, /* errorDetails */ TString(), sanitizedToken);
135+
AuditLogLogin(Request.Get(), PathToDatabase, *GetProtoRequest(), response, /* errorDetails */ TString(), sanitizedToken, isAdmin);
130136

131137
return CleanupAndReply(response);
132138
}

ydb/core/protos/flat_tx_scheme.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ message TEvLoginResult {
154154
optional string Error = 1;
155155
optional string Token = 2; // signed jwt token
156156
optional string SanitizedToken = 3; // sanitized token without signature
157+
optional bool IsAdmin = 4;
157158
}
158159

159160
// Sending actor registers itself to be notified when tx completes

ydb/core/tx/schemeshard/schemeshard__login.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@ struct TSchemeShard::TTxLogin : TTransactionBase<TSchemeShard> {
8787
}
8888

8989
private:
90+
bool IsAdmin() const {
91+
const auto& adminSids = AppData()->AdministrationAllowedSIDs;
92+
if (adminSids.empty()) {
93+
return true;
94+
}
95+
96+
const auto& user = Request->Get()->Record.GetUser();
97+
const auto providerGroups = Self->LoginProvider.GetGroupsMembership(user);
98+
const TVector<NACLib::TSID> groups(providerGroups.begin(), providerGroups.end());
99+
const auto userToken = NACLib::TUserToken(user, groups);
100+
auto hasSid = [&userToken](const TString& sid) -> bool {
101+
return userToken.IsExist(sid);
102+
};
103+
return std::find_if(adminSids.begin(), adminSids.end(), hasSid) != adminSids.end();
104+
}
105+
90106
bool LoginAttempt(NIceDb::TNiceDb& db, const TActorContext& ctx) {
91107
const auto& loginRequest = GetLoginRequest();
92108
if (!loginRequest.ExternalAuth && !AppData(ctx)->AuthConfig.GetEnableLoginAuthentication()) {
@@ -105,6 +121,7 @@ struct TSchemeShard::TTxLogin : TTransactionBase<TSchemeShard> {
105121
case NLogin::TLoginProvider::TLoginUserResponse::EStatus::SUCCESS: {
106122
Result->Record.SetToken(loginResponse.Token);
107123
Result->Record.SetSanitizedToken(loginResponse.SanitizedToken);
124+
Result->Record.SetIsAdmin(IsAdmin());
108125
break;
109126
}
110127
case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD:
@@ -145,6 +162,7 @@ struct TSchemeShard::TTxLogin : TTransactionBase<TSchemeShard> {
145162
HandleLoginAuthSuccess(loginRequest, loginResponse, db);
146163
Result->Record.SetToken(loginResponse.Token);
147164
Result->Record.SetSanitizedToken(loginResponse.SanitizedToken);
165+
Result->Record.SetIsAdmin(IsAdmin());
148166
break;
149167
}
150168
case NLogin::TLoginProvider::TLoginUserResponse::EStatus::INVALID_PASSWORD: {

ydb/core/tx/schemeshard/ut_login/ut_login.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -923,9 +923,7 @@ NHttp::THttpIncomingRequestPtr MakeLogoutRequest(const TString& cookieName, cons
923923
}
924924

925925
Y_UNIT_TEST_SUITE(TWebLoginService) {
926-
927-
Y_UNIT_TEST(AuditLogLoginSuccess) {
928-
TTestBasicRuntime runtime;
926+
void AuditLogLoginTest(TTestBasicRuntime& runtime, bool isUserAdmin) {
929927
std::vector<std::string> lines;
930928
runtime.AuditLogBackends = std::move(CreateTestAuditLogBackends(lines));
931929
TTestEnv env(runtime);
@@ -965,6 +963,33 @@ Y_UNIT_TEST_SUITE(TWebLoginService) {
965963
UNIT_ASSERT_STRING_CONTAINS(last, "login_user=user1");
966964
UNIT_ASSERT_STRING_CONTAINS(last, "sanitized_token=");
967965
UNIT_ASSERT(last.find("sanitized_token={none}") == std::string::npos);
966+
967+
if (isUserAdmin) {
968+
UNIT_ASSERT_STRING_CONTAINS(last, "account_type=admin");
969+
} else {
970+
UNIT_ASSERT(!last.contains("account_type=admin"));
971+
}
972+
}
973+
974+
Y_UNIT_TEST(AuditLogEmptySIDsLoginSuccess) {
975+
TTestBasicRuntime runtime;
976+
AuditLogLoginTest(runtime, true);
977+
}
978+
979+
Y_UNIT_TEST(AuditLogAdminLoginSuccess) {
980+
TTestBasicRuntime runtime;
981+
runtime.AddAppDataInit([](ui32, NKikimr::TAppData& appData){
982+
appData.AdministrationAllowedSIDs.emplace_back("user1");
983+
});
984+
AuditLogLoginTest(runtime, true);
985+
}
986+
987+
Y_UNIT_TEST(AuditLogLoginSuccess) {
988+
TTestBasicRuntime runtime;
989+
runtime.AddAppDataInit([](ui32, NKikimr::TAppData& appData){
990+
appData.AdministrationAllowedSIDs.emplace_back("user2");
991+
});
992+
AuditLogLoginTest(runtime, false);
968993
}
969994

970995
Y_UNIT_TEST(AuditLogLoginBadPassword) {

0 commit comments

Comments
 (0)