Skip to content

Commit

Permalink
v1 and v2
Browse files Browse the repository at this point in the history
  • Loading branch information
molotkov-and committed Dec 29, 2023
1 parent 2aa4959 commit c4869b2
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 75 deletions.
10 changes: 5 additions & 5 deletions ydb/core/fq/libs/control_plane_proxy/control_plane_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@ class TResolveSubjectTypeActor : public NActors::TActorBootstrapped<TResolveSubj
}

private:
static TString GetSubjectType(const yandex::cloud::priv::accessservice::v2::Subject& subject) {
static TString GetSubjectType(const yandex::cloud::priv::servicecontrol::v1::Subject& subject) {
switch (subject.type_case()) {
case yandex::cloud::priv::accessservice::v2::Subject::TYPE_NOT_SET:
case yandex::cloud::priv::accessservice::v2::Subject::kAnonymousAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TYPE_NOT_SET:
case yandex::cloud::priv::servicecontrol::v1::Subject::kAnonymousAccount:
return "unknown";
case yandex::cloud::priv::accessservice::v2::Subject::kUserAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::kUserAccount:
return subject.user_account().federation_id() ? "federated_account" : "user_account";
case yandex::cloud::priv::accessservice::v2::Subject::kServiceAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::kServiceAccount:
return "service_account";
}
}
Expand Down
99 changes: 64 additions & 35 deletions ydb/core/security/ticket_parser_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,16 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
};

struct TPermissionRecord {
enum class TTypeCase {
TYPE_NOT_SET,
USER_ACCOUNT_TYPE,
SERVICE_ACCOUNT_TYPE,
ANONYMOUS_ACCOUNT_TYPE,
};

TString Subject;
bool Required = false;
yandex::cloud::priv::accessservice::v2::Subject::TypeCase SubjectType;
TTypeCase SubjectType;
TEvTicketParser::TError Error;
TStackVec<std::pair<TString, TString>> Attributes;

Expand Down Expand Up @@ -263,7 +270,8 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
TDuration LifeTime = TDuration::Hours(1); // for how long ticket will remain in the cache after last access
TDuration AsSignatureExpireTime = TDuration::Minutes(1);

TActorId AccessServiceValidator;
TActorId AccessServiceValidatorV1;
TActorId AccessServiceValidatorV2;
TActorId UserAccountService;
TActorId ServiceAccountService;
TString UserAccountDomain;
Expand Down Expand Up @@ -388,7 +396,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
request->Request.set_permission(permissionName);
addResourcePaths(record, permissionName, &request->Request);
record.ResponsesLeft++;
Send(AccessServiceValidator, request.Release());
Send(AccessServiceValidatorV1, request.Release());
}
}

Expand All @@ -403,7 +411,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
requestForPermissions << " " << permissionName;
}
BLOG_TRACE("Ticket " << record.GetMaskedTicket() << " asking for AccessServiceBulkAuthorization(" << requestForPermissions << ")");
Send(AccessServiceValidator, request.Release());
Send(AccessServiceValidatorV2, request.Release());
}

template <typename TTokenRecord>
Expand All @@ -422,23 +430,38 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
auto request = CreateAccessServiceRequest<TEvAccessServiceAuthenticateRequest>(key, record);

record.ResponsesLeft++;
Send(AccessServiceValidator, request.Release());
Send(AccessServiceValidatorV1, request.Release());
}


