From 319ebe78983e30160323aa36cc9ede47d9cf40f3 Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Thu, 21 Mar 2024 09:07:00 +0100 Subject: [PATCH] fix: add organizationID query for user v2 ListUsers and clean up depeprecated attribute (#7593) Add organizationID as query for ListUsers and clean up the deprecated Organisation attributes in other queries. This PR removes the following fields from API requests (user service v2): organisation from AddHumanUser (deprecated some time ago, organization still exists) organization from GetUserByID --- .../server/middleware/auth_interceptor.go | 28 +--- internal/api/grpc/user/v2/query.go | 8 +- .../grpc/user/v2/query_integration_test.go | 158 +++++++++++++----- .../api/grpc/user/v2/user_integration_test.go | 60 +++---- pkg/grpc/user/v2beta/user.go | 10 -- .../v2beta/user_service_org.pb.zitadel.go | 12 -- proto/zitadel/user/v2beta/query.proto | 67 +++++++- proto/zitadel/user/v2beta/user_service.proto | 17 +- 8 files changed, 217 insertions(+), 143 deletions(-) delete mode 100644 pkg/grpc/user/v2beta/user_service_org.pb.zitadel.go diff --git a/internal/api/grpc/server/middleware/auth_interceptor.go b/internal/api/grpc/server/middleware/auth_interceptor.go index 21c9d2e726..6eb326a59a 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor.go +++ b/internal/api/grpc/server/middleware/auth_interceptor.go @@ -44,30 +44,17 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, func orgIDAndDomainFromRequest(ctx context.Context, req interface{}) (id, domain string) { orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID) - o, ok := req.(OrganizationFromRequest) - if !ok { - return orgID, "" - } - id = o.OrganizationFromRequest().ID - domain = o.OrganizationFromRequest().Domain - if id != "" || domain != "" { - return id, domain - } - // check if the deprecated organisation is used. - // to be removed before going GA (https://github.com/zitadel/zitadel/issues/6718) - id = o.OrganisationFromRequest().ID - domain = o.OrganisationFromRequest().Domain - if id != "" || domain != "" { - return id, domain + oz, ok := req.(OrganizationFromRequest) + if ok { + id = oz.OrganizationFromRequest().ID + domain = oz.OrganizationFromRequest().Domain + if id != "" || domain != "" { + return id, domain + } } return orgID, domain } -// Deprecated: will be removed in favor of OrganizationFromRequest (https://github.com/zitadel/zitadel/issues/6718) -type OrganisationFromRequest interface { - OrganisationFromRequest() *Organization -} - type Organization struct { ID string Domain string @@ -75,5 +62,4 @@ type Organization struct { type OrganizationFromRequest interface { OrganizationFromRequest() *Organization - OrganisationFromRequest } diff --git a/internal/api/grpc/user/v2/query.go b/internal/api/grpc/user/v2/query.go index 2fa252b24a..225b469302 100644 --- a/internal/api/grpc/user/v2/query.go +++ b/internal/api/grpc/user/v2/query.go @@ -239,8 +239,8 @@ func userQueryToQuery(query *user.SearchQuery, level uint8) (query.SearchQuery, return typeQueryToQuery(q.TypeQuery) case *user.SearchQuery_LoginNameQuery: return loginNameQueryToQuery(q.LoginNameQuery) - case *user.SearchQuery_ResourceOwner: - return resourceOwnerQueryToQuery(q.ResourceOwner) + case *user.SearchQuery_OrganizationIdQuery: + return resourceOwnerQueryToQuery(q.OrganizationIdQuery) case *user.SearchQuery_InUserIdsQuery: return inUserIdsQueryToQuery(q.InUserIdsQuery) case *user.SearchQuery_OrQuery: @@ -292,8 +292,8 @@ func loginNameQueryToQuery(q *user.LoginNameQuery) (query.SearchQuery, error) { return query.NewUserLoginNameExistsQuery(q.LoginName, object.TextMethodToQuery(q.Method)) } -func resourceOwnerQueryToQuery(q *user.ResourceOwnerQuery) (query.SearchQuery, error) { - return query.NewUserResourceOwnerSearchQuery(q.OrgID, query.TextEquals) +func resourceOwnerQueryToQuery(q *user.OrganizationIdQuery) (query.SearchQuery, error) { + return query.NewUserResourceOwnerSearchQuery(q.OrganizationId, query.TextEquals) } func inUserIdsQueryToQuery(q *user.InUserIDQuery) (query.SearchQuery, error) { diff --git a/internal/api/grpc/user/v2/query_integration_test.go b/internal/api/grpc/user/v2/query_integration_test.go index 352bba89a9..1d51b6d4e1 100644 --- a/internal/api/grpc/user/v2/query_integration_test.go +++ b/internal/api/grpc/user/v2/query_integration_test.go @@ -37,11 +37,6 @@ func TestServer_GetUserByID(t *testing.T) { args: args{ IamCTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: Tester.Organisation.ID, - }, - }, UserId: "", }, func(ctx context.Context, username string, request *user.GetUserByIDRequest) error { @@ -55,11 +50,6 @@ func TestServer_GetUserByID(t *testing.T) { args: args{ IamCTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: Tester.Organisation.ID, - }, - }, UserId: "unknown", }, func(ctx context.Context, username string, request *user.GetUserByIDRequest) error { @@ -72,13 +62,7 @@ func TestServer_GetUserByID(t *testing.T) { name: "user by ID, ok", args: args{ IamCTX, - &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: Tester.Organisation.ID, - }, - }, - }, + &user.GetUserByIDRequest{}, func(ctx context.Context, username string, request *user.GetUserByIDRequest) error { resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) request.UserId = resp.GetUserId() @@ -172,11 +156,6 @@ func TestServer_GetUserByID_Permission(t *testing.T) { args: args{ SystemCTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: newOrg.GetOrganizationId(), - }, - }, UserId: newUserID, }, }, @@ -215,11 +194,6 @@ func TestServer_GetUserByID_Permission(t *testing.T) { args: args{ IamCTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: newOrg.GetOrganizationId(), - }, - }, UserId: newUserID, }, }, @@ -258,11 +232,6 @@ func TestServer_GetUserByID_Permission(t *testing.T) { args: args{ CTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: newOrg.GetOrganizationId(), - }, - }, UserId: newUserID, }, }, @@ -273,11 +242,6 @@ func TestServer_GetUserByID_Permission(t *testing.T) { args: args{ UserCTX, &user.GetUserByIDRequest{ - Organization: &object.Organization{ - Org: &object.Organization_OrgId{ - OrgId: newOrg.GetOrganizationId(), - }, - }, UserId: newUserID, }, }, @@ -316,7 +280,7 @@ func TestServer_ListUsers(t *testing.T) { ctx context.Context count int req *user.ListUsersRequest - dep func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) + dep func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) } tests := []struct { name string @@ -330,7 +294,7 @@ func TestServer_ListUsers(t *testing.T) { UserCTX, 0, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { request.Queries = append(request.Queries, InUserIDsQuery([]string{userResp.UserId})) return []userAttr{}, nil }, @@ -350,7 +314,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 1, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) for i, username := range usernames { @@ -400,7 +364,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 3, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) for i, username := range usernames { @@ -492,7 +456,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 1, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) for i, username := range usernames { @@ -542,7 +506,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 1, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) for i, username := range usernames { resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) @@ -590,7 +554,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 3, &user.ListUsersRequest{}, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) for i, username := range usernames { resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) @@ -683,7 +647,7 @@ func TestServer_ListUsers(t *testing.T) { InUserEmailsQuery([]string{"notfound"}), }, }, - func(ctx context.Context, org string, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { return []userAttr{}, nil }, }, @@ -696,6 +660,99 @@ func TestServer_ListUsers(t *testing.T) { Result: []*user.User{}, }, }, + { + name: "list user resourceowner multiple, ok", + args: args{ + IamCTX, + 3, + &user.ListUsersRequest{}, + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + orgResp := Tester.CreateOrganization(ctx, fmt.Sprintf("ListUsersResourceowner%d", time.Now().UnixNano()), fmt.Sprintf("%d@mouse.com", time.Now().UnixNano())) + + infos := make([]userAttr, len(usernames)) + for i, username := range usernames { + resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) + infos[i] = userAttr{resp.GetUserId(), username} + } + request.Queries = append(request.Queries, OrganizationIdQuery(orgResp.OrganizationId)) + request.Queries = append(request.Queries, InUserEmailsQuery(usernames)) + return infos, nil + }, + }, + want: &user.ListUsersResponse{ + Details: &object.ListDetails{ + TotalResult: 3, + Timestamp: timestamppb.Now(), + }, + SortingColumn: 0, + Result: []*user.User{ + { + State: user.UserState_USER_STATE_ACTIVE, + Type: &user.User_Human{ + Human: &user.HumanUser{ + Profile: &user.HumanProfile{ + GivenName: "Mickey", + FamilyName: "Mouse", + NickName: gu.Ptr("Mickey"), + DisplayName: gu.Ptr("Mickey Mouse"), + PreferredLanguage: gu.Ptr("nl"), + Gender: user.Gender_GENDER_MALE.Enum(), + }, + Email: &user.HumanEmail{ + IsVerified: true, + }, + Phone: &user.HumanPhone{ + Phone: "+41791234567", + IsVerified: true, + }, + }, + }, + }, { + State: user.UserState_USER_STATE_ACTIVE, + Type: &user.User_Human{ + Human: &user.HumanUser{ + Profile: &user.HumanProfile{ + GivenName: "Mickey", + FamilyName: "Mouse", + NickName: gu.Ptr("Mickey"), + DisplayName: gu.Ptr("Mickey Mouse"), + PreferredLanguage: gu.Ptr("nl"), + Gender: user.Gender_GENDER_MALE.Enum(), + }, + Email: &user.HumanEmail{ + IsVerified: true, + }, + Phone: &user.HumanPhone{ + Phone: "+41791234567", + IsVerified: true, + }, + }, + }, + }, { + State: user.UserState_USER_STATE_ACTIVE, + Type: &user.User_Human{ + Human: &user.HumanUser{ + Profile: &user.HumanProfile{ + GivenName: "Mickey", + FamilyName: "Mouse", + NickName: gu.Ptr("Mickey"), + DisplayName: gu.Ptr("Mickey Mouse"), + PreferredLanguage: gu.Ptr("nl"), + Gender: user.Gender_GENDER_MALE.Enum(), + }, + Email: &user.HumanEmail{ + IsVerified: true, + }, + Phone: &user.HumanPhone{ + Phone: "+41791234567", + IsVerified: true, + }, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -703,7 +760,7 @@ func TestServer_ListUsers(t *testing.T) { for i := 0; i < tt.args.count; i++ { usernames[i] = fmt.Sprintf("%d%d@mouse.com", time.Now().UnixNano(), i) } - infos, err := tt.args.dep(tt.args.ctx, orgResp.OrganizationId, usernames, tt.args.req) + infos, err := tt.args.dep(tt.args.ctx, usernames, tt.args.req) require.NoError(t, err) retryDuration := time.Minute if ctxDeadline, ok := CTX.Deadline(); ok { @@ -768,3 +825,12 @@ func UsernameQuery(username string) *user.SearchQuery { }, } } + +func OrganizationIdQuery(resourceowner string) *user.SearchQuery { + return &user.SearchQuery{Query: &user.SearchQuery_OrganizationIdQuery{ + OrganizationIdQuery: &user.OrganizationIdQuery{ + OrganizationId: resourceowner, + }, + }, + } +} diff --git a/internal/api/grpc/user/v2/user_integration_test.go b/internal/api/grpc/user/v2/user_integration_test.go index ef1cf9081e..db6bdcdccb 100644 --- a/internal/api/grpc/user/v2/user_integration_test.go +++ b/internal/api/grpc/user/v2/user_integration_test.go @@ -70,8 +70,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -111,8 +111,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -156,8 +156,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -202,8 +202,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -249,8 +249,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -290,8 +290,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -321,8 +321,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -355,8 +355,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -402,8 +402,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -454,8 +454,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -493,8 +493,8 @@ func TestServer_AddHumanUser(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: Tester.Organisation.ID, }, }, @@ -572,8 +572,8 @@ func TestServer_AddHumanUser_Permission(t *testing.T) { args: args{ SystemCTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: newOrg.GetOrganizationId(), }, }, @@ -613,8 +613,8 @@ func TestServer_AddHumanUser_Permission(t *testing.T) { args: args{ IamCTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: newOrg.GetOrganizationId(), }, }, @@ -654,8 +654,8 @@ func TestServer_AddHumanUser_Permission(t *testing.T) { args: args{ CTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: newOrg.GetOrganizationId(), }, }, @@ -690,8 +690,8 @@ func TestServer_AddHumanUser_Permission(t *testing.T) { args: args{ UserCTX, &user.AddHumanUserRequest{ - Organisation: &object.Organisation{ - Org: &object.Organisation_OrgId{ + Organization: &object.Organization{ + Org: &object.Organization_OrgId{ OrgId: newOrg.GetOrganizationId(), }, }, diff --git a/pkg/grpc/user/v2beta/user.go b/pkg/grpc/user/v2beta/user.go index 8309a57f0a..ec9245c8eb 100644 --- a/pkg/grpc/user/v2beta/user.go +++ b/pkg/grpc/user/v2beta/user.go @@ -1,13 +1,3 @@ package user -type SearchQuery_ResourceOwner struct { - ResourceOwner *ResourceOwnerQuery -} - -func (SearchQuery_ResourceOwner) isSearchQuery_Query() {} - -type ResourceOwnerQuery struct { - OrgID string -} - type UserType = isUser_Type diff --git a/pkg/grpc/user/v2beta/user_service_org.pb.zitadel.go b/pkg/grpc/user/v2beta/user_service_org.pb.zitadel.go deleted file mode 100644 index fe2509bd95..0000000000 --- a/pkg/grpc/user/v2beta/user_service_org.pb.zitadel.go +++ /dev/null @@ -1,12 +0,0 @@ -package user - -import "github.com/zitadel/zitadel/internal/api/grpc/server/middleware" - -// OrganisationFromRequest implements deprecated [middleware.OrganisationFromRequest] interface. -// it will be removed before going GA (https://github.com/zitadel/zitadel/issues/6718) -func (r *AddHumanUserRequest) OrganisationFromRequest() *middleware.Organization { - return &middleware.Organization{ - ID: r.GetOrganisation().GetOrgId(), - Domain: r.GetOrganisation().GetOrgDomain(), - } -} diff --git a/proto/zitadel/user/v2beta/query.proto b/proto/zitadel/user/v2beta/query.proto index b6db2bd532..5f42ad7c32 100644 --- a/proto/zitadel/user/v2beta/query.proto +++ b/proto/zitadel/user/v2beta/query.proto @@ -29,9 +29,11 @@ message SearchQuery { AndQuery and_query = 12; NotQuery not_query = 13; InUserEmailsQuery in_user_emails_query = 14; + OrganizationIdQuery organization_id_query = 15; } } +// Connect multiple sub-condition with and OR operator. message OrQuery { repeated SearchQuery queries = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -39,6 +41,8 @@ message OrQuery { } ]; } + +// Connect multiple sub-condition with and AND operator. message AndQuery { repeated SearchQuery queries = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -47,6 +51,7 @@ message AndQuery { ]; } +// Negate the sub-condition. message NotQuery { SearchQuery query = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -55,6 +60,7 @@ message NotQuery { ]; } +// Query for users with ID in list of IDs. message InUserIDQuery { repeated string user_ids = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -64,10 +70,13 @@ message InUserIDQuery { ]; } +// Query for users with a specific user name. message UserNameQuery { string user_name = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; max_length: 200; example: "\"gigi-giraffe\""; } @@ -80,10 +89,13 @@ message UserNameQuery { ]; } +// Query for users with a specific first name. message FirstNameQuery { string first_name = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; max_length: 200; example: "\"Gigi\""; } @@ -96,10 +108,13 @@ message FirstNameQuery { ]; } +// Query for users with a specific last name. message LastNameQuery { string last_name = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; max_length: 200; example: "\"Giraffe\""; } @@ -112,8 +127,17 @@ message LastNameQuery { ]; } +// Query for users with a specific nickname. message NickNameQuery { - string nick_name = 1 [(validate.rules).string = {max_len: 200}]; + string nick_name = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + example: "\"Gigi\""; + } + ]; zitadel.object.v2beta.TextQueryMethod method = 2 [ (validate.rules).enum.defined_only = true, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -122,10 +146,13 @@ message NickNameQuery { ]; } +// Query for users with a specific display name. message DisplayNameQuery { string display_name = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; max_length: 200; example: "\"Gigi Giraffe\""; } @@ -138,11 +165,14 @@ message DisplayNameQuery { ]; } +// Query for users with a specific email. message EmailQuery { string email_address = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200, email: true}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "email address of the user. (spec: https://tools.ietf.org/html/rfc2822#section-3.4.1)" + min_length: 1; max_length: 200; example: "\"gigi@zitadel.com\""; } @@ -155,10 +185,13 @@ message EmailQuery { ]; } +// Query for users with a specific state. message LoginNameQuery { string login_name = 1 [ - (validate.rules).string = {max_len: 200}, + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; max_length: 200; example: "\"gigi@zitadel.cloud\""; } @@ -171,26 +204,29 @@ message LoginNameQuery { ]; } -//UserStateQuery always equals +// Query for users with a specific state. message StateQuery { UserState state = 1 [ (validate.rules).enum.defined_only = true, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "current state of the user"; } ]; } -//UserTypeQuery always equals +// Query for users with a specific type. message TypeQuery { Type type = 1 [ (validate.rules).enum.defined_only = true, + (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "the type of the user"; } ]; } +// Query for users with email in list of emails. message InUserEmailsQuery { repeated string user_emails = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -200,6 +236,19 @@ message InUserEmailsQuery { ]; } +// Query for users under a specific organization as resource owner. +message OrganizationIdQuery { + string organization_id = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + example: "\"69629023906488334\"" + } + ]; +} + enum Type { TYPE_UNSPECIFIED = 0; TYPE_HUMAN = 1; diff --git a/proto/zitadel/user/v2beta/user_service.proto b/proto/zitadel/user/v2beta/user_service.proto index a13e50cfc7..cbf20d6790 100644 --- a/proto/zitadel/user/v2beta/user_service.proto +++ b/proto/zitadel/user/v2beta/user_service.proto @@ -157,7 +157,6 @@ service UserService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { summary: "User by ID"; description: "Returns the full user object (human or machine) including the profile, email, etc." - tags: "Users"; responses: { key: "200" value: { @@ -183,7 +182,6 @@ service UserService { }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - tags: "Users"; summary: "Search Users"; description: "Search for users. By default, we will return users of your organization. Make sure to include a limit and sorting for pagination." responses: { @@ -897,7 +895,9 @@ service UserService { } message AddHumanUserRequest{ - // optionally set your own id unique for the user + reserved 3; + reserved "organisation"; + // optionally set your own id unique for the user. optional string user_id = 1 [ (validate.rules).string = {min_len: 1, max_len: 200}, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -906,7 +906,7 @@ message AddHumanUserRequest{ example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; } ]; - // optionally set a unique username, if none is provided the email will be used + // optionally set a unique username, if none is provided the email will be used. optional string username = 2 [ (validate.rules).string = {min_len: 1, max_len: 200}, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -915,12 +915,6 @@ message AddHumanUserRequest{ example: "\"minnie-mouse\""; } ]; - // deprecated: use organization (if both are set, organization will take precedence) - zitadel.object.v2beta.Organisation organisation = 3 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "deprecated: use organization (if both are set, organization will take precedence)" - } - ]; zitadel.object.v2beta.Organization organization = 11; SetHumanProfile profile = 4 [ (validate.rules).message.required = true, @@ -947,6 +941,8 @@ message AddHumanUserResponse { } message GetUserByIDRequest { + reserved 2; + reserved "organization"; string user_id = 1 [ (validate.rules).string = {min_len: 1, max_len: 200}, (google.api.field_behavior) = REQUIRED, @@ -957,7 +953,6 @@ message GetUserByIDRequest { description: "User ID of the user you like to get." } ]; - zitadel.object.v2beta.Organization organization = 2; } message GetUserByIDResponse {