diff --git a/internal/api/grpc/authorization/v2beta/integration_test/query_test.go b/internal/api/grpc/authorization/v2beta/integration_test/query_test.go index cc342690c2a..0bf40959403 100644 --- a/internal/api/grpc/authorization/v2beta/integration_test/query_test.go +++ b/internal/api/grpc/authorization/v2beta/integration_test/query_test.go @@ -284,6 +284,39 @@ func TestServer_ListAuthorizations(t *testing.T) { }, }, }, + { + name: "list single id in ids, project and project grant, multiple", + args: args{ + ctx: iamOwnerCtx, + dep: func(request *authorization.ListAuthorizationsRequest, response *authorization.ListAuthorizationsResponse) { + userResp := Instance.CreateUserTypeHuman(iamOwnerCtx, integration.Email()) + + request.Filters[0].Filter = &authorization.AuthorizationsSearchFilter_InUserIds{ + InUserIds: &filter.InIDsFilter{ + Ids: []string{userResp.GetId()}, + }, + } + response.Authorizations[5] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), false) + response.Authorizations[4] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), false) + response.Authorizations[3] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), false) + response.Authorizations[2] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), true) + response.Authorizations[1] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), true) + response.Authorizations[0] = createAuthorization(iamOwnerCtx, Instance, t, Instance.DefaultOrg.GetId(), userResp.GetId(), true) + }, + req: &authorization.ListAuthorizationsRequest{ + Filters: []*authorization.AuthorizationsSearchFilter{{}}, + }, + }, + want: &authorization.ListAuthorizationsResponse{ + Pagination: &filter.PaginationResponse{ + TotalResult: 6, + AppliedLimit: 100, + }, + Authorizations: []*authorization.Authorization{ + {}, {}, {}, {}, {}, {}, + }, + }, + }, { name: "list single id, project and project grant, multiple", args: args{ diff --git a/internal/api/grpc/authorization/v2beta/query.go b/internal/api/grpc/authorization/v2beta/query.go index 75c3d671780..680ccf19df7 100644 --- a/internal/api/grpc/authorization/v2beta/query.go +++ b/internal/api/grpc/authorization/v2beta/query.go @@ -92,7 +92,7 @@ func AuthorizationSearchFilterToQuery(query *authorization.AuthorizationsSearchF case *authorization.AuthorizationsSearchFilter_State: return AuthorizationStateQueryToModel(q.State) case *authorization.AuthorizationsSearchFilter_UserId: - return AuthorizationUserUserIDQueryToModel(q.UserId) + return AuthorizationUserIDQueryToModel(q.UserId) case *authorization.AuthorizationsSearchFilter_UserOrganizationId: return AuthorizationUserOrganizationIDQueryToModel(q.UserOrganizationId) case *authorization.AuthorizationsSearchFilter_UserPreferredLoginName: @@ -107,6 +107,8 @@ func AuthorizationSearchFilterToQuery(query *authorization.AuthorizationsSearchF return AuthorizationRoleKeyQueryToModel(q.RoleKey) case *authorization.AuthorizationsSearchFilter_ProjectGrantId: return AuthorizationProjectGrantIDQueryToModel(q.ProjectGrantId) + case *authorization.AuthorizationsSearchFilter_InUserIds: + return AuthorizationInUserIDsQueryToModel(q.InUserIds) default: return nil, errors.New("invalid query") } @@ -144,10 +146,14 @@ func AuthorizationUserNameQueryToModel(q *authorization.UserPreferredLoginNameQu return query.NewUserGrantUsernameQuery(q.LoginName, filter.TextMethodPbToQuery(q.Method)) } -func AuthorizationUserUserIDQueryToModel(q *filter_pb.IDFilter) (query.SearchQuery, error) { +func AuthorizationUserIDQueryToModel(q *filter_pb.IDFilter) (query.SearchQuery, error) { return query.NewUserGrantUserIDSearchQuery(q.Id) } +func AuthorizationInUserIDsQueryToModel(q *filter_pb.InIDsFilter) (query.SearchQuery, error) { + return query.NewUserGrantInUserIDsSearchQuery(q.Ids) +} + func AuthorizationUserOrganizationIDQueryToModel(q *filter_pb.IDFilter) (query.SearchQuery, error) { return query.NewUserGrantUserResourceOwnerSearchQuery(q.Id) } diff --git a/internal/api/grpc/user/user_grant.go b/internal/api/grpc/user/user_grant.go index 14ec8f6395d..2fe46ffd910 100644 --- a/internal/api/grpc/user/user_grant.go +++ b/internal/api/grpc/user/user_grant.go @@ -107,6 +107,8 @@ func UserGrantQueryToQuery(ctx context.Context, query *user_pb.UserGrantQuery) ( return UserGrantWithGrantedQueryToModel(ctx, q.WithGrantedQuery) case *user_pb.UserGrantQuery_UserTypeQuery: return UserGrantUserTypeQueryToModel(q.UserTypeQuery) + case *user_pb.UserGrantQuery_InUserIdsQuery: + return UserGrantInUserIDsQueryToModel(q.InUserIdsQuery) default: return nil, errors.New("invalid query") } @@ -156,6 +158,10 @@ func UserGrantUserIDQueryToModel(q *user_pb.UserGrantUserIDQuery) (query.SearchQ return query.NewUserGrantUserIDSearchQuery(q.UserId) } +func UserGrantInUserIDsQueryToModel(q *user_pb.UserGrantInUserIDsQuery) (query.SearchQuery, error) { + return query.NewUserGrantInUserIDsSearchQuery(q.InUserIds) +} + func UserGrantUserNameQueryToModel(q *user_pb.UserGrantUserNameQuery) (query.SearchQuery, error) { return query.NewUserGrantUsernameQuery(q.UserName, object.TextMethodToQuery(q.Method)) } diff --git a/internal/query/user_grant.go b/internal/query/user_grant.go index 6a527c92c81..6efc82f13b2 100644 --- a/internal/query/user_grant.go +++ b/internal/query/user_grant.go @@ -114,6 +114,14 @@ func NewUserGrantUserIDSearchQuery(id string) (SearchQuery, error) { return NewTextQuery(UserGrantUserID, id, TextEquals) } +func NewUserGrantInUserIDsSearchQuery(ids []string) (SearchQuery, error) { + list := make([]interface{}, len(ids)) + for i, value := range ids { + list[i] = value + } + return NewListQuery(UserGrantUserID, list, ListIn) +} + func NewUserGrantProjectIDSearchQuery(id string) (SearchQuery, error) { return NewTextQuery(UserGrantProjectID, id, TextEquals) } diff --git a/proto/zitadel/authorization/v2beta/authorization.proto b/proto/zitadel/authorization/v2beta/authorization.proto index aedd4c8b3c7..83aa602e780 100644 --- a/proto/zitadel/authorization/v2beta/authorization.proto +++ b/proto/zitadel/authorization/v2beta/authorization.proto @@ -108,6 +108,8 @@ message AuthorizationsSearchFilter { // Search for authorizations by the ID of the project grant the user was granted the authorization for. // This will also include authorizations granted for project grants of the same project. zitadel.filter.v2beta.IDFilter project_grant_id = 11; + // Search for authorizations by the IDs of the users who were granted the authorizations. + zitadel.filter.v2beta.InIDsFilter in_user_ids = 12; } } diff --git a/proto/zitadel/user.proto b/proto/zitadel/user.proto index 569c2ce97ed..d2c1a518d63 100644 --- a/proto/zitadel/user.proto +++ b/proto/zitadel/user.proto @@ -829,6 +829,7 @@ message UserGrantQuery { UserGrantProjectNameQuery project_name_query = 12; UserGrantDisplayNameQuery display_name_query = 13; UserGrantUserTypeQuery user_type_query = 14; + UserGrantInUserIDsQuery in_user_ids_query = 15; } } @@ -850,6 +851,15 @@ message UserGrantUserIDQuery { ]; } +message UserGrantInUserIDsQuery { + repeated string in_user_ids = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "the IDs of the users to include" + example: "[\"69629023906488334\",\"69629023906488335\"]"; + } + ]; +} + message UserGrantWithGrantedQuery { bool with_granted = 1; }