TString GetSubjectName(const yandex::cloud::priv::accessservice::v2::Subject& subject) {
template <typename TSubject>
TString GetSubjectName(const TSubject& subject) {
switch (subject.type_case()) {
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kUserAccount:
case TSubject::TypeCase::kUserAccount:
return subject.user_account().id() + "@" + AccessServiceDomain;
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kServiceAccount:
case TSubject::TypeCase::kServiceAccount:
return subject.service_account().id() + "@" + AccessServiceDomain;
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kAnonymousAccount:
case TSubject::TypeCase::kAnonymousAccount:
return "anonymous" "@" + AccessServiceDomain;
default:
return "Unknown subject type";
}
}

template <typename TSubjectType>
TPermissionRecord::TTypeCase ConvertSubjectType(const TSubjectType& type) {
switch (type) {
case TSubjectType::kUserAccount:
return TPermissionRecord::TTypeCase::USER_ACCOUNT_TYPE;
case TSubjectType::kServiceAccount:
return TPermissionRecord::TTypeCase::SERVICE_ACCOUNT_TYPE;
case TSubjectType::kAnonymousAccount:
return TPermissionRecord::TTypeCase::ANONYMOUS_ACCOUNT_TYPE;
default:
return TPermissionRecord::TTypeCase::TYPE_NOT_SET;
}
}

template <typename TTokenRecord>
bool CanInitBuiltinToken(const TString& key, TTokenRecord& record) {
if (record.TokenType == TDerived::ETokenType::Unknown || record.TokenType == TDerived::ETokenType::Builtin) {
Expand Down Expand Up @@ -665,9 +688,9 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
record.ResponsesLeft--;
if (response->Status.Ok()) {
switch (response->Response.subject().type_case()) {
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kUserAccount:
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kServiceAccount:
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kAnonymousAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TypeCase::kUserAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TypeCase::kServiceAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TypeCase::kAnonymousAccount:
record.Subject = GetSubjectName(response->Response.subject());
break;
default:
Expand All @@ -678,7 +701,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
record.TokenType = request->Request.has_api_key() ? TDerived::ETokenType::ApiKey : TDerived::ETokenType::AccessService;
if (!record.Subject.empty()) {
switch (response->Response.subject().type_case()) {
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kUserAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TypeCase::kUserAccount:
if (UserAccountService) {
BLOG_TRACE("Ticket " << record.GetMaskedTicket()
<< " asking for UserAccount(" << record.Subject << ")");
Expand All @@ -690,7 +713,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
return;
}
break;
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kServiceAccount:
case yandex::cloud::priv::servicecontrol::v1::Subject::TypeCase::kServiceAccount:
if (ServiceAccountService) {
BLOG_TRACE("Ticket " << record.GetMaskedTicket()
<< " asking for ServiceAccount(" << record.Subject << ")");
Expand Down Expand Up @@ -783,8 +806,8 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
if (response->Status.Ok()) {
const auto& subject = response->Response.subject();
const TString subjectName = GetSubjectName(subject);
const auto& subjectType = subject.type_case();
for (const auto& [permissionName, permissionRecord] : examinedPermissions) {
const auto& subjectType = ConvertSubjectType(subject.type_case());
for (auto& [permissionName, permissionRecord] : examinedPermissions) {
permissionRecord.Subject = subjectName;
permissionRecord.SubjectType = subjectType;
permissionRecord.Error.clear();
Expand All @@ -794,7 +817,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
auto permissionDenied = examinedPermissions.find(result.permission());
if (permissionDenied != examinedPermissions.end()) {
auto& permissionDeniedRecord = permissionDenied->second;
permissionDeniedRecord.Subject.Clear();
permissionDeniedRecord.Subject.clear();
permissionDeniedRecord.Error = {.Message = result.permission_denied_error().message(), .Retryable = false};
BLOG_TRACE("Ticket " << record.GetMaskedTicket() << " permission " << result.permission() << " access denied for subject \"" << subject << "\"");
} else {
Expand All @@ -811,8 +834,8 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
grpsErrorMessage = response->Status.Msg;
isRetryableGrpsError = IsRetryableGrpcError(response->Status);
}
for (const auto& [permissionName, permissionRecord] : examinedPermissions) {
permissionRecord.Subject.Clear();
for (auto& [permissionName, permissionRecord] : examinedPermissions) {
permissionRecord.Subject.clear();
permissionRecord.Error = {.Message = grpsErrorMessage, .Retryable = isRetryableGrpsError};
BLOG_TRACE("Ticket " << record.GetMaskedTicket()
<< " permission " << permissionName
Expand All @@ -837,12 +860,12 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
auto& record = itToken->second;
TString permission = request->Request.permission();
TString subject;
yandex::cloud::priv::accessservice::v2::Subject::TypeCase subjectType = yandex::cloud::priv::accessservice::v2::Subject::TypeCase::TYPE_NOT_SET;
typename TPermissionRecord::TTypeCase subjectType = TPermissionRecord::TTypeCase::TYPE_NOT_SET;
auto itPermission = record.Permissions.find(permission);
if (itPermission != record.Permissions.end()) {
if (response->Status.Ok()) {
subject = GetSubjectName(response->Response.subject());
subjectType = response->Response.subject().type_case();
subjectType = ConvertSubjectType(response->Response.subject().type_case());
itPermission->second.Subject = subject;
itPermission->second.SubjectType = subjectType;
itPermission->second.Error.clear();
Expand Down Expand Up @@ -918,7 +941,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
if (permissionsOk > 0 && retryableErrors == 0 && !requiredPermissionFailed) {
record.TokenType = request->Request.has_api_key() ? TDerived::ETokenType::ApiKey : TDerived::ETokenType::AccessService;
switch (subjectType) {
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kUserAccount:
case TPermissionRecord::TTypeCase::USER_ACCOUNT_TYPE:
if (UserAccountService) {
BLOG_TRACE("Ticket " << record.GetMaskedTicket()
<< " asking for UserAccount(" << subject << ")");
Expand All @@ -930,7 +953,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
return;
}
break;
case yandex::cloud::priv::accessservice::v2::Subject::TypeCase::kServiceAccount:
case TPermissionRecord::TTypeCase::SERVICE_ACCOUNT_TYPE:
if (ServiceAccountService) {
BLOG_TRACE("Ticket " << record.GetMaskedTicket()
<< " asking for ServiceAccount(" << subject << ")");
Expand Down Expand Up @@ -1136,13 +1159,13 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
}

if (tokenType == "Bearer" || tokenType == "IAM") {
if (AccessServiceValidator) {
if (AccessServiceValidatorV1 && AccessServiceValidatorV2) {
return TDerived::ETokenType::AccessService;
} else {
return TDerived::ETokenType::Unsupported;
}
} else if (tokenType == "ApiKey") {
if (AccessServiceValidator && Config.GetUseAccessServiceApiKey()) {
if (AccessServiceValidatorV1 && AccessServiceValidatorV2 && Config.GetUseAccessServiceApiKey()) {
return TDerived::ETokenType::ApiKey;
} else {
return TDerived::ETokenType::Unsupported;
Expand Down Expand Up @@ -1198,7 +1221,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
template <typename TTokenRecord>
void InitTokenRecord(const TString& key, TTokenRecord& record, TInstant) {
if (GetDerived()->CanInitAccessServiceToken(record)) {
if (AccessServiceValidator) {
if (AccessServiceValidatorV1 && AccessServiceValidatorV2) {
if (record.Permissions) {
RequestAccessServiceAuthorization(key, record);
} else {
Expand Down Expand Up @@ -1360,7 +1383,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {

template <typename TTokenRecord>
bool CanRefreshAccessServiceTicket(const TTokenRecord& record) {
if (!AccessServiceValidator) {
if (!AccessServiceValidatorV1 && AccessServiceValidatorV2) {
return false;
}
if (record.TokenType == TDerived::ETokenType::AccessService || record.TokenType == TDerived::ETokenType::ApiKey) {
Expand Down Expand Up @@ -1479,7 +1502,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {

void WriteAuthorizeMethods(TStringBuilder& html) {
html << "<tr><td>Login</td><td>" << HtmlBool(UseLoginProvider) << "</td></tr>";
html << "<tr><td>Access Service</td><td>" << HtmlBool((bool)AccessServiceValidator) << "</td></tr>";
html << "<tr><td>Access Service</td><td>" << HtmlBool((bool)AccessServiceValidatorV1 && (bool)AccessServiceValidatorV2) << "</td></tr>";
html << "<tr><td>User Account Service</td><td>" << HtmlBool((bool)UserAccountService) << "</td></tr>";
html << "<tr><td>Service Account Service</td><td>" << HtmlBool((bool)ServiceAccountService) << "</td></tr>";
}
Expand Down Expand Up @@ -1526,21 +1549,23 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
}
settings.GrpcKeepAliveTimeMs = Config.GetAccessServiceGrpcKeepAliveTimeMs();
settings.GrpcKeepAliveTimeoutMs = Config.GetAccessServiceGrpcKeepAliveTimeoutMs();
AccessServiceValidator = Register(NCloud::CreateAccessService(settings), TMailboxType::HTSwap, AppData()->UserPoolId);
AccessServiceValidatorV1 = Register(NCloud::CreateAccessServiceV1(settings), TMailboxType::HTSwap, AppData()->UserPoolId);
if (Config.GetCacheAccessServiceAuthentication()) {
AccessServiceValidator = Register(NCloud::CreateGrpcServiceCache<NCloud::TEvAccessService::TEvAuthenticateRequest, NCloud::TEvAccessService::TEvAuthenticateResponse>(
AccessServiceValidator,
AccessServiceValidatorV1 = Register(NCloud::CreateGrpcServiceCache<NCloud::TEvAccessService::TEvAuthenticateRequest, NCloud::TEvAccessService::TEvAuthenticateResponse>(
AccessServiceValidatorV1,
Config.GetGrpcCacheSize(),
TDuration::MilliSeconds(Config.GetGrpcSuccessLifeTime()),
TDuration::MilliSeconds(Config.GetGrpcErrorLifeTime())), TMailboxType::HTSwap, AppData()->UserPoolId);
}
if (Config.GetCacheAccessServiceAuthorization()) {
AccessServiceValidator = Register(NCloud::CreateGrpcServiceCache<NCloud::TEvAccessService::TEvAuthorizeRequest, NCloud::TEvAccessService::TEvAuthorizeResponse>(
AccessServiceValidator,
AccessServiceValidatorV1 = Register(NCloud::CreateGrpcServiceCache<NCloud::TEvAccessService::TEvAuthorizeRequest, NCloud::TEvAccessService::TEvAuthorizeResponse>(
AccessServiceValidatorV1,
Config.GetGrpcCacheSize(),
TDuration::MilliSeconds(Config.GetGrpcSuccessLifeTime()),
TDuration::MilliSeconds(Config.GetGrpcErrorLifeTime())), TMailboxType::HTSwap, AppData()->UserPoolId);
}

AccessServiceValidatorV2 = Register(NCloud::CreateAccessServiceV2(settings), TMailboxType::HTSwap, AppData()->UserPoolId);
}

if (Config.GetUseUserAccountService()) {
Expand Down Expand Up @@ -1591,8 +1616,11 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
}

void PassAway() override {
if (AccessServiceValidator) {
Send(AccessServiceValidator, new TEvents::TEvPoisonPill);
if (AccessServiceValidatorV1) {
Send(AccessServiceValidatorV1, new TEvents::TEvPoisonPill);
}
if (AccessServiceValidatorV2) {
Send(AccessServiceValidatorV2, new TEvents::TEvPoisonPill);
}
if (UserAccountService) {
Send(UserAccountService, new TEvents::TEvPoisonPill);
Expand Down Expand Up @@ -1638,6 +1666,7 @@ class TTicketParserImpl : public TActorBootstrapped<TDerived> {
hFunc(TEvLdapAuthProvider::TEvEnrichGroupsResponse, Handle);
hFunc(NCloud::TEvAccessService::TEvAuthenticateResponse, Handle);
hFunc(NCloud::TEvAccessService::TEvAuthorizeResponse, Handle);
hFunc(NCloud::TEvAccessService::TEvBulkAuthorizeResponse, Handle);
hFunc(NCloud::TEvUserAccountService::TEvGetUserAccountResponse, Handle);
hFunc(NCloud::TEvServiceAccountService::TEvGetServiceAccountResponse, Handle);
hFunc(NMon::TEvHttpInfo, Handle);
Expand Down
Loading

0 comments on commit c4869b2

Please sign in to comment.