mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-23 07:52:15 +00:00
feat: project v2beta resource API (#9742)
# Which Problems Are Solved Resource management of projects and sub-resources was before limited by the context provided by the management API, which would mean you could only manage resources belonging to a specific organization. # How the Problems Are Solved With the addition of a resource-based API, it is now possible to manage projects and sub-resources on the basis of the resources themselves, which means that as long as you have the permission for the resource, you can create, read, update and delete it. - CreateProject to create a project under an organization - UpdateProject to update an existing project - DeleteProject to delete an existing project - DeactivateProject and ActivateProject to change the status of a project - GetProject to query for a specific project with an identifier - ListProject to query for projects and granted projects - CreateProjectGrant to create a project grant with project and granted organization - UpdateProjectGrant to update the roles of a project grant - DeactivateProjectGrant and ActivateProjectGrant to change the status of a project grant - DeleteProjectGrant to delete an existing project grant - ListProjectGrants to query for project grants - AddProjectRole to add a role to an existing project - UpdateProjectRole to change texts of an existing role - RemoveProjectRole to remove an existing role - ListProjectRoles to query for project roles # Additional Changes - Changes to ListProjects, which now contains granted projects as well - Changes to messages as defined in the [API_DESIGN](https://github.com/zitadel/zitadel/blob/main/API_DESIGN.md) - Permission checks for project functionality on query and command side - Added testing to unit tests on command side - Change update endpoints to no error returns if nothing changes in the resource - Changed all integration test utility to the new service - ListProjects now also correctly lists `granted projects` - Permission checks for project grant and project role functionality on query and command side - Change existing pre checks so that they also work resource specific without resourceowner - Added the resourceowner to the grant and role if no resourceowner is provided - Corrected import tests with project grants and roles - Added testing to unit tests on command side - Change update endpoints to no error returns if nothing changes in the resource - Changed all integration test utility to the new service - Corrected some naming in the proto files to adhere to the API_DESIGN # Additional Context Closes #9177 --------- Co-authored-by: Livio Spring <[email protected]>
This commit is contained in:
co-authored by
Livio Spring
parent
6889d6a1da
commit
7eb45c6cfd
@@ -46,6 +46,7 @@ import (
|
||||
oidc_v2beta "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2beta"
|
||||
org_v2 "github.com/zitadel/zitadel/internal/api/grpc/org/v2"
|
||||
org_v2beta "github.com/zitadel/zitadel/internal/api/grpc/org/v2beta"
|
||||
project_v2beta "github.com/zitadel/zitadel/internal/api/grpc/project/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/resources/debug_events/debug_events"
|
||||
user_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/user/v3alpha"
|
||||
userschema_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/userschema/v3alpha"
|
||||
@@ -491,6 +492,9 @@ func startAPIs(
|
||||
if err := apis.RegisterService(ctx, action_v2_beta.CreateServer(config.SystemDefaults, commands, queries, domain.AllActionFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, project_v2beta.CreateServer(config.SystemDefaults, commands, queries, permissionCheck)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, userschema_v3_alpha.CreateServer(config.SystemDefaults, commands, queries)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -364,6 +364,14 @@ module.exports = {
|
||||
categoryLinkSource: "auto",
|
||||
},
|
||||
},
|
||||
project_v2beta: {
|
||||
specPath: ".artifacts/openapi/zitadel/project/v2beta/project_service.swagger.json",
|
||||
outputDir: "docs/apis/resources/project_service_v2",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
categoryLinkSource: "auto",
|
||||
},
|
||||
},
|
||||
instance_v2: {
|
||||
specPath: ".artifacts/openapi/zitadel/instance/v2beta/instance_service.swagger.json",
|
||||
outputDir: "docs/apis/resources/instance_service_v2",
|
||||
|
||||
@@ -12,6 +12,7 @@ const sidebar_api_feature_service_v2 = require("./docs/apis/resources/feature_se
|
||||
const sidebar_api_org_service_v2 = require("./docs/apis/resources/org_service_v2/sidebar.ts").default
|
||||
const sidebar_api_idp_service_v2 = require("./docs/apis/resources/idp_service_v2/sidebar.ts").default
|
||||
const sidebar_api_actions_v2 = require("./docs/apis/resources/action_service_v2/sidebar.ts").default
|
||||
const sidebar_api_project_service_v2 = require("./docs/apis/resources/project_service_v2/sidebar.ts").default
|
||||
const sidebar_api_webkey_service_v2 = require("./docs/apis/resources/webkey_service_v2/sidebar.ts").default
|
||||
const sidebar_api_instance_service_v2 = require("./docs/apis/resources/instance_service_v2/sidebar.ts").default
|
||||
|
||||
@@ -843,6 +844,17 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Project (Beta)",
|
||||
link: {
|
||||
type: "generated-index",
|
||||
title: "Project Service API (Beta)",
|
||||
slug: "/apis/resources/project_service_v2",
|
||||
description:
|
||||
"This API is intended to manage projects and subresources for ZITADEL. \n"+
|
||||
"\n" +
|
||||
"This service is in beta state. It can AND will continue breaking until a stable version is released.",
|
||||
},
|
||||
items: sidebar_api_project_service_v2,
|
||||
label: "Instance (Beta)",
|
||||
link: {
|
||||
type: "generated-index",
|
||||
|
||||
@@ -580,7 +580,7 @@ func TestServer_ExecutionTargetPreUserinfo(t *testing.T) {
|
||||
isolatedIAMCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
ctxLoginClient := instance.WithAuthorization(CTX, integration.UserTypeLogin)
|
||||
|
||||
client, err := instance.CreateOIDCImplicitFlowClient(isolatedIAMCtx, redirectURIImplicit, loginV2)
|
||||
client, err := instance.CreateOIDCImplicitFlowClient(isolatedIAMCtx, t, redirectURIImplicit, loginV2)
|
||||
require.NoError(t, err)
|
||||
|
||||
type want struct {
|
||||
@@ -893,7 +893,7 @@ func TestServer_ExecutionTargetPreAccessToken(t *testing.T) {
|
||||
isolatedIAMCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
ctxLoginClient := instance.WithAuthorization(CTX, integration.UserTypeLogin)
|
||||
|
||||
client, err := instance.CreateOIDCImplicitFlowClient(isolatedIAMCtx, redirectURIImplicit, loginV2)
|
||||
client, err := instance.CreateOIDCImplicitFlowClient(isolatedIAMCtx, t, redirectURIImplicit, loginV2)
|
||||
require.NoError(t, err)
|
||||
|
||||
type want struct {
|
||||
@@ -1255,10 +1255,9 @@ func createSAMLSP(t *testing.T, idpMetadata *saml.EntityDescriptor, binding stri
|
||||
}
|
||||
|
||||
func createSAMLApplication(ctx context.Context, t *testing.T, instance *integration.Instance, idpMetadata *saml.EntityDescriptor, binding string, projectRoleCheck, hasProjectCheck bool) (string, string, *samlsp.Middleware) {
|
||||
project, err := instance.CreateProjectWithPermissionCheck(ctx, projectRoleCheck, hasProjectCheck)
|
||||
require.NoError(t, err)
|
||||
project := instance.CreateProject(ctx, t, instance.DefaultOrg.GetId(), gofakeit.AppName(), projectRoleCheck, hasProjectCheck)
|
||||
rootURL, sp := createSAMLSP(t, idpMetadata, binding)
|
||||
_, err = instance.CreateSAMLClient(ctx, project.GetId(), sp)
|
||||
_, err := instance.CreateSAMLClient(ctx, project.GetId(), sp)
|
||||
require.NoError(t, err)
|
||||
return project.GetId(), rootURL, sp
|
||||
}
|
||||
|
||||
@@ -736,7 +736,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
queriedProjects, err := s.query.SearchProjects(ctx, &query.ProjectSearchQueries{Queries: []query.SearchQuery{projectSearch}})
|
||||
queriedProjects, err := s.query.SearchProjects(ctx, &query.ProjectSearchQueries{Queries: []query.SearchQuery{projectSearch}}, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
@@ -763,7 +763,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
queriedProjectRoles, err := s.query.SearchProjectRoles(ctx, false, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectRoleSearch}})
|
||||
queriedProjectRoles, err := s.query.SearchProjectRoles(ctx, false, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectRoleSearch}}, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, err
|
||||
}
|
||||
@@ -945,7 +945,7 @@ func (s *Server) getNecessaryProjectGrantsForOrg(ctx context.Context, org string
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queriedProjectGrants, err := s.query.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectGrantSearchOrg}})
|
||||
queriedProjectGrants, err := s.query.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectGrantSearchOrg}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -621,7 +621,7 @@ func importProjects(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDa
|
||||
}
|
||||
for _, project := range org.GetProjects() {
|
||||
logging.Debugf("import project: %s", project.GetProjectId())
|
||||
_, err := s.command.AddProjectWithID(ctx, management.ProjectCreateToDomain(project.GetProject()), org.GetOrgId(), project.GetProjectId())
|
||||
_, err := s.command.AddProject(ctx, management.ProjectCreateToCommand(project.GetProject(), project.GetProjectId(), org.GetOrgId()))
|
||||
if err != nil {
|
||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "project", Id: project.GetProjectId(), Message: err.Error()})
|
||||
if isCtxTimeout(ctx) {
|
||||
@@ -761,7 +761,7 @@ func importProjectRoles(ctx context.Context, s *Server, errors *[]*admin_pb.Impo
|
||||
logging.Debugf("import projectroles: %s", role.ProjectId+"_"+role.RoleKey)
|
||||
|
||||
// TBD: why not command.BulkAddProjectRole?
|
||||
_, err := s.command.AddProjectRole(ctx, management.AddProjectRoleRequestToDomain(role), org.GetOrgId())
|
||||
_, err := s.command.AddProjectRole(ctx, management.AddProjectRoleRequestToCommand(role, org.GetOrgId()))
|
||||
if err != nil {
|
||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "project_role", Id: role.ProjectId + "_" + role.RoleKey, Message: err.Error()})
|
||||
if isCtxTimeout(ctx) {
|
||||
@@ -1023,7 +1023,7 @@ func importOrg2(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataEr
|
||||
if org.ProjectGrants != nil {
|
||||
for _, grant := range org.GetProjectGrants() {
|
||||
logging.Debugf("import projectgrant: %s", grant.GetGrantId()+"_"+grant.GetProjectGrant().GetProjectId()+"_"+grant.GetProjectGrant().GetGrantedOrgId())
|
||||
_, err := s.command.AddProjectGrantWithID(ctx, management.AddProjectGrantRequestToDomain(grant.GetProjectGrant()), grant.GetGrantId(), org.GetOrgId())
|
||||
_, err := s.command.AddProjectGrant(ctx, management.AddProjectGrantRequestToCommand(grant.GetProjectGrant(), grant.GetGrantId(), org.GetOrgId()))
|
||||
if err != nil {
|
||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "project_grant", Id: org.GetOrgId() + "_" + grant.GetProjectGrant().GetProjectId() + "_" + grant.GetProjectGrant().GetGrantedOrgId(), Message: err.Error()})
|
||||
if isCtxTimeout(ctx) {
|
||||
|
||||
@@ -259,6 +259,12 @@ func TestServer_ImportData(t *testing.T) {
|
||||
Data: &admin.ImportDataRequest_DataOrgs{
|
||||
DataOrgs: &admin.ImportDataOrg{
|
||||
Orgs: []*admin.DataOrg{
|
||||
{
|
||||
OrgId: orgIDs[4],
|
||||
Org: &management.AddOrgRequest{
|
||||
Name: gofakeit.ProductName(),
|
||||
},
|
||||
},
|
||||
{
|
||||
OrgId: orgIDs[3],
|
||||
Org: &management.AddOrgRequest{
|
||||
@@ -336,6 +342,9 @@ func TestServer_ImportData(t *testing.T) {
|
||||
},
|
||||
Success: &admin.ImportDataSuccess{
|
||||
Orgs: []*admin.ImportDataSuccessOrg{
|
||||
{
|
||||
OrgId: orgIDs[4],
|
||||
},
|
||||
{
|
||||
OrgId: orgIDs[3],
|
||||
ProjectIds: projectIDs[2:4],
|
||||
@@ -363,6 +372,12 @@ func TestServer_ImportData(t *testing.T) {
|
||||
Data: &admin.ImportDataRequest_DataOrgs{
|
||||
DataOrgs: &admin.ImportDataOrg{
|
||||
Orgs: []*admin.DataOrg{
|
||||
{
|
||||
OrgId: orgIDs[6],
|
||||
Org: &management.AddOrgRequest{
|
||||
Name: gofakeit.ProductName(),
|
||||
},
|
||||
},
|
||||
{
|
||||
OrgId: orgIDs[5],
|
||||
Org: &management.AddOrgRequest{
|
||||
@@ -383,6 +398,11 @@ func TestServer_ImportData(t *testing.T) {
|
||||
RoleKey: "role1",
|
||||
DisplayName: "role1",
|
||||
},
|
||||
{
|
||||
ProjectId: projectIDs[4],
|
||||
RoleKey: "role2",
|
||||
DisplayName: "role2",
|
||||
},
|
||||
},
|
||||
HumanUsers: []*v1.DataHumanUser{
|
||||
{
|
||||
@@ -442,11 +462,15 @@ func TestServer_ImportData(t *testing.T) {
|
||||
},
|
||||
Success: &admin.ImportDataSuccess{
|
||||
Orgs: []*admin.ImportDataSuccessOrg{
|
||||
{
|
||||
OrgId: orgIDs[6],
|
||||
},
|
||||
{
|
||||
OrgId: orgIDs[5],
|
||||
ProjectIds: projectIDs[4:5],
|
||||
ProjectRoles: []string{
|
||||
projectIDs[4] + "_role1",
|
||||
projectIDs[4] + "_role2",
|
||||
},
|
||||
HumanUserIds: userIDs[2:3],
|
||||
ProjectGrants: []*admin.ImportDataSuccessProjectGrant{
|
||||
|
||||
@@ -47,7 +47,7 @@ func (s *Server) ListProjects(ctx context.Context, req *mgmt_pb.ListProjectsRequ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projects, err := s.query.SearchProjects(ctx, queries)
|
||||
projects, err := s.query.SearchProjects(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (s *Server) ListGrantedProjects(ctx context.Context, req *mgmt_pb.ListGrant
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projects, err := s.query.SearchProjectGrants(ctx, queries)
|
||||
projects, err := s.query.SearchProjectGrants(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -175,25 +175,26 @@ func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjec
|
||||
}
|
||||
|
||||
func (s *Server) AddProject(ctx context.Context, req *mgmt_pb.AddProjectRequest) (*mgmt_pb.AddProjectResponse, error) {
|
||||
project, err := s.command.AddProject(ctx, ProjectCreateToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||
add := ProjectCreateToCommand(req, "", authz.GetCtxData(ctx).OrgID)
|
||||
project, err := s.command.AddProject(ctx, add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddProjectResponse{
|
||||
Id: project.AggregateID,
|
||||
Details: object_grpc.AddToDetailsPb(project.Sequence, project.ChangeDate, project.ResourceOwner),
|
||||
Id: add.AggregateID,
|
||||
Details: object_grpc.AddToDetailsPb(project.Sequence, project.EventDate, project.ResourceOwner),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateProject(ctx context.Context, req *mgmt_pb.UpdateProjectRequest) (*mgmt_pb.UpdateProjectResponse, error) {
|
||||
project, err := s.command.ChangeProject(ctx, ProjectUpdateToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||
project, err := s.command.ChangeProject(ctx, ProjectUpdateToCommand(req, authz.GetCtxData(ctx).OrgID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateProjectResponse{
|
||||
Details: object_grpc.ChangeToDetailsPb(
|
||||
project.Sequence,
|
||||
project.ChangeDate,
|
||||
project.EventDate,
|
||||
project.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
@@ -252,7 +253,7 @@ func (s *Server) ListProjectRoles(ctx context.Context, req *mgmt_pb.ListProjectR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roles, err := s.query.SearchProjectRoles(ctx, true, queries)
|
||||
roles, err := s.query.SearchProjectRoles(ctx, true, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -263,21 +264,21 @@ func (s *Server) ListProjectRoles(ctx context.Context, req *mgmt_pb.ListProjectR
|
||||
}
|
||||
|
||||
func (s *Server) AddProjectRole(ctx context.Context, req *mgmt_pb.AddProjectRoleRequest) (*mgmt_pb.AddProjectRoleResponse, error) {
|
||||
role, err := s.command.AddProjectRole(ctx, AddProjectRoleRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||
role, err := s.command.AddProjectRole(ctx, AddProjectRoleRequestToCommand(req, authz.GetCtxData(ctx).OrgID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddProjectRoleResponse{
|
||||
Details: object_grpc.AddToDetailsPb(
|
||||
role.Sequence,
|
||||
role.ChangeDate,
|
||||
role.EventDate,
|
||||
role.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) BulkAddProjectRoles(ctx context.Context, req *mgmt_pb.BulkAddProjectRolesRequest) (*mgmt_pb.BulkAddProjectRolesResponse, error) {
|
||||
details, err := s.command.BulkAddProjectRole(ctx, req.ProjectId, authz.GetCtxData(ctx).OrgID, BulkAddProjectRolesRequestToDomain(req))
|
||||
details, err := s.command.BulkAddProjectRole(ctx, req.ProjectId, authz.GetCtxData(ctx).OrgID, BulkAddProjectRolesRequestToCommand(req, authz.GetCtxData(ctx).OrgID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -287,14 +288,14 @@ func (s *Server) BulkAddProjectRoles(ctx context.Context, req *mgmt_pb.BulkAddPr
|
||||
}
|
||||
|
||||
func (s *Server) UpdateProjectRole(ctx context.Context, req *mgmt_pb.UpdateProjectRoleRequest) (*mgmt_pb.UpdateProjectRoleResponse, error) {
|
||||
role, err := s.command.ChangeProjectRole(ctx, UpdateProjectRoleRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||
role, err := s.command.ChangeProjectRole(ctx, UpdateProjectRoleRequestToCommand(req, authz.GetCtxData(ctx).OrgID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateProjectRoleResponse{
|
||||
Details: object_grpc.ChangeToDetailsPb(
|
||||
role.Sequence,
|
||||
role.ChangeDate,
|
||||
role.EventDate,
|
||||
role.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
|
||||
@@ -3,10 +3,13 @@ package management
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
member_grpc "github.com/zitadel/zitadel/internal/api/grpc/member"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
proj_grpc "github.com/zitadel/zitadel/internal/api/grpc/project"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@@ -14,8 +17,12 @@ import (
|
||||
proj_pb "github.com/zitadel/zitadel/pkg/grpc/project"
|
||||
)
|
||||
|
||||
func ProjectCreateToDomain(req *mgmt_pb.AddProjectRequest) *domain.Project {
|
||||
return &domain.Project{
|
||||
func ProjectCreateToCommand(req *mgmt_pb.AddProjectRequest, projectID string, resourceOwner string) *command.AddProject {
|
||||
return &command.AddProject{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Name: req.Name,
|
||||
ProjectRoleAssertion: req.ProjectRoleAssertion,
|
||||
ProjectRoleCheck: req.ProjectRoleCheck,
|
||||
@@ -24,16 +31,17 @@ func ProjectCreateToDomain(req *mgmt_pb.AddProjectRequest) *domain.Project {
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectUpdateToDomain(req *mgmt_pb.UpdateProjectRequest) *domain.Project {
|
||||
return &domain.Project{
|
||||
func ProjectUpdateToCommand(req *mgmt_pb.UpdateProjectRequest, resourceOwner string) *command.ChangeProject {
|
||||
return &command.ChangeProject{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.Id,
|
||||
AggregateID: req.Id,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Name: req.Name,
|
||||
ProjectRoleAssertion: req.ProjectRoleAssertion,
|
||||
ProjectRoleCheck: req.ProjectRoleCheck,
|
||||
HasProjectCheck: req.HasProjectCheck,
|
||||
PrivateLabelingSetting: privateLabelingSettingToDomain(req.PrivateLabelingSetting),
|
||||
Name: gu.Ptr(req.Name),
|
||||
ProjectRoleAssertion: gu.Ptr(req.ProjectRoleAssertion),
|
||||
ProjectRoleCheck: gu.Ptr(req.ProjectRoleCheck),
|
||||
HasProjectCheck: gu.Ptr(req.HasProjectCheck),
|
||||
PrivateLabelingSetting: gu.Ptr(privateLabelingSettingToDomain(req.PrivateLabelingSetting)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,10 +56,11 @@ func privateLabelingSettingToDomain(setting proj_pb.PrivateLabelingSetting) doma
|
||||
}
|
||||
}
|
||||
|
||||
func AddProjectRoleRequestToDomain(req *mgmt_pb.AddProjectRoleRequest) *domain.ProjectRole {
|
||||
return &domain.ProjectRole{
|
||||
func AddProjectRoleRequestToCommand(req *mgmt_pb.AddProjectRoleRequest, resourceOwner string) *command.AddProjectRole {
|
||||
return &command.AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
AggregateID: req.ProjectId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Key: req.RoleKey,
|
||||
DisplayName: req.DisplayName,
|
||||
@@ -59,12 +68,13 @@ func AddProjectRoleRequestToDomain(req *mgmt_pb.AddProjectRoleRequest) *domain.P
|
||||
}
|
||||
}
|
||||
|
||||
func BulkAddProjectRolesRequestToDomain(req *mgmt_pb.BulkAddProjectRolesRequest) []*domain.ProjectRole {
|
||||
roles := make([]*domain.ProjectRole, len(req.Roles))
|
||||
func BulkAddProjectRolesRequestToCommand(req *mgmt_pb.BulkAddProjectRolesRequest, resourceOwner string) []*command.AddProjectRole {
|
||||
roles := make([]*command.AddProjectRole, len(req.Roles))
|
||||
for i, role := range req.Roles {
|
||||
roles[i] = &domain.ProjectRole{
|
||||
roles[i] = &command.AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
AggregateID: req.ProjectId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Key: role.Key,
|
||||
DisplayName: role.DisplayName,
|
||||
@@ -74,10 +84,11 @@ func BulkAddProjectRolesRequestToDomain(req *mgmt_pb.BulkAddProjectRolesRequest)
|
||||
return roles
|
||||
}
|
||||
|
||||
func UpdateProjectRoleRequestToDomain(req *mgmt_pb.UpdateProjectRoleRequest) *domain.ProjectRole {
|
||||
return &domain.ProjectRole{
|
||||
func UpdateProjectRoleRequestToCommand(req *mgmt_pb.UpdateProjectRoleRequest, resourceOwner string) *command.ChangeProjectRole {
|
||||
return &command.ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
AggregateID: req.ProjectId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Key: req.RoleKey,
|
||||
DisplayName: req.DisplayName,
|
||||
|
||||
@@ -31,7 +31,7 @@ func (s *Server) ListProjectGrants(ctx context.Context, req *mgmt_pb.ListProject
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grants, err := s.query.SearchProjectGrants(ctx, queries)
|
||||
grants, err := s.query.SearchProjectGrants(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (s *Server) ListAllProjectGrants(ctx context.Context, req *mgmt_pb.ListAllP
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grants, err := s.query.SearchProjectGrants(ctx, queries)
|
||||
grants, err := s.query.SearchProjectGrants(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,16 +65,17 @@ func (s *Server) ListAllProjectGrants(ctx context.Context, req *mgmt_pb.ListAllP
|
||||
}
|
||||
|
||||
func (s *Server) AddProjectGrant(ctx context.Context, req *mgmt_pb.AddProjectGrantRequest) (*mgmt_pb.AddProjectGrantResponse, error) {
|
||||
grant, err := s.command.AddProjectGrant(ctx, AddProjectGrantRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||
grant := AddProjectGrantRequestToCommand(req, "", authz.GetCtxData(ctx).OrgID)
|
||||
details, err := s.command.AddProjectGrant(ctx, grant)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddProjectGrantResponse{
|
||||
GrantId: grant.GrantID,
|
||||
Details: object_grpc.AddToDetailsPb(
|
||||
grant.Sequence,
|
||||
grant.ChangeDate,
|
||||
grant.ResourceOwner,
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
@@ -94,14 +95,14 @@ func (s *Server) UpdateProjectGrant(ctx context.Context, req *mgmt_pb.UpdateProj
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant, err := s.command.ChangeProjectGrant(ctx, UpdateProjectGrantRequestToDomain(req), authz.GetCtxData(ctx).OrgID, userGrantsToIDs(grants.UserGrants)...)
|
||||
grant, err := s.command.ChangeProjectGrant(ctx, UpdateProjectGrantRequestToCommand(req, authz.GetCtxData(ctx).OrgID), userGrantsToIDs(grants.UserGrants)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateProjectGrantResponse{
|
||||
Details: object_grpc.ChangeToDetailsPb(
|
||||
grant.Sequence,
|
||||
grant.ChangeDate,
|
||||
grant.EventDate,
|
||||
grant.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
member_grpc "github.com/zitadel/zitadel/internal/api/grpc/member"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@@ -100,20 +101,23 @@ func AllProjectGrantQueryToModel(apiQuery *proj_pb.AllProjectGrantQuery) (query.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-M099f", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
func AddProjectGrantRequestToDomain(req *mgmt_pb.AddProjectGrantRequest) *domain.ProjectGrant {
|
||||
return &domain.ProjectGrant{
|
||||
func AddProjectGrantRequestToCommand(req *mgmt_pb.AddProjectGrantRequest, grantID string, resourceOwner string) *command.AddProjectGrant {
|
||||
return &command.AddProjectGrant{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
AggregateID: req.ProjectId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
GrantID: grantID,
|
||||
GrantedOrgID: req.GrantedOrgId,
|
||||
RoleKeys: req.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateProjectGrantRequestToDomain(req *mgmt_pb.UpdateProjectGrantRequest) *domain.ProjectGrant {
|
||||
return &domain.ProjectGrant{
|
||||
func UpdateProjectGrantRequestToCommand(req *mgmt_pb.UpdateProjectGrantRequest, resourceOwner string) *command.ChangeProjectGrant {
|
||||
return &command.ChangeProjectGrant{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
AggregateID: req.ProjectId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
GrantID: req.GrantId,
|
||||
RoleKeys: req.RoleKeys,
|
||||
|
||||
@@ -24,8 +24,7 @@ import (
|
||||
)
|
||||
|
||||
func TestServer_GetAuthRequest(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -98,8 +97,7 @@ func TestServer_GetAuthRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_CreateCallback(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||
require.NoError(t, err)
|
||||
clientV2, err := Instance.CreateOIDCClientLoginVersion(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, loginV2)
|
||||
@@ -288,7 +286,7 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
ctx: CTX,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
client, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, nil)
|
||||
client, err := Instance.CreateOIDCImplicitFlowClient(CTX, t, redirectURIImplicit, nil)
|
||||
require.NoError(t, err)
|
||||
authRequestID, err := Instance.CreateOIDCAuthRequestImplicit(CTX, client.GetClientId(), Instance.Users.Get(integration.UserTypeOrgOwner).ID, redirectURIImplicit)
|
||||
require.NoError(t, err)
|
||||
@@ -315,7 +313,7 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
clientV2, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, loginV2)
|
||||
clientV2, err := Instance.CreateOIDCImplicitFlowClient(CTX, t, redirectURIImplicit, loginV2)
|
||||
require.NoError(t, err)
|
||||
authRequestID, err := Instance.CreateOIDCAuthRequestImplicitWithoutLoginClientHeader(CTX, clientV2.GetClientId(), redirectURIImplicit)
|
||||
require.NoError(t, err)
|
||||
@@ -371,7 +369,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID2, _ := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID2, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID2, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -386,7 +384,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -407,9 +405,9 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
@@ -544,9 +542,9 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
want: &oidc_pb.CreateCallbackResponse{
|
||||
@@ -564,7 +562,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
@@ -606,7 +604,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, false, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
@@ -639,8 +637,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_GetDeviceAuthorizationRequest(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, app.OIDCGrantType_OIDC_GRANT_TYPE_DEVICE_CODE)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -697,8 +694,7 @@ func TestServer_GetDeviceAuthorizationRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, app.OIDCGrantType_OIDC_GRANT_TYPE_DEVICE_CODE)
|
||||
require.NoError(t, err)
|
||||
sessionResp := createSession(t, CTX, Instance.Users[integration.UserTypeOrgOwner].ID)
|
||||
@@ -895,8 +891,7 @@ func createSessionAndAuthRequestForCallback(ctx context.Context, t *testing.T, c
|
||||
}
|
||||
|
||||
func createOIDCApplication(ctx context.Context, t *testing.T, projectRoleCheck, hasProjectCheck bool) (string, string) {
|
||||
project, err := Instance.CreateProjectWithPermissionCheck(ctx, projectRoleCheck, hasProjectCheck)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(ctx, t, "", gofakeit.AppName(), projectRoleCheck, hasProjectCheck)
|
||||
clientV2, err := Instance.CreateOIDCClientLoginVersion(ctx, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, loginV2)
|
||||
require.NoError(t, err)
|
||||
return project.GetId(), clientV2.GetClientId()
|
||||
|
||||
@@ -23,8 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestServer_GetAuthRequest(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -97,8 +96,7 @@ func TestServer_GetAuthRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_CreateCallback(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||
require.NoError(t, err)
|
||||
clientV2, err := Instance.CreateOIDCClientLoginVersion(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, loginV2)
|
||||
@@ -289,7 +287,7 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
ctx: CTX,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
client, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, nil)
|
||||
client, err := Instance.CreateOIDCImplicitFlowClient(CTX, t, redirectURIImplicit, nil)
|
||||
require.NoError(t, err)
|
||||
authRequestID, err := Instance.CreateOIDCAuthRequestImplicit(CTX, client.GetClientId(), Instance.Users.Get(integration.UserTypeOrgOwner).ID, redirectURIImplicit)
|
||||
require.NoError(t, err)
|
||||
@@ -316,7 +314,7 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
clientV2, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, loginV2)
|
||||
clientV2, err := Instance.CreateOIDCImplicitFlowClient(CTX, t, redirectURIImplicit, loginV2)
|
||||
require.NoError(t, err)
|
||||
authRequestID, err := Instance.CreateOIDCAuthRequestImplicitWithoutLoginClientHeader(CTX, clientV2.GetClientId(), redirectURIImplicit)
|
||||
require.NoError(t, err)
|
||||
@@ -372,7 +370,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID2, _ := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID2, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID2, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -387,7 +385,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -408,9 +406,9 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
@@ -545,9 +543,9 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
want: &oidc_pb.CreateCallbackResponse{
|
||||
@@ -565,7 +563,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
},
|
||||
@@ -607,7 +605,7 @@ func TestServer_CreateCallback_Permission(t *testing.T) {
|
||||
projectID, clientID := createOIDCApplication(ctx, t, false, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "oidc-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
|
||||
return createSessionAndAuthRequestForCallback(ctx, t, clientID, Instance.Users.Get(integration.UserTypeOrgOwner).ID, user.GetUserId())
|
||||
@@ -669,8 +667,7 @@ func createSessionAndAuthRequestForCallback(ctx context.Context, t *testing.T, c
|
||||
}
|
||||
|
||||
func createOIDCApplication(ctx context.Context, t *testing.T, projectRoleCheck, hasProjectCheck bool) (string, string) {
|
||||
project, err := Instance.CreateProjectWithPermissionCheck(ctx, projectRoleCheck, hasProjectCheck)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(ctx, t, "", gofakeit.AppName(), projectRoleCheck, hasProjectCheck)
|
||||
clientV2, err := Instance.CreateOIDCClientLoginVersion(ctx, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, loginV2)
|
||||
require.NoError(t, err)
|
||||
return project.GetId(), clientV2.GetClientId()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,698 @@
|
||||
//go:build integration
|
||||
|
||||
package project_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
project "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func TestServer_AddProjectRole(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
alreadyExistingProject := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
alreadyExistingProjectRoleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, alreadyExistingProject.GetId(), alreadyExistingProjectRoleName, alreadyExistingProjectRoleName, "")
|
||||
|
||||
type want struct {
|
||||
creationDate bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
prepare func(request *project.AddProjectRoleRequest)
|
||||
req *project.AddProjectRoleRequest
|
||||
want
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty key",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: "",
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty displayname",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: "",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "already existing, error",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
request.ProjectId = alreadyExistingProject.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: alreadyExistingProjectRoleName,
|
||||
DisplayName: alreadyExistingProjectRoleName,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty, ok",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.Name(),
|
||||
DisplayName: gofakeit.Name(),
|
||||
},
|
||||
want: want{
|
||||
creationDate: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.prepare != nil {
|
||||
tt.prepare(tt.req)
|
||||
}
|
||||
|
||||
creationDate := time.Now().UTC()
|
||||
got, err := instance.Client.Projectv2Beta.AddProjectRole(tt.ctx, tt.req)
|
||||
changeDate := time.Now().UTC()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertAddProjectRoleResponse(t, creationDate, changeDate, tt.want.creationDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_AddProjectRole_Permission(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
alreadyExistingProject := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
alreadyExistingProjectRoleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, alreadyExistingProject.GetId(), alreadyExistingProjectRoleName, alreadyExistingProjectRoleName, "")
|
||||
|
||||
type want struct {
|
||||
creationDate bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
prepare func(request *project.AddProjectRoleRequest)
|
||||
req *project.AddProjectRoleRequest
|
||||
want
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "unauthenticated",
|
||||
ctx: CTX,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no permission",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeNoPermission),
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, other org",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, ok",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, instance.DefaultOrg.GetId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
want: want{
|
||||
creationDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance owner, ok",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.AddProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
request.ProjectId = projectResp.GetId()
|
||||
},
|
||||
req: &project.AddProjectRoleRequest{
|
||||
RoleKey: gofakeit.AppName(),
|
||||
DisplayName: gofakeit.AppName(),
|
||||
},
|
||||
want: want{
|
||||
creationDate: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.prepare != nil {
|
||||
tt.prepare(tt.req)
|
||||
}
|
||||
|
||||
creationDate := time.Now().UTC()
|
||||
got, err := instance.Client.Projectv2Beta.AddProjectRole(tt.ctx, tt.req)
|
||||
changeDate := time.Now().UTC()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertAddProjectRoleResponse(t, creationDate, changeDate, tt.want.creationDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertAddProjectRoleResponse(t *testing.T, creationDate, changeDate time.Time, expectedCreationDate bool, actualResp *project.AddProjectRoleResponse) {
|
||||
if expectedCreationDate {
|
||||
if !changeDate.IsZero() {
|
||||
assert.WithinRange(t, actualResp.GetCreationDate().AsTime(), creationDate, changeDate)
|
||||
} else {
|
||||
assert.WithinRange(t, actualResp.GetCreationDate().AsTime(), creationDate, time.Now().UTC())
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, actualResp.CreationDate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UpdateProjectRole(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *project.UpdateProjectRoleRequest
|
||||
}
|
||||
type want struct {
|
||||
change bool
|
||||
changeDate bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare func(request *project.UpdateProjectRoleRequest)
|
||||
args args
|
||||
want want
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeNoPermission),
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not existing",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
request.RoleKey = "notexisting"
|
||||
return
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no change, ok",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
request.DisplayName = gu.Ptr(roleName)
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.UpdateProjectRoleRequest{},
|
||||
},
|
||||
want: want{
|
||||
change: false,
|
||||
changeDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change display name, ok",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr(gofakeit.AppName()),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
change: true,
|
||||
changeDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change full, ok",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr(gofakeit.AppName()),
|
||||
Group: gu.Ptr(gofakeit.AppName()),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
change: true,
|
||||
changeDate: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
got, err := instance.Client.Projectv2Beta.UpdateProjectRole(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
changeDate := time.Time{}
|
||||
if tt.want.change {
|
||||
changeDate = time.Now().UTC()
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertUpdateProjectRoleResponse(t, creationDate, changeDate, tt.want.changeDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UpdateProjectRole_Permission(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *project.UpdateProjectRoleRequest
|
||||
}
|
||||
type want struct {
|
||||
change bool
|
||||
changeDate bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare func(request *project.UpdateProjectRoleRequest)
|
||||
args args
|
||||
want want
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "unauthenicated",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no permission",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeNoPermission),
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, other org",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr("changed"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, ok",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, instance.DefaultOrg.GetId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr(gofakeit.AppName()),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
change: true,
|
||||
changeDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance owner, ok",
|
||||
prepare: func(request *project.UpdateProjectRoleRequest) {
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.UpdateProjectRoleRequest{
|
||||
DisplayName: gu.Ptr(gofakeit.AppName()),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
change: true,
|
||||
changeDate: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
got, err := instance.Client.Projectv2Beta.UpdateProjectRole(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
changeDate := time.Time{}
|
||||
if tt.want.change {
|
||||
changeDate = time.Now().UTC()
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertUpdateProjectRoleResponse(t, creationDate, changeDate, tt.want.changeDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertUpdateProjectRoleResponse(t *testing.T, creationDate, changeDate time.Time, expectedChangeDate bool, actualResp *project.UpdateProjectRoleResponse) {
|
||||
if expectedChangeDate {
|
||||
if !changeDate.IsZero() {
|
||||
assert.WithinRange(t, actualResp.GetChangeDate().AsTime(), creationDate, changeDate)
|
||||
} else {
|
||||
assert.WithinRange(t, actualResp.GetChangeDate().AsTime(), creationDate, time.Now().UTC())
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, actualResp.ChangeDate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteProjectRole(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
prepare func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time)
|
||||
req *project.RemoveProjectRoleRequest
|
||||
wantDeletionDate bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty id",
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.RemoveProjectRoleRequest{
|
||||
ProjectId: "",
|
||||
RoleKey: "notexisting",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "delete, not existing",
|
||||
ctx: iamOwnerCtx,
|
||||
req: &project.RemoveProjectRoleRequest{
|
||||
ProjectId: "notexisting",
|
||||
RoleKey: "notexisting",
|
||||
},
|
||||
wantDeletionDate: false,
|
||||
},
|
||||
{
|
||||
name: "delete",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantDeletionDate: true,
|
||||
},
|
||||
{
|
||||
name: "delete, already removed",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
instance.RemoveProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName)
|
||||
return creationDate, time.Now().UTC()
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantDeletionDate: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var creationDate, deletionDate time.Time
|
||||
if tt.prepare != nil {
|
||||
creationDate, deletionDate = tt.prepare(tt.req)
|
||||
}
|
||||
got, err := instance.Client.Projectv2Beta.RemoveProjectRole(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertRemoveProjectRoleResponse(t, creationDate, deletionDate, tt.wantDeletionDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteProjectRole_Permission(t *testing.T) {
|
||||
iamOwnerCtx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, gofakeit.AppName(), gofakeit.Email())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
prepare func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time)
|
||||
req *project.RemoveProjectRoleRequest
|
||||
wantDeletionDate bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "unauthenticated",
|
||||
ctx: CTX,
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no permission",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeNoPermission),
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, other org",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "organization owner, ok",
|
||||
ctx: instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, instance.DefaultOrg.GetId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantDeletionDate: true,
|
||||
},
|
||||
{
|
||||
name: "instance owner, ok",
|
||||
ctx: iamOwnerCtx,
|
||||
prepare: func(request *project.RemoveProjectRoleRequest) (time.Time, time.Time) {
|
||||
creationDate := time.Now().UTC()
|
||||
projectResp := instance.CreateProject(iamOwnerCtx, t, orgResp.GetOrganizationId(), gofakeit.AppName(), false, false)
|
||||
roleName := gofakeit.AppName()
|
||||
instance.AddProjectRole(iamOwnerCtx, t, projectResp.GetId(), roleName, roleName, "")
|
||||
request.ProjectId = projectResp.GetId()
|
||||
request.RoleKey = roleName
|
||||
return creationDate, time.Time{}
|
||||
},
|
||||
req: &project.RemoveProjectRoleRequest{},
|
||||
wantDeletionDate: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var creationDate, deletionDate time.Time
|
||||
if tt.prepare != nil {
|
||||
creationDate, deletionDate = tt.prepare(tt.req)
|
||||
}
|
||||
got, err := instance.Client.Projectv2Beta.RemoveProjectRole(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assertRemoveProjectRoleResponse(t, creationDate, deletionDate, tt.wantDeletionDate, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertRemoveProjectRoleResponse(t *testing.T, creationDate, deletionDate time.Time, expectedDeletionDate bool, actualResp *project.RemoveProjectRoleResponse) {
|
||||
if expectedDeletionDate {
|
||||
if !deletionDate.IsZero() {
|
||||
assert.WithinRange(t, actualResp.GetRemovalDate().AsTime(), creationDate, deletionDate)
|
||||
} else {
|
||||
assert.WithinRange(t, actualResp.GetRemovalDate().AsTime(), creationDate, time.Now().UTC())
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, actualResp.RemovalDate)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
//go:build integration
|
||||
|
||||
package project_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
CTX context.Context
|
||||
instance *integration.Instance
|
||||
instancePermissionV2 *integration.Instance
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
|
||||
defer cancel()
|
||||
CTX = ctx
|
||||
instance = integration.NewInstance(ctx)
|
||||
instancePermissionV2 = integration.NewInstance(CTX)
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
||||
|
||||
func ensureFeaturePermissionV2Enabled(t *testing.T, instance *integration.Instance) {
|
||||
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
if f.PermissionCheckV2.GetEnabled() {
|
||||
return
|
||||
}
|
||||
_, err = instance.Client.FeatureV2.SetInstanceFeatures(ctx, &feature.SetInstanceFeaturesRequest{
|
||||
PermissionCheckV2: gu.Ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(ctx, 5*time.Minute)
|
||||
require.EventuallyWithT(t,
|
||||
func(ttt *assert.CollectT) {
|
||||
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
assert.NoError(ttt, err)
|
||||
if f.PermissionCheckV2.GetEnabled() {
|
||||
return
|
||||
}
|
||||
},
|
||||
retryDuration,
|
||||
tick,
|
||||
"timed out waiting for ensuring instance feature")
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) CreateProject(ctx context.Context, req *project_pb.CreateProjectRequest) (*project_pb.CreateProjectResponse, error) {
|
||||
add := projectCreateToCommand(req)
|
||||
project, err := s.command.AddProject(ctx, add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var creationDate *timestamppb.Timestamp
|
||||
if !project.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.CreateProjectResponse{
|
||||
Id: add.AggregateID,
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectCreateToCommand(req *project_pb.CreateProjectRequest) *command.AddProject {
|
||||
var aggregateID string
|
||||
if req.Id != nil {
|
||||
aggregateID = *req.Id
|
||||
}
|
||||
return &command.AddProject{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
ResourceOwner: req.OrganizationId,
|
||||
AggregateID: aggregateID,
|
||||
},
|
||||
Name: req.Name,
|
||||
ProjectRoleAssertion: req.ProjectRoleAssertion,
|
||||
ProjectRoleCheck: req.AuthorizationRequired,
|
||||
HasProjectCheck: req.ProjectAccessRequired,
|
||||
PrivateLabelingSetting: privateLabelingSettingToDomain(req.PrivateLabelingSetting),
|
||||
}
|
||||
}
|
||||
|
||||
func privateLabelingSettingToDomain(setting project_pb.PrivateLabelingSetting) domain.PrivateLabelingSetting {
|
||||
switch setting {
|
||||
case project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_ALLOW_LOGIN_USER_RESOURCE_OWNER_POLICY:
|
||||
return domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy
|
||||
case project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_ENFORCE_PROJECT_RESOURCE_OWNER_POLICY:
|
||||
return domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy
|
||||
case project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_UNSPECIFIED:
|
||||
return domain.PrivateLabelingSettingUnspecified
|
||||
default:
|
||||
return domain.PrivateLabelingSettingUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateProject(ctx context.Context, req *project_pb.UpdateProjectRequest) (*project_pb.UpdateProjectResponse, error) {
|
||||
project, err := s.command.ChangeProject(ctx, projectUpdateToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !project.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectUpdateToCommand(req *project_pb.UpdateProjectRequest) *command.ChangeProject {
|
||||
var labeling *domain.PrivateLabelingSetting
|
||||
if req.PrivateLabelingSetting != nil {
|
||||
labeling = gu.Ptr(privateLabelingSettingToDomain(*req.PrivateLabelingSetting))
|
||||
}
|
||||
return &command.ChangeProject{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.Id,
|
||||
},
|
||||
Name: req.Name,
|
||||
ProjectRoleAssertion: req.ProjectRoleAssertion,
|
||||
ProjectRoleCheck: req.ProjectRoleCheck,
|
||||
HasProjectCheck: req.HasProjectCheck,
|
||||
PrivateLabelingSetting: labeling,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) DeleteProject(ctx context.Context, req *project_pb.DeleteProjectRequest) (*project_pb.DeleteProjectResponse, error) {
|
||||
userGrantIDs, err := s.userGrantsFromProject(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deletedAt, err := s.command.DeleteProject(ctx, req.Id, "", userGrantIDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deletionDate *timestamppb.Timestamp
|
||||
if !deletedAt.IsZero() {
|
||||
deletionDate = timestamppb.New(deletedAt)
|
||||
}
|
||||
return &project_pb.DeleteProjectResponse{
|
||||
DeletionDate: deletionDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) userGrantsFromProject(ctx context.Context, projectID string) ([]string, error) {
|
||||
projectQuery, err := query.NewUserGrantProjectIDSearchQuery(projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: []query.SearchQuery{projectQuery},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userGrantsToIDs(userGrants.UserGrants), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateProject(ctx context.Context, req *project_pb.DeactivateProjectRequest) (*project_pb.DeactivateProjectResponse, error) {
|
||||
details, err := s.command.DeactivateProject(ctx, req.Id, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeactivateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateProject(ctx context.Context, req *project_pb.ActivateProjectRequest) (*project_pb.ActivateProjectResponse, error) {
|
||||
details, err := s.command.ReactivateProject(ctx, req.Id, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.ActivateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
converted := make([]string, len(userGrants))
|
||||
for i, grant := range userGrants {
|
||||
converted[i] = grant.ID
|
||||
}
|
||||
return converted
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) CreateProjectGrant(ctx context.Context, req *project_pb.CreateProjectGrantRequest) (*project_pb.CreateProjectGrantResponse, error) {
|
||||
add := projectGrantCreateToCommand(req)
|
||||
project, err := s.command.AddProjectGrant(ctx, add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var creationDate *timestamppb.Timestamp
|
||||
if !project.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.CreateProjectGrantResponse{
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectGrantCreateToCommand(req *project_pb.CreateProjectGrantRequest) *command.AddProjectGrant {
|
||||
return &command.AddProjectGrant{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
},
|
||||
GrantID: req.GrantedOrganizationId,
|
||||
GrantedOrgID: req.GrantedOrganizationId,
|
||||
RoleKeys: req.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateProjectGrant(ctx context.Context, req *project_pb.UpdateProjectGrantRequest) (*project_pb.UpdateProjectGrantResponse, error) {
|
||||
project, err := s.command.ChangeProjectGrant(ctx, projectGrantUpdateToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !project.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectGrantUpdateToCommand(req *project_pb.UpdateProjectGrantRequest) *command.ChangeProjectGrant {
|
||||
return &command.ChangeProjectGrant{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
},
|
||||
GrantID: req.GrantedOrganizationId,
|
||||
RoleKeys: req.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateProjectGrant(ctx context.Context, req *project_pb.DeactivateProjectGrantRequest) (*project_pb.DeactivateProjectGrantResponse, error) {
|
||||
details, err := s.command.DeactivateProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeactivateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateProjectGrant(ctx context.Context, req *project_pb.ActivateProjectGrantRequest) (*project_pb.ActivateProjectGrantResponse, error) {
|
||||
details, err := s.command.ReactivateProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.ActivateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteProjectGrant(ctx context.Context, req *project_pb.DeleteProjectGrantRequest) (*project_pb.DeleteProjectGrantResponse, error) {
|
||||
userGrantIDs, err := s.userGrantsFromProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.RemoveProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId, "", userGrantIDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deletionDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
deletionDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeleteProjectGrantResponse{
|
||||
DeletionDate: deletionDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) userGrantsFromProjectGrant(ctx context.Context, projectID, grantedOrganizationID string) ([]string, error) {
|
||||
projectQuery, err := query.NewUserGrantProjectIDSearchQuery(projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grantQuery, err := query.NewUserGrantGrantIDSearchQuery(grantedOrganizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: []query.SearchQuery{projectQuery, grantQuery},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userGrantsToIDs(userGrants.UserGrants), nil
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) AddProjectRole(ctx context.Context, req *project_pb.AddProjectRoleRequest) (*project_pb.AddProjectRoleResponse, error) {
|
||||
role, err := s.command.AddProjectRole(ctx, addProjectRoleRequestToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var creationDate *timestamppb.Timestamp
|
||||
if !role.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(role.EventDate)
|
||||
}
|
||||
return &project_pb.AddProjectRoleResponse{
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func addProjectRoleRequestToCommand(req *project_pb.AddProjectRoleRequest) *command.AddProjectRole {
|
||||
group := ""
|
||||
if req.Group != nil {
|
||||
group = *req.Group
|
||||
}
|
||||
|
||||
return &command.AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
},
|
||||
Key: req.RoleKey,
|
||||
DisplayName: req.DisplayName,
|
||||
Group: group,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateProjectRole(ctx context.Context, req *project_pb.UpdateProjectRoleRequest) (*project_pb.UpdateProjectRoleResponse, error) {
|
||||
role, err := s.command.ChangeProjectRole(ctx, updateProjectRoleRequestToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var changeDate *timestamppb.Timestamp
|
||||
if !role.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(role.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectRoleResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateProjectRoleRequestToCommand(req *project_pb.UpdateProjectRoleRequest) *command.ChangeProjectRole {
|
||||
displayName := ""
|
||||
if req.DisplayName != nil {
|
||||
displayName = *req.DisplayName
|
||||
}
|
||||
group := ""
|
||||
if req.Group != nil {
|
||||
group = *req.Group
|
||||
}
|
||||
|
||||
return &command.ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.ProjectId,
|
||||
},
|
||||
Key: req.RoleKey,
|
||||
DisplayName: displayName,
|
||||
Group: group,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RemoveProjectRole(ctx context.Context, req *project_pb.RemoveProjectRoleRequest) (*project_pb.RemoveProjectRoleResponse, error) {
|
||||
userGrantIDs, err := s.userGrantsFromProjectAndRole(ctx, req.ProjectId, req.RoleKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectGrantIDs, err := s.projectGrantsFromProjectAndRole(ctx, req.ProjectId, req.RoleKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.RemoveProjectRole(ctx, req.ProjectId, req.RoleKey, "", projectGrantIDs, userGrantIDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deletionDate *timestamppb.Timestamp
|
||||
if !details.EventDate.IsZero() {
|
||||
deletionDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.RemoveProjectRoleResponse{
|
||||
RemovalDate: deletionDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) userGrantsFromProjectAndRole(ctx context.Context, projectID, roleKey string) ([]string, error) {
|
||||
projectQuery, err := query.NewUserGrantProjectIDSearchQuery(projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rolesQuery, err := query.NewUserGrantRoleQuery(roleKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: []query.SearchQuery{projectQuery, rolesQuery},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userGrantsToIDs(userGrants.UserGrants), nil
|
||||
}
|
||||
|
||||
func (s *Server) projectGrantsFromProjectAndRole(ctx context.Context, projectID, roleKey string) ([]string, error) {
|
||||
projectGrants, err := s.query.SearchProjectGrantsByProjectIDAndRoleKey(ctx, projectID, roleKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantsToIDs(projectGrants), nil
|
||||
}
|
||||
|
||||
func projectGrantsToIDs(projectGrants *query.ProjectGrants) []string {
|
||||
converted := make([]string, len(projectGrants.ProjectGrants))
|
||||
for i, grant := range projectGrants.ProjectGrants {
|
||||
converted[i] = grant.GrantID
|
||||
}
|
||||
return converted
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) GetProject(ctx context.Context, req *project_pb.GetProjectRequest) (*project_pb.GetProjectResponse, error) {
|
||||
project, err := s.query.GetProjectByIDWithPermission(ctx, true, req.Id, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.GetProjectResponse{
|
||||
Project: projectToPb(project),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListProjects(ctx context.Context, req *project_pb.ListProjectsRequest) (*project_pb.ListProjectsResponse, error) {
|
||||
queries, err := s.listProjectRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := s.query.SearchGrantedProjects(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectsResponse{
|
||||
Projects: grantedProjectsToPb(resp.GrantedProjects),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) listProjectRequestToModel(req *project_pb.ListProjectsRequest) (*query.ProjectAndGrantedProjectSearchQueries, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := projectFiltersToQuery(req.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.ProjectAndGrantedProjectSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: grantedProjectFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func grantedProjectFieldNameToSortingColumn(field *project_pb.ProjectFieldName) query.Column {
|
||||
if field == nil {
|
||||
return query.GrantedProjectColumnCreationDate
|
||||
}
|
||||
switch *field {
|
||||
case project_pb.ProjectFieldName_PROJECT_FIELD_NAME_CREATION_DATE:
|
||||
return query.GrantedProjectColumnCreationDate
|
||||
case project_pb.ProjectFieldName_PROJECT_FIELD_NAME_ID:
|
||||
return query.GrantedProjectColumnID
|
||||
case project_pb.ProjectFieldName_PROJECT_FIELD_NAME_NAME:
|
||||
return query.GrantedProjectColumnName
|
||||
case project_pb.ProjectFieldName_PROJECT_FIELD_NAME_CHANGE_DATE:
|
||||
return query.GrantedProjectColumnChangeDate
|
||||
case project_pb.ProjectFieldName_PROJECT_FIELD_NAME_UNSPECIFIED:
|
||||
return query.GrantedProjectColumnCreationDate
|
||||
default:
|
||||
return query.GrantedProjectColumnCreationDate
|
||||
}
|
||||
}
|
||||
|
||||
func projectFiltersToQuery(queries []*project_pb.ProjectSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, qry := range queries {
|
||||
q[i], err = projectFilterToModel(qry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func projectFilterToModel(filter *project_pb.ProjectSearchFilter) (query.SearchQuery, error) {
|
||||
switch q := filter.Filter.(type) {
|
||||
case *project_pb.ProjectSearchFilter_ProjectNameFilter:
|
||||
return projectNameFilterToQuery(q.ProjectNameFilter)
|
||||
case *project_pb.ProjectSearchFilter_InProjectIdsFilter:
|
||||
return projectInIDsFilterToQuery(q.InProjectIdsFilter)
|
||||
case *project_pb.ProjectSearchFilter_ProjectResourceOwnerFilter:
|
||||
return projectResourceOwnerFilterToQuery(q.ProjectResourceOwnerFilter)
|
||||
case *project_pb.ProjectSearchFilter_ProjectOrganizationIdFilter:
|
||||
return projectOrganizationIDFilterToQuery(q.ProjectOrganizationIdFilter)
|
||||
case *project_pb.ProjectSearchFilter_ProjectGrantResourceOwnerFilter:
|
||||
return projectGrantResourceOwnerFilterToQuery(q.ProjectGrantResourceOwnerFilter)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func projectNameFilterToQuery(q *project_pb.ProjectNameFilter) (query.SearchQuery, error) {
|
||||
return query.NewGrantedProjectNameSearchQuery(filter.TextMethodPbToQuery(q.Method), q.GetProjectName())
|
||||
}
|
||||
|
||||
func projectInIDsFilterToQuery(q *project_pb.InProjectIDsFilter) (query.SearchQuery, error) {
|
||||
return query.NewGrantedProjectIDSearchQuery(q.ProjectIds)
|
||||
}
|
||||
|
||||
func projectResourceOwnerFilterToQuery(q *project_pb.ProjectResourceOwnerFilter) (query.SearchQuery, error) {
|
||||
return query.NewGrantedProjectResourceOwnerSearchQuery(q.ProjectResourceOwner)
|
||||
}
|
||||
|
||||
func projectOrganizationIDFilterToQuery(q *project_pb.ProjectOrganizationIDFilter) (query.SearchQuery, error) {
|
||||
return query.NewGrantedProjectOrganizationIDSearchQuery(q.ProjectOrganizationId)
|
||||
}
|
||||
|
||||
func projectGrantResourceOwnerFilterToQuery(q *project_pb.ProjectGrantResourceOwnerFilter) (query.SearchQuery, error) {
|
||||
return query.NewGrantedProjectGrantResourceOwnerSearchQuery(q.ProjectGrantResourceOwner)
|
||||
}
|
||||
|
||||
func grantedProjectsToPb(projects []*query.GrantedProject) []*project_pb.Project {
|
||||
o := make([]*project_pb.Project, len(projects))
|
||||
for i, org := range projects {
|
||||
o[i] = grantedProjectToPb(org)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func projectToPb(project *query.Project) *project_pb.Project {
|
||||
return &project_pb.Project{
|
||||
Id: project.ID,
|
||||
OrganizationId: project.ResourceOwner,
|
||||
CreationDate: timestamppb.New(project.CreationDate),
|
||||
ChangeDate: timestamppb.New(project.ChangeDate),
|
||||
State: projectStateToPb(project.State),
|
||||
Name: project.Name,
|
||||
PrivateLabelingSetting: privateLabelingSettingToPb(project.PrivateLabelingSetting),
|
||||
ProjectAccessRequired: project.HasProjectCheck,
|
||||
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||
AuthorizationRequired: project.ProjectRoleCheck,
|
||||
}
|
||||
}
|
||||
|
||||
func grantedProjectToPb(project *query.GrantedProject) *project_pb.Project {
|
||||
var grantedOrganizationID, grantedOrganizationName *string
|
||||
if project.GrantedOrgID != "" {
|
||||
grantedOrganizationID = &project.GrantedOrgID
|
||||
}
|
||||
if project.OrgName != "" {
|
||||
grantedOrganizationName = &project.OrgName
|
||||
}
|
||||
|
||||
return &project_pb.Project{
|
||||
Id: project.ProjectID,
|
||||
OrganizationId: project.ResourceOwner,
|
||||
CreationDate: timestamppb.New(project.CreationDate),
|
||||
ChangeDate: timestamppb.New(project.ChangeDate),
|
||||
State: projectStateToPb(project.ProjectState),
|
||||
Name: project.ProjectName,
|
||||
PrivateLabelingSetting: privateLabelingSettingToPb(project.PrivateLabelingSetting),
|
||||
ProjectAccessRequired: project.HasProjectCheck,
|
||||
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||
AuthorizationRequired: project.ProjectRoleCheck,
|
||||
GrantedOrganizationId: grantedOrganizationID,
|
||||
GrantedOrganizationName: grantedOrganizationName,
|
||||
GrantedState: grantedProjectStateToPb(project.ProjectGrantState),
|
||||
}
|
||||
}
|
||||
|
||||
func projectStateToPb(state domain.ProjectState) project_pb.ProjectState {
|
||||
switch state {
|
||||
case domain.ProjectStateActive:
|
||||
return project_pb.ProjectState_PROJECT_STATE_ACTIVE
|
||||
case domain.ProjectStateInactive:
|
||||
return project_pb.ProjectState_PROJECT_STATE_INACTIVE
|
||||
case domain.ProjectStateUnspecified, domain.ProjectStateRemoved:
|
||||
return project_pb.ProjectState_PROJECT_STATE_UNSPECIFIED
|
||||
default:
|
||||
return project_pb.ProjectState_PROJECT_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
func grantedProjectStateToPb(state domain.ProjectGrantState) project_pb.GrantedProjectState {
|
||||
switch state {
|
||||
case domain.ProjectGrantStateActive:
|
||||
return project_pb.GrantedProjectState_GRANTED_PROJECT_STATE_ACTIVE
|
||||
case domain.ProjectGrantStateInactive:
|
||||
return project_pb.GrantedProjectState_GRANTED_PROJECT_STATE_INACTIVE
|
||||
case domain.ProjectGrantStateUnspecified, domain.ProjectGrantStateRemoved:
|
||||
return project_pb.GrantedProjectState_GRANTED_PROJECT_STATE_UNSPECIFIED
|
||||
default:
|
||||
return project_pb.GrantedProjectState_GRANTED_PROJECT_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func privateLabelingSettingToPb(setting domain.PrivateLabelingSetting) project_pb.PrivateLabelingSetting {
|
||||
switch setting {
|
||||
case domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy:
|
||||
return project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_ALLOW_LOGIN_USER_RESOURCE_OWNER_POLICY
|
||||
case domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy:
|
||||
return project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_ENFORCE_PROJECT_RESOURCE_OWNER_POLICY
|
||||
case domain.PrivateLabelingSettingUnspecified:
|
||||
return project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_UNSPECIFIED
|
||||
default:
|
||||
return project_pb.PrivateLabelingSetting_PRIVATE_LABELING_SETTING_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ListProjectGrants(ctx context.Context, req *project_pb.ListProjectGrantsRequest) (*project_pb.ListProjectGrantsResponse, error) {
|
||||
queries, err := s.listProjectGrantsRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := s.query.SearchProjectGrants(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectGrantsResponse{
|
||||
ProjectGrants: projectGrantsToPb(resp.ProjectGrants),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) listProjectGrantsRequestToModel(req *project_pb.ListProjectGrantsRequest) (*query.ProjectGrantSearchQueries, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := projectGrantFiltersToModel(req.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.ProjectGrantSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: projectGrantFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectGrantFieldNameToSortingColumn(field *project_pb.ProjectGrantFieldName) query.Column {
|
||||
if field == nil {
|
||||
return query.ProjectGrantColumnCreationDate
|
||||
}
|
||||
switch *field {
|
||||
case project_pb.ProjectGrantFieldName_PROJECT_GRANT_FIELD_NAME_PROJECT_ID:
|
||||
return query.ProjectGrantColumnProjectID
|
||||
case project_pb.ProjectGrantFieldName_PROJECT_GRANT_FIELD_NAME_CREATION_DATE:
|
||||
return query.ProjectGrantColumnCreationDate
|
||||
case project_pb.ProjectGrantFieldName_PROJECT_GRANT_FIELD_NAME_CHANGE_DATE:
|
||||
return query.ProjectGrantColumnChangeDate
|
||||
case project_pb.ProjectGrantFieldName_PROJECT_GRANT_FIELD_NAME_UNSPECIFIED:
|
||||
return query.ProjectGrantColumnCreationDate
|
||||
default:
|
||||
return query.ProjectGrantColumnCreationDate
|
||||
}
|
||||
}
|
||||
|
||||
func projectGrantFiltersToModel(queries []*project_pb.ProjectGrantSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, qry := range queries {
|
||||
q[i], err = projectGrantFilterToModel(qry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func projectGrantFilterToModel(filter *project_pb.ProjectGrantSearchFilter) (query.SearchQuery, error) {
|
||||
switch q := filter.Filter.(type) {
|
||||
case *project_pb.ProjectGrantSearchFilter_ProjectNameFilter:
|
||||
return projectNameFilterToQuery(q.ProjectNameFilter)
|
||||
case *project_pb.ProjectGrantSearchFilter_RoleKeyFilter:
|
||||
return query.NewProjectGrantRoleKeySearchQuery(q.RoleKeyFilter.Key)
|
||||
case *project_pb.ProjectGrantSearchFilter_InProjectIdsFilter:
|
||||
return query.NewProjectGrantProjectIDsSearchQuery(q.InProjectIdsFilter.ProjectIds)
|
||||
case *project_pb.ProjectGrantSearchFilter_ProjectResourceOwnerFilter:
|
||||
return query.NewProjectGrantResourceOwnerSearchQuery(q.ProjectResourceOwnerFilter.ProjectResourceOwner)
|
||||
case *project_pb.ProjectGrantSearchFilter_ProjectGrantResourceOwnerFilter:
|
||||
return query.NewProjectGrantGrantedOrgIDSearchQuery(q.ProjectGrantResourceOwnerFilter.ProjectGrantResourceOwner)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-M099f", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func projectGrantsToPb(projects []*query.ProjectGrant) []*project_pb.ProjectGrant {
|
||||
p := make([]*project_pb.ProjectGrant, len(projects))
|
||||
for i, project := range projects {
|
||||
p[i] = projectGrantToPb(project)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func projectGrantToPb(project *query.ProjectGrant) *project_pb.ProjectGrant {
|
||||
return &project_pb.ProjectGrant{
|
||||
OrganizationId: project.ResourceOwner,
|
||||
CreationDate: timestamppb.New(project.CreationDate),
|
||||
ChangeDate: timestamppb.New(project.ChangeDate),
|
||||
GrantedOrganizationId: project.GrantedOrgID,
|
||||
GrantedOrganizationName: project.OrgName,
|
||||
GrantedRoleKeys: project.GrantedRoleKeys,
|
||||
ProjectId: project.ProjectID,
|
||||
ProjectName: project.ProjectName,
|
||||
State: projectGrantStateToPb(project.State),
|
||||
}
|
||||
}
|
||||
|
||||
func projectGrantStateToPb(state domain.ProjectGrantState) project_pb.ProjectGrantState {
|
||||
switch state {
|
||||
case domain.ProjectGrantStateActive:
|
||||
return project_pb.ProjectGrantState_PROJECT_GRANT_STATE_ACTIVE
|
||||
case domain.ProjectGrantStateInactive:
|
||||
return project_pb.ProjectGrantState_PROJECT_GRANT_STATE_INACTIVE
|
||||
case domain.ProjectGrantStateUnspecified, domain.ProjectGrantStateRemoved:
|
||||
return project_pb.ProjectGrantState_PROJECT_GRANT_STATE_UNSPECIFIED
|
||||
default:
|
||||
return project_pb.ProjectGrantState_PROJECT_GRANT_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ListProjectRoles(ctx context.Context, req *project_pb.ListProjectRolesRequest) (*project_pb.ListProjectRolesResponse, error) {
|
||||
queries, err := s.listProjectRolesRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = queries.AppendProjectIDQuery(req.ProjectId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roles, err := s.query.SearchProjectRoles(ctx, true, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectRolesResponse{
|
||||
ProjectRoles: roleViewsToPb(roles.ProjectRoles),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, roles.SearchResponse),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) listProjectRolesRequestToModel(req *project_pb.ListProjectRolesRequest) (*query.ProjectRoleSearchQueries, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := roleQueriesToModel(req.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.ProjectRoleSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: projectRoleFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectRoleFieldNameToSortingColumn(field *project_pb.ProjectRoleFieldName) query.Column {
|
||||
if field == nil {
|
||||
return query.ProjectRoleColumnCreationDate
|
||||
}
|
||||
switch *field {
|
||||
case project_pb.ProjectRoleFieldName_PROJECT_ROLE_FIELD_NAME_KEY:
|
||||
return query.ProjectRoleColumnKey
|
||||
case project_pb.ProjectRoleFieldName_PROJECT_ROLE_FIELD_NAME_CREATION_DATE:
|
||||
return query.ProjectRoleColumnCreationDate
|
||||
case project_pb.ProjectRoleFieldName_PROJECT_ROLE_FIELD_NAME_CHANGE_DATE:
|
||||
return query.ProjectRoleColumnChangeDate
|
||||
case project_pb.ProjectRoleFieldName_PROJECT_ROLE_FIELD_NAME_UNSPECIFIED:
|
||||
return query.ProjectRoleColumnCreationDate
|
||||
default:
|
||||
return query.ProjectRoleColumnCreationDate
|
||||
}
|
||||
}
|
||||
|
||||
func roleQueriesToModel(queries []*project_pb.ProjectRoleSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = roleQueryToModel(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func roleQueryToModel(apiQuery *project_pb.ProjectRoleSearchFilter) (query.SearchQuery, error) {
|
||||
switch q := apiQuery.Filter.(type) {
|
||||
case *project_pb.ProjectRoleSearchFilter_RoleKeyFilter:
|
||||
return query.NewProjectRoleKeySearchQuery(filter.TextMethodPbToQuery(q.RoleKeyFilter.Method), q.RoleKeyFilter.Key)
|
||||
case *project_pb.ProjectRoleSearchFilter_DisplayNameFilter:
|
||||
return query.NewProjectRoleDisplayNameSearchQuery(filter.TextMethodPbToQuery(q.DisplayNameFilter.Method), q.DisplayNameFilter.DisplayName)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-fms0e", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func roleViewsToPb(roles []*query.ProjectRole) []*project_pb.ProjectRole {
|
||||
o := make([]*project_pb.ProjectRole, len(roles))
|
||||
for i, org := range roles {
|
||||
o[i] = roleViewToPb(org)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func roleViewToPb(role *query.ProjectRole) *project_pb.ProjectRole {
|
||||
return &project_pb.ProjectRole{
|
||||
ProjectId: role.ProjectID,
|
||||
Key: role.Key,
|
||||
CreationDate: timestamppb.New(role.CreationDate),
|
||||
ChangeDate: timestamppb.New(role.ChangeDate),
|
||||
DisplayName: role.DisplayName,
|
||||
Group: role.Group,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
project "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
var _ project.ProjectServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
project.UnimplementedProjectServiceServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
systemDefaults systemdefaults.SystemDefaults,
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
checkPermission domain.PermissionCheck,
|
||||
) *Server {
|
||||
return &Server{
|
||||
systemDefaults: systemDefaults,
|
||||
command: command,
|
||||
query: query,
|
||||
checkPermission: checkPermission,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
project.RegisterProjectServiceServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return project.ProjectService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return project.ProjectService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return project.ProjectService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return project.RegisterProjectServiceHandler
|
||||
}
|
||||
@@ -332,7 +332,7 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
projectID2, _, _ := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID2, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID2, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -346,7 +346,7 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
projectID, _, sp := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectUserGrant(t, ctx, projectID, user.GetUserId())
|
||||
|
||||
@@ -368,9 +368,9 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
projectID, _, sp := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, true, true)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permission-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
|
||||
return createSessionAndSmlRequestForCallback(ctx, t, sp, Instance.Users[integration.UserTypeOrgOwner].ID, acsRedirect, user.GetUserId(), saml.HTTPRedirectBinding)
|
||||
},
|
||||
@@ -502,9 +502,9 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
projectID, _, sp := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permissison-"+gofakeit.AppName(), gofakeit.Email())
|
||||
projectGrantResp := Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, projectGrantResp.GetGrantId(), user.GetUserId())
|
||||
Instance.CreateProjectGrantUserGrant(ctx, orgResp.GetOrganizationId(), projectID, orgResp.GetOrganizationId(), user.GetUserId())
|
||||
|
||||
return createSessionAndSmlRequestForCallback(ctx, t, sp, Instance.Users[integration.UserTypeOrgOwner].ID, acsRedirect, user.GetUserId(), saml.HTTPRedirectBinding)
|
||||
},
|
||||
@@ -523,7 +523,7 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
projectID, _, sp := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, true, false)
|
||||
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permissison-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
|
||||
return createSessionAndSmlRequestForCallback(ctx, t, sp, Instance.Users[integration.UserTypeOrgOwner].ID, acsRedirect, user.GetUserId(), saml.HTTPRedirectBinding)
|
||||
@@ -563,7 +563,7 @@ func TestServer_CreateResponse_Permission(t *testing.T) {
|
||||
dep: func(ctx context.Context, t *testing.T) *saml_pb.CreateResponseRequest {
|
||||
projectID, _, sp := createSAMLApplication(ctx, t, idpMetadata, saml.HTTPRedirectBinding, false, true)
|
||||
orgResp := Instance.CreateOrganization(ctx, "saml-permissison-"+gofakeit.AppName(), gofakeit.Email())
|
||||
Instance.CreateProjectGrant(ctx, projectID, orgResp.GetOrganizationId())
|
||||
Instance.CreateProjectGrant(ctx, t, projectID, orgResp.GetOrganizationId())
|
||||
user := Instance.CreateHumanUserVerified(ctx, orgResp.GetOrganizationId(), gofakeit.Email(), gofakeit.Phone())
|
||||
|
||||
return createSessionAndSmlRequestForCallback(ctx, t, sp, Instance.Users[integration.UserTypeOrgOwner].ID, acsRedirect, user.GetUserId(), saml.HTTPRedirectBinding)
|
||||
@@ -640,10 +640,9 @@ func createSAMLSP(t *testing.T, idpMetadata *saml.EntityDescriptor, binding stri
|
||||
}
|
||||
|
||||
func createSAMLApplication(ctx context.Context, t *testing.T, idpMetadata *saml.EntityDescriptor, binding string, projectRoleCheck, hasProjectCheck bool) (string, string, *samlsp.Middleware) {
|
||||
project, err := Instance.CreateProjectWithPermissionCheck(ctx, projectRoleCheck, hasProjectCheck)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(ctx, t, "", gofakeit.AppName(), projectRoleCheck, hasProjectCheck)
|
||||
rootURL, sp := createSAMLSP(t, idpMetadata, binding)
|
||||
_, err = Instance.CreateSAMLClient(ctx, project.GetId(), sp)
|
||||
_, err := Instance.CreateSAMLClient(ctx, project.GetId(), sp)
|
||||
require.NoError(t, err)
|
||||
return project.GetId(), rootURL, sp
|
||||
}
|
||||
|
||||
@@ -1753,8 +1753,8 @@ func TestServer_ReactivateUser(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_DeleteUser(t *testing.T) {
|
||||
projectResp, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
projectResp := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
|
||||
type args struct {
|
||||
req *user.DeleteUserRequest
|
||||
prepare func(*testing.T, *user.DeleteUserRequest) context.Context
|
||||
|
||||
@@ -1706,12 +1706,11 @@ func TestServer_ReactivateUser(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_DeleteUser(t *testing.T) {
|
||||
projectResp, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
projectResp := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *user.DeleteUserRequest
|
||||
prepare func(request *user.DeleteUserRequest) error
|
||||
prepare func(request *user.DeleteUserRequest)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1726,7 +1725,7 @@ func TestServer_DeleteUser(t *testing.T) {
|
||||
&user.DeleteUserRequest{
|
||||
UserId: "notexisting",
|
||||
},
|
||||
func(request *user.DeleteUserRequest) error { return nil },
|
||||
nil,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@@ -1735,10 +1734,9 @@ func TestServer_DeleteUser(t *testing.T) {
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
prepare: func(request *user.DeleteUserRequest) {
|
||||
resp := Instance.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
@@ -1753,10 +1751,9 @@ func TestServer_DeleteUser(t *testing.T) {
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
prepare: func(request *user.DeleteUserRequest) {
|
||||
resp := Instance.CreateMachineUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
@@ -1771,13 +1768,12 @@ func TestServer_DeleteUser(t *testing.T) {
|
||||
args: args{
|
||||
ctx: CTX,
|
||||
req: &user.DeleteUserRequest{},
|
||||
prepare: func(request *user.DeleteUserRequest) error {
|
||||
prepare: func(request *user.DeleteUserRequest) {
|
||||
resp := Instance.CreateHumanUser(CTX)
|
||||
request.UserId = resp.GetUserId()
|
||||
Instance.CreateProjectUserGrant(t, CTX, projectResp.GetId(), request.UserId)
|
||||
Instance.CreateProjectMembership(t, CTX, projectResp.GetId(), request.UserId)
|
||||
Instance.CreateOrgMembership(t, CTX, request.UserId)
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &user.DeleteUserResponse{
|
||||
@@ -1790,8 +1786,9 @@ func TestServer_DeleteUser(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
if tt.args.prepare != nil {
|
||||
tt.args.prepare(tt.args.req)
|
||||
}
|
||||
|
||||
got, err := Client.DeleteUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
|
||||
@@ -122,7 +122,7 @@ func (s *Server) assertClientScopesForPAT(ctx context.Context, token *accessToke
|
||||
if err != nil {
|
||||
return zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
|
||||
}
|
||||
roles, err := s.query.SearchProjectRoles(ctx, authz.GetFeatures(ctx).TriggerIntrospectionProjections, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}})
|
||||
roles, err := s.query.SearchProjectRoles(ctx, authz.GetFeatures(ctx).TriggerIntrospectionProjections, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
|
||||
}
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}})
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -482,7 +482,7 @@ func (o *OPStorage) assertProjectRoleScopesByProject(ctx context.Context, projec
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
|
||||
}
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}})
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -498,7 +498,7 @@ func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.T
|
||||
if err != nil {
|
||||
return zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
|
||||
}
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}})
|
||||
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zitadel/oidc/v3/pkg/client"
|
||||
@@ -24,8 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func TestServer_Introspect(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
app, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -188,10 +188,8 @@ func assertIntrospection(
|
||||
// with clients that have different authentication methods.
|
||||
func TestServer_VerifyClient(t *testing.T) {
|
||||
sessionID, sessionToken, startTime, changeTime := Instance.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
projectInactive, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
projectInactive := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
|
||||
inactiveClient, err := Instance.CreateOIDCInactivateClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -421,21 +421,20 @@ type clientOpts struct {
|
||||
func createClientWithOpts(t testing.TB, instance *integration.Instance, opts clientOpts) (clientID, projectID string) {
|
||||
ctx := instance.WithAuthorization(CTX, integration.UserTypeOrgOwner)
|
||||
|
||||
project, err := instance.CreateProject(ctx)
|
||||
require.NoError(t, err)
|
||||
project := instance.CreateProject(ctx, t.(*testing.T), "", gofakeit.AppName(), false, false)
|
||||
app, err := instance.CreateOIDCClientLoginVersion(ctx, opts.redirectURI, opts.logoutURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, opts.devMode, opts.LoginVersion)
|
||||
require.NoError(t, err)
|
||||
return app.GetClientId(), project.GetId()
|
||||
}
|
||||
|
||||
func createImplicitClient(t testing.TB) string {
|
||||
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, nil)
|
||||
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, t.(*testing.T), redirectURIImplicit, nil)
|
||||
require.NoError(t, err)
|
||||
return app.GetClientId()
|
||||
}
|
||||
|
||||
func createImplicitClientNoLoginClientHeader(t testing.TB) string {
|
||||
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, &app.LoginVersion{Version: &app.LoginVersion_LoginV2{LoginV2: &app.LoginV2{BaseUri: nil}}})
|
||||
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, t.(*testing.T), redirectURIImplicit, &app.LoginVersion{Version: &app.LoginVersion_LoginV2{LoginV2: &app.LoginV2{BaseUri: nil}}})
|
||||
require.NoError(t, err)
|
||||
return app.GetClientId()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
||||
@@ -21,8 +22,7 @@ import (
|
||||
)
|
||||
|
||||
func TestServer_DeviceAuth(t *testing.T) {
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
client, err := Instance.CreateOIDCClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, app.OIDCGrantType_OIDC_GRANT_TYPE_DEVICE_CODE)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestServer_TokenExchange(t *testing.T) {
|
||||
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
userResp := instance.CreateHumanUser(ctx)
|
||||
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
|
||||
require.NoError(t, err)
|
||||
signer, err := rp.SignerFromKeyFile(keyData)()
|
||||
require.NoError(t, err)
|
||||
@@ -371,7 +371,7 @@ func TestServer_TokenExchangeImpersonation(t *testing.T) {
|
||||
setTokenExchangeFeature(t, instance, true)
|
||||
setImpersonationPolicy(t, instance, true)
|
||||
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
|
||||
require.NoError(t, err)
|
||||
signer, err := rp.SignerFromKeyFile(keyData)()
|
||||
require.NoError(t, err)
|
||||
@@ -591,7 +591,7 @@ func TestImpersonation_API_Call(t *testing.T) {
|
||||
instance := integration.NewInstance(CTX)
|
||||
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
|
||||
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
|
||||
require.NoError(t, err)
|
||||
signer, err := rp.SignerFromKeyFile(keyData)()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -309,9 +309,7 @@ func TestServer_UserInfo_Issue6662(t *testing.T) {
|
||||
roleBar = "bar"
|
||||
)
|
||||
|
||||
project, err := Instance.CreateProject(CTX)
|
||||
projectID := project.GetId()
|
||||
require.NoError(t, err)
|
||||
projectID := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false).GetId()
|
||||
user, _, clientID, clientSecret, err := Instance.CreateOIDCCredentialsClient(CTX)
|
||||
require.NoError(t, err)
|
||||
addProjectRolesGrants(t, user.GetUserId(), projectID, roleFoo, roleBar)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -76,13 +77,12 @@ func TestDeleteUser_errors(t *testing.T) {
|
||||
func TestDeleteUser_ensureReallyDeleted(t *testing.T) {
|
||||
// create user and dependencies
|
||||
createUserResp := Instance.CreateHumanUser(CTX)
|
||||
proj, err := Instance.CreateProject(CTX)
|
||||
require.NoError(t, err)
|
||||
proj := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
|
||||
|
||||
Instance.CreateProjectUserGrant(t, CTX, proj.Id, createUserResp.UserId)
|
||||
|
||||
// delete user via scim
|
||||
err = Instance.Client.SCIM.Users.Delete(CTX, Instance.DefaultOrg.Id, createUserResp.UserId)
|
||||
err := Instance.Client.SCIM.Users.Delete(CTX, Instance.DefaultOrg.Id, createUserResp.UserId)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ensure it is really deleted => try to delete again => should 404
|
||||
|
||||
@@ -125,7 +125,7 @@ type userGrantProvider interface {
|
||||
|
||||
type projectProvider interface {
|
||||
ProjectByClientID(context.Context, string) (*query.Project, error)
|
||||
SearchProjectGrants(ctx context.Context, queries *query.ProjectGrantSearchQueries) (projects *query.ProjectGrants, err error)
|
||||
SearchProjectGrants(ctx context.Context, queries *query.ProjectGrantSearchQueries, permissionCheck domain.PermissionCheck) (projects *query.ProjectGrants, err error)
|
||||
}
|
||||
|
||||
type applicationProvider interface {
|
||||
@@ -1841,7 +1841,7 @@ func projectRequired(ctx context.Context, request *domain.AuthRequest, projectPr
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
grants, err := projectProvider.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectID, grantedOrg}})
|
||||
grants, err := projectProvider.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectID, grantedOrg}}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ func (m *mockProject) ProjectByClientID(ctx context.Context, s string) (*query.P
|
||||
return &query.Project{ResourceOwner: m.resourceOwner, HasProjectCheck: m.projectCheck}, nil
|
||||
}
|
||||
|
||||
func (m *mockProject) SearchProjectGrants(ctx context.Context, queries *query.ProjectGrantSearchQueries) (*query.ProjectGrants, error) {
|
||||
func (m *mockProject) SearchProjectGrants(ctx context.Context, queries *query.ProjectGrantSearchQueries, permissionCheck domain.PermissionCheck) (*query.ProjectGrants, error) {
|
||||
if m.hasProject {
|
||||
mockProjectGrant := new(query.ProjectGrant)
|
||||
return &query.ProjectGrants{ProjectGrants: []*query.ProjectGrant{mockProjectGrant}}, nil
|
||||
|
||||
@@ -468,7 +468,7 @@ func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMA-wG9p1", "Errors.Org.DefaultOrgNotDeletable")
|
||||
}
|
||||
|
||||
err := c.checkProjectExists(ctx, instance.ProjectID(), a.ID)
|
||||
_, err := c.checkProjectExists(ctx, instance.ProjectID(), a.ID)
|
||||
// if there is no error, the ZITADEL project was found on the org to be deleted
|
||||
if err == nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMA-AF3JW", "Errors.Org.ZitadelOrgNotDeletable")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/v2/user"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -58,3 +59,15 @@ func (c *Commands) checkPermissionUpdateUser(ctx context.Context, resourceOwner,
|
||||
func (c *Commands) checkPermissionUpdateUserCredentials(ctx context.Context, resourceOwner, userID string) error {
|
||||
return c.checkPermissionOnUser(ctx, domain.PermissionUserCredentialWrite)(resourceOwner, userID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectDelete, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionUpdateProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectWrite, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionWriteProjectGrant(ctx context.Context, resourceOwner, projectGrantID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectGrantWrite, project.AggregateType)(resourceOwner, projectGrantID)
|
||||
}
|
||||
|
||||
+154
-84
@@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@@ -17,67 +19,60 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
if resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-w8tnSoJxtn", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-nDXf5vXoUj", "Errors.IDMissing")
|
||||
}
|
||||
if !project.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
}
|
||||
project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return project, nil
|
||||
type AddProject struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Name string
|
||||
ProjectRoleAssertion bool
|
||||
ProjectRoleCheck bool
|
||||
HasProjectCheck bool
|
||||
PrivateLabelingSetting domain.PrivateLabelingSetting
|
||||
}
|
||||
|
||||
func (c *Commands) AddProject(ctx context.Context, project *domain.Project, resourceOwner string) (_ *domain.Project, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
if !project.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
func (p *AddProject) IsValid() error {
|
||||
if p.ResourceOwner == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing")
|
||||
if p.Name == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
}
|
||||
|
||||
projectID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return project, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
||||
projectAdd.AggregateID = projectID
|
||||
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectAdd.AggregateID, resourceOwner)
|
||||
func (c *Commands) AddProject(ctx context.Context, add *AddProject) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err := add.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if add.AggregateID == "" {
|
||||
add.AggregateID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
wm, err := c.getProjectWriteModelByID(ctx, add.AggregateID, add.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isProjectStateExists(projectWriteModel.State) {
|
||||
if isProjectStateExists(wm.State) {
|
||||
return nil, zerrors.ThrowAlreadyExists(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectAddedEvent(
|
||||
ctx,
|
||||
//nolint: contextcheck
|
||||
ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel),
|
||||
projectAdd.Name,
|
||||
projectAdd.ProjectRoleAssertion,
|
||||
projectAdd.ProjectRoleCheck,
|
||||
projectAdd.HasProjectCheck,
|
||||
projectAdd.PrivateLabelingSetting),
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &wm.WriteModel),
|
||||
add.Name,
|
||||
add.ProjectRoleAssertion,
|
||||
add.ProjectRoleCheck,
|
||||
add.HasProjectCheck,
|
||||
add.PrivateLabelingSetting),
|
||||
}
|
||||
postCommit, err := c.projectCreatedMilestone(ctx, &events)
|
||||
if err != nil {
|
||||
@@ -88,11 +83,11 @@ func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Proj
|
||||
return nil, err
|
||||
}
|
||||
postCommit(ctx)
|
||||
err = AppendAndReduce(projectWriteModel, pushedEvents...)
|
||||
err = AppendAndReduce(wm, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectWriteModelToProject(projectWriteModel), nil
|
||||
return writeModelToObjectDetails(&wm.WriteModel), nil
|
||||
}
|
||||
|
||||
func AddProjectCommand(
|
||||
@@ -143,14 +138,14 @@ func projectWriteModel(ctx context.Context, filter preparation.FilterToQueryRedu
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resourceOwner string) (*eventstore.Aggregate, domain.ProjectState, error) {
|
||||
result, err := c.projectState(ctx, projectID, resourceOwner)
|
||||
func (c *Commands) projectAggregateByID(ctx context.Context, projectID string) (*eventstore.Aggregate, domain.ProjectState, error) {
|
||||
result, err := c.projectState(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, domain.ProjectStateUnspecified, zerrors.ThrowNotFound(err, "COMMA-NDQoF", "Errors.Project.NotFound")
|
||||
}
|
||||
if len(result) == 0 {
|
||||
_ = projection.ProjectGrantFields.Trigger(ctx)
|
||||
result, err = c.projectState(ctx, projectID, resourceOwner)
|
||||
result, err = c.projectState(ctx, projectID)
|
||||
if err != nil || len(result) == 0 {
|
||||
return nil, domain.ProjectStateUnspecified, zerrors.ThrowNotFound(err, "COMMA-U1nza", "Errors.Project.NotFound")
|
||||
}
|
||||
@@ -164,7 +159,7 @@ func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resource
|
||||
return &result[0].Aggregate, state, nil
|
||||
}
|
||||
|
||||
func (c *Commands) projectState(ctx context.Context, projectID, resourceOwner string) ([]*eventstore.SearchResult, error) {
|
||||
func (c *Commands) projectState(ctx context.Context, projectID string) ([]*eventstore.SearchResult, error) {
|
||||
return c.eventstore.Search(
|
||||
ctx,
|
||||
map[eventstore.FieldType]any{
|
||||
@@ -172,12 +167,11 @@ func (c *Commands) projectState(ctx context.Context, projectID, resourceOwner st
|
||||
eventstore.FieldTypeObjectID: projectID,
|
||||
eventstore.FieldTypeObjectRevision: project.ProjectObjectRevision,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOwner string) (err error) {
|
||||
func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOwner string) (_ string, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -185,50 +179,69 @@ func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOw
|
||||
return c.checkProjectExistsOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
_, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
agg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil || !state.Valid() {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMA-VCnwD", "Errors.Project.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMA-VCnwD", "Errors.Project.NotFound")
|
||||
}
|
||||
return agg.ResourceOwner, nil
|
||||
}
|
||||
|
||||
type ChangeProject struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Name *string
|
||||
ProjectRoleAssertion *bool
|
||||
ProjectRoleCheck *bool
|
||||
HasProjectCheck *bool
|
||||
PrivateLabelingSetting *domain.PrivateLabelingSetting
|
||||
}
|
||||
|
||||
func (p *ChangeProject) IsValid() error {
|
||||
if p.AggregateID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
if p.Name != nil && *p.Name == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Project, resourceOwner string) (*domain.Project, error) {
|
||||
if !projectChange.IsValid() || projectChange.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
func (c *Commands) ChangeProject(ctx context.Context, change *ChangeProject) (_ *domain.ObjectDetails, err error) {
|
||||
if err := change.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner)
|
||||
existing, err := c.getProjectWriteModelByID(ctx, change.AggregateID, change.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isProjectStateExists(existingProject.State) {
|
||||
if !isProjectStateExists(existing.State) {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existing.ResourceOwner, existing.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
changedEvent, hasChanged, err := existingProject.NewChangedEvent(
|
||||
changedEvent := existing.NewChangedEvent(
|
||||
ctx,
|
||||
projectAgg,
|
||||
projectChange.Name,
|
||||
projectChange.ProjectRoleAssertion,
|
||||
projectChange.ProjectRoleCheck,
|
||||
projectChange.HasProjectCheck,
|
||||
projectChange.PrivateLabelingSetting)
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existing.WriteModel),
|
||||
change.Name,
|
||||
change.ProjectRoleAssertion,
|
||||
change.ProjectRoleCheck,
|
||||
change.HasProjectCheck,
|
||||
change.PrivateLabelingSetting)
|
||||
if changedEvent == nil {
|
||||
return writeModelToObjectDetails(&existing.WriteModel), nil
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, existing, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !hasChanged {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, existingProject, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectWriteModelToProject(existingProject), nil
|
||||
return writeModelToObjectDetails(&existing.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
@@ -236,7 +249,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
return c.deactivateProjectOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -247,6 +260,9 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
if state != domain.ProjectStateActive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, projectAgg.ResourceOwner, projectAgg.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectDeactivatedEvent(ctx, projectAgg))
|
||||
if err != nil {
|
||||
@@ -261,7 +277,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
}
|
||||
|
||||
func (c *Commands) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-3ihsF", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
@@ -269,7 +285,7 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
return c.reactivateProjectOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -280,6 +296,9 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
if state != domain.ProjectStateInactive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, projectAgg.ResourceOwner, projectAgg.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg))
|
||||
if err != nil {
|
||||
@@ -293,6 +312,7 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Deprecated: use commands.DeleteProject
|
||||
func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing")
|
||||
@@ -316,15 +336,18 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s
|
||||
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectRemovedEvent(ctx, projectAgg, existingProject.Name, uniqueConstraints),
|
||||
project.NewProjectRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingProject.WriteModel),
|
||||
existingProject.Name,
|
||||
uniqueConstraints,
|
||||
),
|
||||
}
|
||||
|
||||
for _, grantID := range cascadingUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||
if err != nil {
|
||||
logging.LogWithFields("COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
logging.WithFields("id", "COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
continue
|
||||
}
|
||||
events = append(events, event)
|
||||
@@ -341,6 +364,53 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s
|
||||
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteProject(ctx context.Context, id, resourceOwner string, cascadingUserGrantIDs ...string) (time.Time, error) {
|
||||
if id == "" {
|
||||
return time.Time{}, zerrors.ThrowInvalidArgument(nil, "COMMAND-obqos2l3no", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
existing, err := c.getProjectWriteModelByID(ctx, id, resourceOwner)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if !isProjectStateExists(existing.State) {
|
||||
return existing.WriteModel.ChangeDate, nil
|
||||
}
|
||||
if err := c.checkPermissionDeleteProject(ctx, existing.ResourceOwner, existing.AggregateID); err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
samlEntityIDsAgg, err := c.getSAMLEntityIdsWriteModelByProjectID(ctx, id, resourceOwner)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
uniqueConstraints := make([]*eventstore.UniqueConstraint, len(samlEntityIDsAgg.EntityIDs))
|
||||
for i, entityID := range samlEntityIDsAgg.EntityIDs {
|
||||
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
|
||||
}
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existing.WriteModel),
|
||||
existing.Name,
|
||||
uniqueConstraints,
|
||||
),
|
||||
}
|
||||
for _, grantID := range cascadingUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||
if err != nil {
|
||||
logging.WithFields("id", "COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
continue
|
||||
}
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
if err := c.pushAppendAndReduce(ctx, existing, events...); err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return existing.WriteModel.ChangeDate, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getProjectWriteModelByID(ctx context.Context, projectID, resourceOwner string) (_ *ProjectWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -79,7 +79,7 @@ func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mabu12", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
|
||||
@@ -90,7 +90,7 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !apiApp.IsValid() {
|
||||
|
||||
@@ -132,7 +132,7 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID)
|
||||
@@ -142,7 +142,7 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
|
||||
if oidcApp == nil || oidcApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oidcApp.AppName == "" || !oidcApp.IsValid() {
|
||||
|
||||
@@ -16,7 +16,7 @@ func (c *Commands) AddSAMLApplication(ctx context.Context, application *domain.S
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-35Fn0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedApplication := NewSAMLApplicationWriteModel(application.AggregateID, resourceOwner)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@@ -16,69 +17,107 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectGrantWithID(ctx context.Context, grant *domain.ProjectGrant, grantID string, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
type AddProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
GrantID string
|
||||
GrantedOrgID string
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
func (p *AddProjectGrant) IsValid() error {
|
||||
if p.AggregateID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-FYRnWEzBzV", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
if p.GrantedOrgID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-PPhHpWGRAE", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectGrant(ctx context.Context, grant *AddProjectGrant) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
return c.addProjectGrantWithID(ctx, grant, grantID, resourceOwner)
|
||||
if err := grant.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if grant.GrantID == "" {
|
||||
grant.GrantID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
projectResourceOwner, err := c.checkProjectGrantPreCondition(ctx, grant.AggregateID, grant.GrantedOrgID, grant.ResourceOwner, grant.RoleKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if there is no resourceowner provided then use the resourceowner of the project
|
||||
if grant.ResourceOwner == "" {
|
||||
grant.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, grant.ResourceOwner, grant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wm := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, grant.ResourceOwner)
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project or the project grant is for the same organization
|
||||
if projectResourceOwner != wm.ResourceOwner || wm.ResourceOwner == grant.GrantedOrgID {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-ckUpbvboAH", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
if err := c.pushAppendAndReduce(ctx,
|
||||
wm,
|
||||
project.NewGrantAddedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &wm.WriteModel),
|
||||
grant.GrantID,
|
||||
grant.GrantedOrgID,
|
||||
grant.RoleKeys),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&wm.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
if !grant.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-3b8fs", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
type ChangeProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
grantID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.addProjectGrantWithID(ctx, grant, grantID, resourceOwner)
|
||||
GrantID string
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectGrantWithID(ctx context.Context, grant *domain.ProjectGrant, grantID string, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
grant.GrantID = grantID
|
||||
|
||||
addedGrant := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedGrant.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(
|
||||
ctx,
|
||||
project.NewGrantAddedEvent(ctx, projectAgg, grant.GrantID, grant.GrantedOrgID, grant.RoleKeys))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(addedGrant, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(addedGrant), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string, cascadeUserGrantIDs ...string) (_ *domain.ProjectGrant, err error) {
|
||||
func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *ChangeProjectGrant, cascadeUserGrantIDs ...string) (_ *domain.ObjectDetails, err error) {
|
||||
if grant.GrantID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1j83s", "Errors.IDMissing")
|
||||
}
|
||||
existingGrant, err := c.projectGrantWriteModelByID(ctx, grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
existingGrant, err := c.projectGrantWriteModelByID(ctx, grant.GrantID, grant.AggregateID, grant.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant.GrantedOrgID = existingGrant.GrantedOrgID
|
||||
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectResourceOwner, err := c.checkProjectGrantPreCondition(ctx, existingGrant.AggregateID, existingGrant.GrantedOrgID, existingGrant.ResourceOwner, grant.RoleKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if existingGrant.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-q1BhA68RBC", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
|
||||
// return if there are no changes to the project grant roles
|
||||
if reflect.DeepEqual(existingGrant.RoleKeys, grant.RoleKeys) {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-0o0pL", "Errors.NoChangesFoundc")
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
events := []eventstore.Command{
|
||||
project.NewGrantChangedEvent(ctx, projectAgg, grant.GrantID, grant.RoleKeys),
|
||||
project.NewGrantChangedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
existingGrant.GrantID,
|
||||
grant.RoleKeys,
|
||||
),
|
||||
}
|
||||
|
||||
removedRoles := domain.GetRemovedRoles(existingGrant.RoleKeys, grant.RoleKeys)
|
||||
@@ -91,7 +130,7 @@ func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.Project
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(existingGrant), nil
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
for _, userGrantID := range cascadeUserGrantIDs {
|
||||
@@ -109,7 +148,7 @@ func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.Project
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(existingGrant), nil
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeRoleFromProjectGrant(ctx context.Context, projectAgg *eventstore.Aggregate, projectID, projectGrantID, roleKey string, cascade bool) (_ eventstore.Command, _ *ProjectGrantWriteModel, err error) {
|
||||
@@ -147,7 +186,7 @@ func (c *Commands) DeactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
return details, zerrors.ThrowInvalidArgument(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -156,12 +195,27 @@ func (c *Commands) DeactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if projectResourceOwner != existingGrant.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-0l10S9OmZV", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
// return if project grant is already inactive
|
||||
if existingGrant.State == domain.ProjectGrantStateInactive {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
// error if project grant is neither active nor inactive
|
||||
if existingGrant.State != domain.ProjectGrantStateActive {
|
||||
return details, zerrors.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotActive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewGrantDeactivateEvent(ctx, projectAgg, grantID))
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx,
|
||||
project.NewGrantDeactivateEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -177,7 +231,7 @@ func (c *Commands) ReactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
return details, zerrors.ThrowInvalidArgument(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -186,11 +240,27 @@ func (c *Commands) ReactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if projectResourceOwner != existingGrant.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-byscAarAST", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
// return if project grant is already active
|
||||
if existingGrant.State == domain.ProjectGrantStateActive {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
// error if project grant is neither active nor inactive
|
||||
if existingGrant.State != domain.ProjectGrantStateInactive {
|
||||
return details, zerrors.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotInactive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewGrantReactivatedEvent(ctx, projectAgg, grantID))
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx,
|
||||
project.NewGrantReactivatedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -209,9 +279,20 @@ func (c *Commands) RemoveProjectGrant(ctx context.Context, projectID, grantID, r
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// return if project grant does not exist, or was removed already
|
||||
if !existingGrant.State.Exists() {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
if err := c.checkPermissionDeleteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events := make([]eventstore.Command, 0)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
events = append(events, project.NewGrantRemovedEvent(ctx, projectAgg, grantID, existingGrant.GrantedOrgID))
|
||||
events = append(events, project.NewGrantRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
existingGrant.GrantedOrgID,
|
||||
),
|
||||
)
|
||||
|
||||
for _, userGrantID := range cascadeUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, userGrantID, "", true)
|
||||
@@ -232,6 +313,10 @@ func (c *Commands) RemoveProjectGrant(ctx context.Context, projectID, grantID, r
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProjectGrant(ctx context.Context, resourceOwner, projectGrantID string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectGrantDelete, resourceOwner, projectGrantID)
|
||||
}
|
||||
|
||||
func (c *Commands) projectGrantWriteModelByID(ctx context.Context, grantID, projectID, resourceOwner string) (member *ProjectGrantWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -249,55 +334,61 @@ func (c *Commands) projectGrantWriteModelByID(ctx context.Context, grantID, proj
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectID, grantedOrgID, resourceOwner string, roles []string) (string, error) {
|
||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProjectGrant) {
|
||||
return c.checkProjectGrantPreConditionOld(ctx, projectGrant, resourceOwner)
|
||||
return c.checkProjectGrantPreConditionOld(ctx, projectID, grantedOrgID, resourceOwner, roles)
|
||||
}
|
||||
existingRoleKeys, err := c.searchProjectGrantState(ctx, projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||
projectResourceOwner, existingRoleKeys, err := c.searchProjectGrantState(ctx, projectID, grantedOrgID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if projectGrant.HasInvalidRoles(existingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
if domain.HasInvalidRoles(existingRoleKeys, roles) {
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
return projectResourceOwner, nil
|
||||
}
|
||||
|
||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID, resourceOwner string) (existingRoleKeys []string, err error) {
|
||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID, resourceOwner string) (_ string, existingRoleKeys []string, err error) {
|
||||
projectStateQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
}
|
||||
grantedOrgQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: grantedOrgID,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
}
|
||||
roleQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
}
|
||||
|
||||
// as resourceowner is not always provided, it has to be separately
|
||||
if resourceOwner != "" {
|
||||
projectStateQuery[eventstore.FieldTypeResourceOwner] = resourceOwner
|
||||
roleQuery[eventstore.FieldTypeResourceOwner] = resourceOwner
|
||||
}
|
||||
|
||||
results, err := c.eventstore.Search(
|
||||
ctx,
|
||||
// project state query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
},
|
||||
// granted org query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: grantedOrgID,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
},
|
||||
// role query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
},
|
||||
projectStateQuery,
|
||||
grantedOrgQuery,
|
||||
roleQuery,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
existsProject bool
|
||||
existsGrantedOrg bool
|
||||
existsProject bool
|
||||
existingProjectResourceOwner string
|
||||
existsGrantedOrg bool
|
||||
)
|
||||
|
||||
for _, result := range results {
|
||||
@@ -306,31 +397,32 @@ func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grant
|
||||
var role string
|
||||
err := result.Value.Unmarshal(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existingRoleKeys = append(existingRoleKeys, role)
|
||||
case org.OrgSearchType:
|
||||
var state domain.OrgState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existsGrantedOrg = state.Valid() && state != domain.OrgStateRemoved
|
||||
case project.ProjectSearchType:
|
||||
var state domain.ProjectState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existsProject = state.Valid() && state != domain.ProjectStateRemoved
|
||||
existingProjectResourceOwner = result.Aggregate.ResourceOwner
|
||||
}
|
||||
}
|
||||
|
||||
if !existsProject {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
return "", nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !existsGrantedOrg {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
return "", nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
return existingRoleKeys, nil
|
||||
return existingProjectResourceOwner, existingRoleKeys, nil
|
||||
}
|
||||
|
||||
@@ -133,14 +133,18 @@ func (wm *ProjectGrantPreConditionReadModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.ProjectAddedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
if wm.ResourceOwner == "" {
|
||||
wm.ResourceOwner = e.Aggregate().ResourceOwner
|
||||
}
|
||||
if wm.ResourceOwner != e.Aggregate().ResourceOwner {
|
||||
continue
|
||||
}
|
||||
wm.ProjectExists = true
|
||||
case *project.ProjectRemovedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
if wm.ResourceOwner != e.Aggregate().ResourceOwner {
|
||||
continue
|
||||
}
|
||||
wm.ResourceOwner = ""
|
||||
wm.ProjectExists = false
|
||||
case *project.RoleAddedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -88,40 +88,35 @@ func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
func (wm *ProjectWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
name string,
|
||||
name *string,
|
||||
projectRoleAssertion,
|
||||
projectRoleCheck,
|
||||
hasProjectCheck bool,
|
||||
privateLabelingSetting domain.PrivateLabelingSetting,
|
||||
) (*project.ProjectChangeEvent, bool, error) {
|
||||
hasProjectCheck *bool,
|
||||
privateLabelingSetting *domain.PrivateLabelingSetting,
|
||||
) *project.ProjectChangeEvent {
|
||||
changes := make([]project.ProjectChanges, 0)
|
||||
var err error
|
||||
|
||||
oldName := ""
|
||||
if wm.Name != name {
|
||||
if name != nil && wm.Name != *name {
|
||||
oldName = wm.Name
|
||||
changes = append(changes, project.ChangeName(name))
|
||||
changes = append(changes, project.ChangeName(*name))
|
||||
}
|
||||
if wm.ProjectRoleAssertion != projectRoleAssertion {
|
||||
changes = append(changes, project.ChangeProjectRoleAssertion(projectRoleAssertion))
|
||||
if projectRoleAssertion != nil && wm.ProjectRoleAssertion != *projectRoleAssertion {
|
||||
changes = append(changes, project.ChangeProjectRoleAssertion(*projectRoleAssertion))
|
||||
}
|
||||
if wm.ProjectRoleCheck != projectRoleCheck {
|
||||
changes = append(changes, project.ChangeProjectRoleCheck(projectRoleCheck))
|
||||
if projectRoleCheck != nil && wm.ProjectRoleCheck != *projectRoleCheck {
|
||||
changes = append(changes, project.ChangeProjectRoleCheck(*projectRoleCheck))
|
||||
}
|
||||
if wm.HasProjectCheck != hasProjectCheck {
|
||||
changes = append(changes, project.ChangeHasProjectCheck(hasProjectCheck))
|
||||
if hasProjectCheck != nil && wm.HasProjectCheck != *hasProjectCheck {
|
||||
changes = append(changes, project.ChangeHasProjectCheck(*hasProjectCheck))
|
||||
}
|
||||
if wm.PrivateLabelingSetting != privateLabelingSetting {
|
||||
changes = append(changes, project.ChangePrivateLabelingSetting(privateLabelingSetting))
|
||||
if privateLabelingSetting != nil && wm.PrivateLabelingSetting != *privateLabelingSetting {
|
||||
changes = append(changes, project.ChangePrivateLabelingSetting(*privateLabelingSetting))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
return nil
|
||||
}
|
||||
changeEvent, err := project.NewProjectChangeEvent(ctx, aggregate, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return changeEvent, true, nil
|
||||
return project.NewProjectChangeEvent(ctx, aggregate, oldName, changes)
|
||||
}
|
||||
|
||||
func isProjectStateExists(state domain.ProjectState) bool {
|
||||
@@ -132,6 +127,10 @@ func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggre
|
||||
return eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion)
|
||||
}
|
||||
|
||||
func ProjectAggregateFromWriteModelWithCTX(ctx context.Context, wm *eventstore.WriteModel) *eventstore.Aggregate {
|
||||
return project.AggregateFromWriteModel(ctx, wm)
|
||||
}
|
||||
|
||||
func hasProjectState(check domain.ProjectState, states ...domain.ProjectState) bool {
|
||||
for _, state := range states {
|
||||
if check == state {
|
||||
|
||||
@@ -9,18 +9,18 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) checkProjectExistsOld(ctx context.Context, projectID, resourceOwner string) (err error) {
|
||||
func (c *Commands) checkProjectExistsOld(ctx context.Context, projectID, resourceOwner string) (_ string, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if !isProjectStateExists(projectWriteModel.State) {
|
||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound")
|
||||
}
|
||||
return nil
|
||||
return projectWriteModel.ResourceOwner, nil
|
||||
}
|
||||
|
||||
func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
@@ -34,6 +34,9 @@ func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, r
|
||||
if existingProject.State != domain.ProjectStateActive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existingProject.ResourceOwner, existingProject.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint: contextcheck
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
@@ -59,6 +62,9 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
|
||||
if existingProject.State != domain.ProjectStateInactive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existingProject.ResourceOwner, existingProject.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint: contextcheck
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
@@ -73,20 +79,20 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
|
||||
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||
preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectID, grantedOrgID, resourceOwner string, roles []string) (string, error) {
|
||||
preConditions := NewProjectGrantPreConditionReadModel(projectID, grantedOrgID, resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, preConditions)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if !preConditions.ProjectExists {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !preConditions.GrantedOrgExists {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
if projectGrant.HasInvalidRoles(preConditions.ExistingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
if domain.HasInvalidRoles(preConditions.ExistingRoleKeys, roles) {
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
return preConditions.ResourceOwner, nil
|
||||
}
|
||||
|
||||
@@ -7,22 +7,45 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
type AddProjectRole struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Key string
|
||||
DisplayName string
|
||||
Group string
|
||||
}
|
||||
|
||||
func (p *AddProjectRole) IsValid() bool {
|
||||
return p.AggregateID != "" && p.Key != ""
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectRole(ctx context.Context, projectRole *AddProjectRole) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
err = c.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if roleWriteModel.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-RLB4UpqQSd", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &roleWriteModel.WriteModel)
|
||||
events, err := c.addProjectRoles(ctx, projectAgg, projectRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -35,37 +58,45 @@ func (c *Commands) AddProjectRole(ctx context.Context, projectRole *domain.Proje
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(roleWriteModel), nil
|
||||
return writeModelToObjectDetails(&roleWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) BulkAddProjectRole(ctx context.Context, projectID, resourceOwner string, projectRoles []*domain.ProjectRole) (details *domain.ObjectDetails, err error) {
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
func (c *Commands) checkPermissionWriteProjectRole(ctx context.Context, resourceOwner, roleKey string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectRoleWrite, resourceOwner, roleKey)
|
||||
}
|
||||
|
||||
func (c *Commands) BulkAddProjectRole(ctx context.Context, projectID, resourceOwner string, projectRoles []*AddProjectRole) (details *domain.ObjectDetails, err error) {
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, projectRole := range projectRoles {
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-9ZXtdaJKJJ", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModel(projectID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &roleWriteModel.WriteModel)
|
||||
events, err := c.addProjectRoles(ctx, projectAgg, projectRoles...)
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(roleWriteModel, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&roleWriteModel.WriteModel), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, roleWriteModel, events...)
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.Aggregate, projectRoles ...*domain.ProjectRole) ([]eventstore.Command, error) {
|
||||
func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.Aggregate, projectRoles ...*AddProjectRole) ([]eventstore.Command, error) {
|
||||
var events []eventstore.Command
|
||||
for _, projectRole := range projectRoles {
|
||||
projectRole.AggregateID = projectAgg.ID
|
||||
if projectRole.ResourceOwner != projectAgg.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-4Q2WjlbHvc", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
if !projectRole.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
@@ -81,42 +112,55 @@ func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.A
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
type ChangeProjectRole struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Key string
|
||||
DisplayName string
|
||||
Group string
|
||||
}
|
||||
|
||||
func (p *ChangeProjectRole) IsValid() bool {
|
||||
return p.AggregateID != "" && p.Key != ""
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectRole(ctx context.Context, projectRole *ChangeProjectRole) (_ *domain.ObjectDetails, err error) {
|
||||
if !projectRole.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-2ilfW", "Errors.Project.Invalid")
|
||||
}
|
||||
err = c.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRole, err := c.getProjectRoleWriteModelByID(ctx, projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
existingRole, err := c.getProjectRoleWriteModelByID(ctx, projectRole.Key, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
if !existingRole.State.Exists() {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMAND-vv8M9", "Errors.Project.Role.NotExisting")
|
||||
}
|
||||
if existingRole.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-3MizLWveMf", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &existingRole.WriteModel)
|
||||
|
||||
changeEvent, changed, err := existingRole.NewProjectRoleChangedEvent(ctx, projectAgg, projectRole.Key, projectRole.DisplayName, projectRole.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M0cs", "Errors.NoChangesFound")
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, changeEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingRole, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(existingRole), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, existingRole, changeEvent)
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resourceOwner string, cascadingProjectGrantIds []string, cascadeUserGrantIDs ...string) (details *domain.ObjectDetails, err error) {
|
||||
@@ -127,10 +171,14 @@ func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resour
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
return details, zerrors.ThrowNotFound(nil, "COMMAND-m9vMf", "Errors.Project.Role.NotExisting")
|
||||
// return if project role is not existing
|
||||
if !existingRole.State.Exists() {
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
if err := c.checkPermissionDeleteProjectRole(ctx, existingRole.ResourceOwner, existingRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &existingRole.WriteModel)
|
||||
events := []eventstore.Command{
|
||||
project.NewRoleRemovedEvent(ctx, projectAgg, key),
|
||||
}
|
||||
@@ -153,15 +201,11 @@ func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resour
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingRole, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, existingRole, events...)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProjectRole(ctx context.Context, resourceOwner, roleKey string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectRoleDelete, resourceOwner, roleKey)
|
||||
}
|
||||
|
||||
func (c *Commands) getProjectRoleWriteModelByID(ctx context.Context, key, projectID, resourceOwner string) (*ProjectRoleWriteModel, error) {
|
||||
|
||||
@@ -17,6 +17,10 @@ type ProjectRoleWriteModel struct {
|
||||
State domain.ProjectRoleState
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) GetWriteModel() *eventstore.WriteModel {
|
||||
return &wm.WriteModel
|
||||
}
|
||||
|
||||
func NewProjectRoleWriteModelWithKey(key, projectID, resourceOwner string) *ProjectRoleWriteModel {
|
||||
return &ProjectRoleWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
|
||||
@@ -16,15 +16,15 @@ import (
|
||||
|
||||
func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
role *domain.ProjectRole
|
||||
resourceOwner string
|
||||
ctx context.Context
|
||||
role *AddProjectRole
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ProjectRole
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -36,8 +36,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -55,16 +54,16 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
@@ -73,8 +72,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -85,15 +83,15 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
@@ -102,8 +100,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role key already exists, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -123,10 +120,11 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -134,7 +132,6 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorAlreadyExists,
|
||||
@@ -143,8 +140,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "add role,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -164,10 +160,11 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -175,10 +172,41 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ProjectRole{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add role, resourceowner, ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"projectname1", true, true, true,
|
||||
domain.PrivateLabelingSettingUnspecified,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
project.NewRoleAddedEvent(
|
||||
context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"key1",
|
||||
"key",
|
||||
"group",
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
@@ -188,14 +216,20 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
Group: "group",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.AddProjectRole(tt.args.ctx, tt.args.role, tt.args.resourceOwner)
|
||||
got, err := r.AddProjectRole(tt.args.ctx, tt.args.role)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -203,7 +237,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -211,11 +245,12 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
roles []*domain.ProjectRole
|
||||
roles []*AddProjectRole
|
||||
projectID string
|
||||
resourceOwner string
|
||||
}
|
||||
@@ -232,8 +267,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -251,10 +285,11 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
@@ -271,8 +306,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -283,10 +317,11 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{},
|
||||
},
|
||||
@@ -304,8 +339,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role key already exists, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -332,16 +366,23 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key2",
|
||||
DisplayName: "key2",
|
||||
Group: "group",
|
||||
@@ -357,8 +398,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "add roles,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -385,16 +425,23 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key2",
|
||||
DisplayName: "key2",
|
||||
Group: "group",
|
||||
@@ -413,7 +460,8 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.BulkAddProjectRole(tt.args.ctx, tt.args.projectID, tt.args.resourceOwner, tt.args.roles)
|
||||
if tt.res.err == nil {
|
||||
@@ -431,15 +479,15 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
role *domain.ProjectRole
|
||||
resourceOwner string
|
||||
ctx context.Context
|
||||
role *ChangeProjectRole
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ProjectRole
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -451,18 +499,16 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
@@ -471,8 +517,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -490,16 +535,16 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
@@ -508,8 +553,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -536,10 +580,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -547,7 +592,6 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
@@ -556,8 +600,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role not changed, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -578,10 +621,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -589,17 +633,17 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role changed, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -623,10 +667,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
newRoleChangedEvent(context.Background(), "project1", "org1", "key1", "keychanged", "groupchanged"),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -634,17 +679,10 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "keychanged",
|
||||
Group: "groupchanged",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "keychanged",
|
||||
Group: "groupchanged",
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -652,9 +690,10 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.ChangeProjectRole(tt.args.ctx, tt.args.role, tt.args.resourceOwner)
|
||||
got, err := r.ChangeProjectRole(tt.args.ctx, tt.args.role)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -662,7 +701,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -670,7 +709,8 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -693,9 +733,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid projectid, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -709,9 +748,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid key, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -726,10 +764,10 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -738,14 +776,15 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role removed, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -763,6 +802,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -771,14 +811,15 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role removed, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -796,6 +837,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -812,8 +854,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingProjectGrantids, grant not found, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -832,6 +873,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -849,8 +891,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingProjectGrantids, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -883,6 +924,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -900,8 +942,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingUserGrantIDs, grant not found, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -920,6 +961,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -937,8 +979,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingUserGrantIDs, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -969,6 +1010,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -987,7 +1029,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.RemoveProjectRole(tt.args.ctx, tt.args.projectID, tt.args.key, tt.args.resourceOwner, tt.args.cascadingProjectGrantIDs, tt.args.cascadingUserGrantIDs...)
|
||||
if tt.res.err == nil {
|
||||
|
||||
+645
-200
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,15 @@ const (
|
||||
PermissionOrgRead = "org.read"
|
||||
PermissionIDPRead = "iam.idp.read"
|
||||
PermissionOrgIDPRead = "org.idp.read"
|
||||
PermissionProjectWrite = "project.write"
|
||||
PermissionProjectRead = "project.read"
|
||||
PermissionProjectDelete = "project.delete"
|
||||
PermissionProjectGrantWrite = "project.grant.write"
|
||||
PermissionProjectGrantRead = "project.grant.read"
|
||||
PermissionProjectGrantDelete = "project.grant.delete"
|
||||
PermissionProjectRoleWrite = "project.role.write"
|
||||
PermissionProjectRoleRead = "project.role.read"
|
||||
PermissionProjectRoleDelete = "project.role.delete"
|
||||
)
|
||||
|
||||
// ProjectPermissionCheck is used as a check for preconditions dependent on application, project, user resourceowner and usergrants.
|
||||
|
||||
@@ -26,17 +26,12 @@ func (s ProjectGrantState) Valid() bool {
|
||||
return s > ProjectGrantStateUnspecified && s < projectGrantStateMax
|
||||
}
|
||||
|
||||
func (p *ProjectGrant) IsValid() bool {
|
||||
return p.GrantedOrgID != ""
|
||||
func (s ProjectGrantState) Exists() bool {
|
||||
return s != ProjectGrantStateUnspecified && s != ProjectGrantStateRemoved
|
||||
}
|
||||
|
||||
func (g *ProjectGrant) HasInvalidRoles(validRoles []string) bool {
|
||||
for _, roleKey := range g.RoleKeys {
|
||||
if !containsRoleKey(roleKey, validRoles) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (p *ProjectGrant) IsValid() bool {
|
||||
return p.GrantedOrgID != ""
|
||||
}
|
||||
|
||||
func GetRemovedRoles(existingRoles, newRoles []string) []string {
|
||||
|
||||
@@ -20,14 +20,23 @@ const (
|
||||
ProjectRoleStateRemoved
|
||||
)
|
||||
|
||||
func NewProjectRole(projectID, key string) *ProjectRole {
|
||||
return &ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: projectID}, Key: key}
|
||||
func (s ProjectRoleState) Exists() bool {
|
||||
return s != ProjectRoleStateUnspecified && s != ProjectRoleStateRemoved
|
||||
}
|
||||
|
||||
func (p *ProjectRole) IsValid() bool {
|
||||
return p.AggregateID != "" && p.Key != ""
|
||||
}
|
||||
|
||||
func HasInvalidRoles(validRoles, roles []string) bool {
|
||||
for _, roleKey := range roles {
|
||||
if !containsRoleKey(roleKey, validRoles) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func containsRoleKey(roleKey string, validRoles []string) bool {
|
||||
for _, validRole := range validRoles {
|
||||
if roleKey == validRole {
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
oidc_pb_v2beta "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
org_v2beta "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
|
||||
project_v2beta "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
user_v3alpha "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
|
||||
userschema_v3alpha "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
saml_pb "github.com/zitadel/zitadel/pkg/grpc/saml/v2"
|
||||
@@ -71,6 +72,7 @@ type Client struct {
|
||||
UserV3Alpha user_v3alpha.ZITADELUsersClient
|
||||
SAMLv2 saml_pb.SAMLServiceClient
|
||||
SCIM *scim.Client
|
||||
Projectv2Beta project_v2beta.ProjectServiceClient
|
||||
InstanceV2Beta instance.InstanceServiceClient
|
||||
}
|
||||
|
||||
@@ -109,6 +111,7 @@ func newClient(ctx context.Context, target string) (*Client, error) {
|
||||
UserV3Alpha: user_v3alpha.NewZITADELUsersClient(cc),
|
||||
SAMLv2: saml_pb.NewSAMLServiceClient(cc),
|
||||
SCIM: scim.NewScimClient(target),
|
||||
Projectv2Beta: project_v2beta.NewProjectServiceClient(cc),
|
||||
InstanceV2Beta: instance.NewInstanceServiceClient(cc),
|
||||
}
|
||||
return client, client.pollHealth(ctx)
|
||||
@@ -446,6 +449,70 @@ func (i *Instance) SetUserPassword(ctx context.Context, userID, password string,
|
||||
return resp.GetDetails()
|
||||
}
|
||||
|
||||
func (i *Instance) CreateProject(ctx context.Context, t *testing.T, orgID, name string, projectRoleCheck, hasProjectCheck bool) *project_v2beta.CreateProjectResponse {
|
||||
if orgID == "" {
|
||||
orgID = i.DefaultOrg.GetId()
|
||||
}
|
||||
|
||||
resp, err := i.Client.Projectv2Beta.CreateProject(ctx, &project_v2beta.CreateProjectRequest{
|
||||
OrganizationId: orgID,
|
||||
Name: name,
|
||||
AuthorizationRequired: projectRoleCheck,
|
||||
ProjectAccessRequired: hasProjectCheck,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) DeleteProject(ctx context.Context, t *testing.T, projectID string) *project_v2beta.DeleteProjectResponse {
|
||||
resp, err := i.Client.Projectv2Beta.DeleteProject(ctx, &project_v2beta.DeleteProjectRequest{
|
||||
Id: projectID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) DeactivateProject(ctx context.Context, t *testing.T, projectID string) *project_v2beta.DeactivateProjectResponse {
|
||||
resp, err := i.Client.Projectv2Beta.DeactivateProject(ctx, &project_v2beta.DeactivateProjectRequest{
|
||||
Id: projectID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) ActivateProject(ctx context.Context, t *testing.T, projectID string) *project_v2beta.ActivateProjectResponse {
|
||||
resp, err := i.Client.Projectv2Beta.ActivateProject(ctx, &project_v2beta.ActivateProjectRequest{
|
||||
Id: projectID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) AddProjectRole(ctx context.Context, t *testing.T, projectID, roleKey, displayName, group string) *project_v2beta.AddProjectRoleResponse {
|
||||
var groupP *string
|
||||
if group != "" {
|
||||
groupP = &group
|
||||
}
|
||||
|
||||
resp, err := i.Client.Projectv2Beta.AddProjectRole(ctx, &project_v2beta.AddProjectRoleRequest{
|
||||
ProjectId: projectID,
|
||||
RoleKey: roleKey,
|
||||
DisplayName: displayName,
|
||||
Group: groupP,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) RemoveProjectRole(ctx context.Context, t *testing.T, projectID, roleKey string) *project_v2beta.RemoveProjectRoleResponse {
|
||||
resp, err := i.Client.Projectv2Beta.RemoveProjectRole(ctx, &project_v2beta.RemoveProjectRoleRequest{
|
||||
ProjectId: projectID,
|
||||
RoleKey: roleKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) AddProviderToDefaultLoginPolicy(ctx context.Context, id string) {
|
||||
_, err := i.Client.Admin.AddIDPToLoginPolicy(ctx, &admin.AddIDPToLoginPolicyRequest{
|
||||
IdpId: id,
|
||||
@@ -705,12 +772,40 @@ func (i *Instance) CreateIntentSession(t *testing.T, ctx context.Context, userID
|
||||
createResp.GetDetails().GetChangeDate().AsTime(), createResp.GetDetails().GetChangeDate().AsTime()
|
||||
}
|
||||
|
||||
func (i *Instance) CreateProjectGrant(ctx context.Context, projectID, grantedOrgID string) *mgmt.AddProjectGrantResponse {
|
||||
resp, err := i.Client.Mgmt.AddProjectGrant(ctx, &mgmt.AddProjectGrantRequest{
|
||||
GrantedOrgId: grantedOrgID,
|
||||
ProjectId: projectID,
|
||||
func (i *Instance) CreateProjectGrant(ctx context.Context, t *testing.T, projectID, grantedOrgID string, roles ...string) *project_v2beta.CreateProjectGrantResponse {
|
||||
resp, err := i.Client.Projectv2Beta.CreateProjectGrant(ctx, &project_v2beta.CreateProjectGrantRequest{
|
||||
GrantedOrganizationId: grantedOrgID,
|
||||
ProjectId: projectID,
|
||||
RoleKeys: roles,
|
||||
})
|
||||
logging.OnError(err).Panic("create project grant")
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) DeleteProjectGrant(ctx context.Context, t *testing.T, projectID, grantedOrgID string) *project_v2beta.DeleteProjectGrantResponse {
|
||||
resp, err := i.Client.Projectv2Beta.DeleteProjectGrant(ctx, &project_v2beta.DeleteProjectGrantRequest{
|
||||
GrantedOrganizationId: grantedOrgID,
|
||||
ProjectId: projectID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) DeactivateProjectGrant(ctx context.Context, t *testing.T, projectID, grantedOrgID string) *project_v2beta.DeactivateProjectGrantResponse {
|
||||
resp, err := i.Client.Projectv2Beta.DeactivateProjectGrant(ctx, &project_v2beta.DeactivateProjectGrantRequest{
|
||||
ProjectId: projectID,
|
||||
GrantedOrganizationId: grantedOrgID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (i *Instance) ActivateProjectGrant(ctx context.Context, t *testing.T, projectID, grantedOrgID string) *project_v2beta.ActivateProjectGrantResponse {
|
||||
resp, err := i.Client.Projectv2Beta.ActivateProjectGrant(ctx, &project_v2beta.ActivateProjectGrantRequest{
|
||||
ProjectId: projectID,
|
||||
GrantedOrganizationId: grantedOrgID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
@@ -133,13 +134,9 @@ func (i *Instance) CreateOIDCInactivateProjectClient(ctx context.Context, redire
|
||||
return client, err
|
||||
}
|
||||
|
||||
func (i *Instance) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI string, loginVersion *app.LoginVersion) (*management.AddOIDCAppResponse, error) {
|
||||
project, err := i.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||||
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (i *Instance) CreateOIDCImplicitFlowClient(ctx context.Context, t *testing.T, redirectURI string, loginVersion *app.LoginVersion) (*management.AddOIDCAppResponse, error) {
|
||||
project := i.CreateProject(ctx, t, "", gofakeit.AppName(), false, false)
|
||||
|
||||
resp, err := i.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
|
||||
ProjectId: project.GetId(),
|
||||
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
|
||||
@@ -178,30 +175,11 @@ func (i *Instance) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI
|
||||
})
|
||||
}
|
||||
|
||||
func (i *Instance) CreateOIDCTokenExchangeClient(ctx context.Context) (client *management.AddOIDCAppResponse, keyData []byte, err error) {
|
||||
project, err := i.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||||
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
func (i *Instance) CreateOIDCTokenExchangeClient(ctx context.Context, t *testing.T) (client *management.AddOIDCAppResponse, keyData []byte, err error) {
|
||||
project := i.CreateProject(ctx, t, "", gofakeit.AppName(), false, false)
|
||||
return i.CreateOIDCWebClientJWT(ctx, "", "", project.GetId(), app.OIDCGrantType_OIDC_GRANT_TYPE_TOKEN_EXCHANGE, app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE, app.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN)
|
||||
}
|
||||
|
||||
func (i *Instance) CreateProject(ctx context.Context) (*management.AddProjectResponse, error) {
|
||||
return i.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||||
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||||
})
|
||||
}
|
||||
|
||||
func (i *Instance) CreateProjectWithPermissionCheck(ctx context.Context, projectRoleCheck, hasProjectCheck bool) (*management.AddProjectResponse, error) {
|
||||
return i.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||||
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||||
HasProjectCheck: hasProjectCheck,
|
||||
ProjectRoleCheck: projectRoleCheck,
|
||||
})
|
||||
}
|
||||
|
||||
func (i *Instance) CreateAPIClientJWT(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) {
|
||||
return i.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{
|
||||
ProjectId: projectID,
|
||||
|
||||
+370
-2
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
@@ -72,11 +73,104 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
grantedProjectsAlias = table{
|
||||
name: "granted_projects",
|
||||
instanceIDCol: projection.ProjectColumnInstanceID,
|
||||
}
|
||||
GrantedProjectColumnID = Column{
|
||||
name: projection.ProjectColumnID,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
GrantedProjectColumnCreationDate = Column{
|
||||
name: projection.ProjectColumnCreationDate,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
GrantedProjectColumnChangeDate = Column{
|
||||
name: projection.ProjectColumnChangeDate,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnResourceOwner = Column{
|
||||
name: projection.ProjectColumnResourceOwner,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnInstanceID = Column{
|
||||
name: projection.ProjectGrantColumnInstanceID,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnState = Column{
|
||||
name: "project_state",
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
GrantedProjectColumnName = Column{
|
||||
name: "project_name",
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnProjectRoleAssertion = Column{
|
||||
name: projection.ProjectColumnProjectRoleAssertion,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnProjectRoleCheck = Column{
|
||||
name: projection.ProjectColumnProjectRoleCheck,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnHasProjectCheck = Column{
|
||||
name: projection.ProjectColumnHasProjectCheck,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnPrivateLabelingSetting = Column{
|
||||
name: projection.ProjectColumnPrivateLabelingSetting,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnGrantResourceOwner = Column{
|
||||
name: "project_grant_resource_owner",
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnGrantedOrganization = Column{
|
||||
name: projection.ProjectGrantColumnGrantedOrgID,
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnGrantedOrganizationName = Column{
|
||||
name: "granted_org_name",
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
grantedProjectColumnGrantState = Column{
|
||||
name: "project_grant_state",
|
||||
table: grantedProjectsAlias,
|
||||
}
|
||||
)
|
||||
|
||||
type Projects struct {
|
||||
SearchResponse
|
||||
Projects []*Project
|
||||
}
|
||||
|
||||
func projectsCheckPermission(ctx context.Context, projects *Projects, permissionCheck domain.PermissionCheck) {
|
||||
projects.Projects = slices.DeleteFunc(projects.Projects,
|
||||
func(project *Project) bool {
|
||||
return projectCheckPermission(ctx, project.ResourceOwner, project.ID, permissionCheck) != nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func projectCheckPermission(ctx context.Context, resourceOwner string, projectID string, permissionCheck domain.PermissionCheck) error {
|
||||
return permissionCheck(ctx, domain.PermissionProjectRead, resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func projectPermissionCheckV2(ctx context.Context, query sq.SelectBuilder, enabled bool, queries *ProjectAndGrantedProjectSearchQueries) sq.SelectBuilder {
|
||||
if !enabled {
|
||||
return query
|
||||
}
|
||||
join, args := PermissionClause(
|
||||
ctx,
|
||||
grantedProjectColumnResourceOwner,
|
||||
domain.PermissionProjectRead,
|
||||
SingleOrgPermissionOption(queries.Queries),
|
||||
OwnedRowsPermissionOption(GrantedProjectColumnID),
|
||||
)
|
||||
return query.JoinClause(join, args...)
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
ID string
|
||||
CreationDate time.Time
|
||||
@@ -94,7 +188,19 @@ type Project struct {
|
||||
|
||||
type ProjectSearchQueries struct {
|
||||
SearchRequest
|
||||
Queries []SearchQuery
|
||||
Queries []SearchQuery
|
||||
GrantQueries []SearchQuery
|
||||
}
|
||||
|
||||
func (q *Queries) GetProjectByIDWithPermission(ctx context.Context, shouldTriggerBulk bool, id string, permissionCheck domain.PermissionCheck) (*Project, error) {
|
||||
project, err := q.ProjectByID(ctx, shouldTriggerBulk, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := projectCheckPermission(ctx, project.ResourceOwner, project.ID, permissionCheck); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id string) (project *Project, err error) {
|
||||
@@ -125,7 +231,18 @@ func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id st
|
||||
return project, err
|
||||
}
|
||||
|
||||
func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQueries) (projects *Projects, err error) {
|
||||
func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQueries, permissionCheck domain.PermissionCheck) (*Projects, error) {
|
||||
projects, err := q.searchProjects(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if permissionCheck != nil {
|
||||
projectsCheckPermission(ctx, projects, permissionCheck)
|
||||
}
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
func (q *Queries) searchProjects(ctx context.Context, queries *ProjectSearchQueries) (projects *Projects, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -147,6 +264,89 @@ func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQuer
|
||||
return projects, err
|
||||
}
|
||||
|
||||
type ProjectAndGrantedProjectSearchQueries struct {
|
||||
SearchRequest
|
||||
Queries []SearchQuery
|
||||
}
|
||||
|
||||
func (q *ProjectAndGrantedProjectSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||
query = q.SearchRequest.toQuery(query)
|
||||
for _, q := range q.Queries {
|
||||
query = q.toQuery(query)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func (q *Queries) SearchGrantedProjects(ctx context.Context, queries *ProjectAndGrantedProjectSearchQueries, permissionCheck domain.PermissionCheck) (*GrantedProjects, error) {
|
||||
permissionCheckV2 := PermissionV2(ctx, permissionCheck)
|
||||
projects, err := q.searchGrantedProjects(ctx, queries, permissionCheckV2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if permissionCheck != nil && !authz.GetFeatures(ctx).PermissionCheckV2 {
|
||||
grantedProjectsCheckPermission(ctx, projects, permissionCheck)
|
||||
}
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
func (q *Queries) searchGrantedProjects(ctx context.Context, queries *ProjectAndGrantedProjectSearchQueries, permissionCheckV2 bool) (grantedProjects *GrantedProjects, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareGrantedProjectsQuery()
|
||||
query = projectPermissionCheckV2(ctx, query, permissionCheckV2, queries)
|
||||
eq := sq.Eq{grantedProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "QUERY-T84X9", "Errors.Query.InvalidRequest")
|
||||
}
|
||||
|
||||
err = q.client.QueryContext(ctx, func(rows *sql.Rows) error {
|
||||
grantedProjects, err = scan(rows)
|
||||
return err
|
||||
}, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return grantedProjects, nil
|
||||
}
|
||||
|
||||
func NewGrantedProjectNameSearchQuery(method TextComparison, value string) (SearchQuery, error) {
|
||||
return NewTextQuery(GrantedProjectColumnName, value, method)
|
||||
}
|
||||
|
||||
func NewGrantedProjectResourceOwnerSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(grantedProjectColumnResourceOwner, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewGrantedProjectIDSearchQuery(ids []string) (SearchQuery, error) {
|
||||
list := make([]interface{}, len(ids))
|
||||
for i, value := range ids {
|
||||
list[i] = value
|
||||
}
|
||||
return NewListQuery(GrantedProjectColumnID, list, ListIn)
|
||||
}
|
||||
|
||||
func NewGrantedProjectOrganizationIDSearchQuery(value string) (SearchQuery, error) {
|
||||
project, err := NewTextQuery(grantedProjectColumnResourceOwner, value, TextEquals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant, err := NewTextQuery(grantedProjectColumnGrantedOrganization, value, TextEquals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewOrQuery(project, grant)
|
||||
}
|
||||
|
||||
func NewGrantedProjectGrantResourceOwnerSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(grantedProjectColumnGrantResourceOwner, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewGrantedProjectGrantedOrganizationIDSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(grantedProjectColumnGrantedOrganization, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewProjectNameSearchQuery(method TextComparison, value string) (SearchQuery, error) {
|
||||
return NewTextQuery(ProjectColumnName, value, method)
|
||||
}
|
||||
@@ -285,3 +485,171 @@ func prepareProjectsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Projects, error
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type GrantedProjects struct {
|
||||
SearchResponse
|
||||
GrantedProjects []*GrantedProject
|
||||
}
|
||||
|
||||
func grantedProjectsCheckPermission(ctx context.Context, grantedProjects *GrantedProjects, permissionCheck domain.PermissionCheck) {
|
||||
grantedProjects.GrantedProjects = slices.DeleteFunc(grantedProjects.GrantedProjects,
|
||||
func(grantedProject *GrantedProject) bool {
|
||||
return projectCheckPermission(ctx, grantedProject.ResourceOwner, grantedProject.ProjectID, permissionCheck) != nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type GrantedProject struct {
|
||||
ProjectID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
ResourceOwner string
|
||||
InstanceID string
|
||||
ProjectState domain.ProjectState
|
||||
ProjectName string
|
||||
|
||||
ProjectRoleAssertion bool
|
||||
ProjectRoleCheck bool
|
||||
HasProjectCheck bool
|
||||
PrivateLabelingSetting domain.PrivateLabelingSetting
|
||||
|
||||
GrantedOrgID string
|
||||
OrgName string
|
||||
ProjectGrantState domain.ProjectGrantState
|
||||
}
|
||||
|
||||
func prepareGrantedProjectsQuery() (sq.SelectBuilder, func(*sql.Rows) (*GrantedProjects, error)) {
|
||||
return sq.Select(
|
||||
GrantedProjectColumnID.identifier(),
|
||||
GrantedProjectColumnCreationDate.identifier(),
|
||||
GrantedProjectColumnChangeDate.identifier(),
|
||||
grantedProjectColumnResourceOwner.identifier(),
|
||||
grantedProjectColumnInstanceID.identifier(),
|
||||
grantedProjectColumnState.identifier(),
|
||||
GrantedProjectColumnName.identifier(),
|
||||
grantedProjectColumnProjectRoleAssertion.identifier(),
|
||||
grantedProjectColumnProjectRoleCheck.identifier(),
|
||||
grantedProjectColumnHasProjectCheck.identifier(),
|
||||
grantedProjectColumnPrivateLabelingSetting.identifier(),
|
||||
grantedProjectColumnGrantedOrganization.identifier(),
|
||||
grantedProjectColumnGrantedOrganizationName.identifier(),
|
||||
grantedProjectColumnGrantState.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(getProjectsAndGrantedProjectsFromQuery()).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*GrantedProjects, error) {
|
||||
projects := make([]*GrantedProject, 0)
|
||||
var (
|
||||
count uint64
|
||||
orgID = sql.NullString{}
|
||||
orgName = sql.NullString{}
|
||||
projectGrantState = sql.NullInt16{}
|
||||
)
|
||||
for rows.Next() {
|
||||
grantedProject := new(GrantedProject)
|
||||
err := rows.Scan(
|
||||
&grantedProject.ProjectID,
|
||||
&grantedProject.CreationDate,
|
||||
&grantedProject.ChangeDate,
|
||||
&grantedProject.ResourceOwner,
|
||||
&grantedProject.InstanceID,
|
||||
&grantedProject.ProjectState,
|
||||
&grantedProject.ProjectName,
|
||||
&grantedProject.ProjectRoleAssertion,
|
||||
&grantedProject.ProjectRoleCheck,
|
||||
&grantedProject.HasProjectCheck,
|
||||
&grantedProject.PrivateLabelingSetting,
|
||||
&orgID,
|
||||
&orgName,
|
||||
&projectGrantState,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if orgID.Valid {
|
||||
grantedProject.GrantedOrgID = orgID.String
|
||||
}
|
||||
if orgName.Valid {
|
||||
grantedProject.OrgName = orgName.String
|
||||
}
|
||||
if projectGrantState.Valid {
|
||||
grantedProject.ProjectGrantState = domain.ProjectGrantState(projectGrantState.Int16)
|
||||
}
|
||||
projects = append(projects, grantedProject)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-K9gEE", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &GrantedProjects{
|
||||
GrantedProjects: projects,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getProjectsAndGrantedProjectsFromQuery() string {
|
||||
return "(" +
|
||||
prepareProjects() +
|
||||
" UNION ALL " +
|
||||
prepareGrantedProjects() +
|
||||
") AS " + grantedProjectsAlias.identifier()
|
||||
}
|
||||
|
||||
func prepareProjects() string {
|
||||
builder := sq.Select(
|
||||
ProjectColumnID.identifier()+" AS "+GrantedProjectColumnID.name,
|
||||
ProjectColumnCreationDate.identifier()+" AS "+GrantedProjectColumnCreationDate.name,
|
||||
ProjectColumnChangeDate.identifier()+" AS "+GrantedProjectColumnChangeDate.name,
|
||||
ProjectColumnResourceOwner.identifier()+" AS "+grantedProjectColumnResourceOwner.name,
|
||||
ProjectColumnInstanceID.identifier()+" AS "+grantedProjectColumnInstanceID.name,
|
||||
ProjectColumnState.identifier()+" AS "+grantedProjectColumnState.name,
|
||||
ProjectColumnName.identifier()+" AS "+GrantedProjectColumnName.name,
|
||||
ProjectColumnProjectRoleAssertion.identifier()+" AS "+grantedProjectColumnProjectRoleAssertion.name,
|
||||
ProjectColumnProjectRoleCheck.identifier()+" AS "+grantedProjectColumnProjectRoleCheck.name,
|
||||
ProjectColumnHasProjectCheck.identifier()+" AS "+grantedProjectColumnHasProjectCheck.name,
|
||||
ProjectColumnPrivateLabelingSetting.identifier()+" AS "+grantedProjectColumnPrivateLabelingSetting.name,
|
||||
"NULL::TEXT AS "+grantedProjectColumnGrantResourceOwner.name,
|
||||
"NULL::TEXT AS "+grantedProjectColumnGrantedOrganization.name,
|
||||
"NULL::TEXT AS "+grantedProjectColumnGrantedOrganizationName.name,
|
||||
"NULL::SMALLINT AS "+grantedProjectColumnGrantState.name,
|
||||
countColumn.identifier()).
|
||||
From(projectsTable.identifier()).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
|
||||
stmt, _ := builder.MustSql()
|
||||
return stmt
|
||||
}
|
||||
|
||||
func prepareGrantedProjects() string {
|
||||
grantedOrgTable := orgsTable.setAlias(ProjectGrantGrantedOrgTableAlias)
|
||||
grantedOrgIDColumn := OrgColumnID.setTable(grantedOrgTable)
|
||||
builder := sq.Select(
|
||||
ProjectGrantColumnProjectID.identifier()+" AS "+GrantedProjectColumnID.name,
|
||||
ProjectGrantColumnCreationDate.identifier()+" AS "+GrantedProjectColumnCreationDate.name,
|
||||
ProjectGrantColumnChangeDate.identifier()+" AS "+GrantedProjectColumnChangeDate.name,
|
||||
ProjectColumnResourceOwner.identifier()+" AS "+grantedProjectColumnResourceOwner.name,
|
||||
ProjectGrantColumnInstanceID.identifier()+" AS "+grantedProjectColumnInstanceID.name,
|
||||
ProjectColumnState.identifier()+" AS "+grantedProjectColumnState.name,
|
||||
ProjectColumnName.identifier()+" AS "+GrantedProjectColumnName.name,
|
||||
ProjectColumnProjectRoleAssertion.identifier()+" AS "+grantedProjectColumnProjectRoleAssertion.name,
|
||||
ProjectColumnProjectRoleCheck.identifier()+" AS "+grantedProjectColumnProjectRoleCheck.name,
|
||||
ProjectColumnHasProjectCheck.identifier()+" AS "+grantedProjectColumnHasProjectCheck.name,
|
||||
ProjectColumnPrivateLabelingSetting.identifier()+" AS "+grantedProjectColumnPrivateLabelingSetting.name,
|
||||
ProjectGrantColumnResourceOwner.identifier()+" AS "+grantedProjectColumnGrantResourceOwner.name,
|
||||
ProjectGrantColumnGrantedOrgID.identifier()+" AS "+grantedProjectColumnGrantedOrganization.name,
|
||||
ProjectGrantColumnGrantedOrgName.identifier()+" AS "+grantedProjectColumnGrantedOrganizationName.name,
|
||||
ProjectGrantColumnState.identifier()+" AS "+grantedProjectColumnGrantState.name,
|
||||
countColumn.identifier()).
|
||||
From(projectGrantsTable.identifier()).
|
||||
PlaceholderFormat(sq.Dollar).
|
||||
LeftJoin(join(ProjectColumnID, ProjectGrantColumnProjectID)).
|
||||
LeftJoin(join(grantedOrgIDColumn, ProjectGrantColumnGrantedOrgID))
|
||||
|
||||
stmt, _ := builder.MustSql()
|
||||
return stmt
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
@@ -104,6 +105,43 @@ type ProjectGrantSearchQueries struct {
|
||||
Queries []SearchQuery
|
||||
}
|
||||
|
||||
func projectGrantsCheckPermission(ctx context.Context, projectGrants *ProjectGrants, permissionCheck domain.PermissionCheck) {
|
||||
projectGrants.ProjectGrants = slices.DeleteFunc(projectGrants.ProjectGrants,
|
||||
func(projectGrant *ProjectGrant) bool {
|
||||
return projectGrantCheckPermission(ctx, projectGrant.ResourceOwner, projectGrant.GrantID, permissionCheck) != nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func projectGrantCheckPermission(ctx context.Context, resourceOwner string, grantID string, permissionCheck domain.PermissionCheck) error {
|
||||
return permissionCheck(ctx, domain.PermissionProjectGrantRead, resourceOwner, grantID)
|
||||
}
|
||||
|
||||
func projectGrantPermissionCheckV2(ctx context.Context, query sq.SelectBuilder, enabled bool, queries *ProjectGrantSearchQueries) sq.SelectBuilder {
|
||||
if !enabled {
|
||||
return query
|
||||
}
|
||||
join, args := PermissionClause(
|
||||
ctx,
|
||||
ProjectGrantColumnResourceOwner,
|
||||
domain.PermissionProjectGrantRead,
|
||||
SingleOrgPermissionOption(queries.Queries),
|
||||
OwnedRowsPermissionOption(ProjectGrantColumnGrantID),
|
||||
)
|
||||
return query.JoinClause(join, args...)
|
||||
}
|
||||
|
||||
func (q *Queries) GetProjectGrantByIDWithPermission(ctx context.Context, shouldTriggerBulk bool, id string, permissionCheck domain.PermissionCheck) (*ProjectGrant, error) {
|
||||
projectGrant, err := q.ProjectGrantByID(ctx, shouldTriggerBulk, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := projectCheckPermission(ctx, projectGrant.ResourceOwner, projectGrant.GrantID, permissionCheck); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrant, nil
|
||||
}
|
||||
|
||||
func (q *Queries) ProjectGrantByID(ctx context.Context, shouldTriggerBulk bool, id string) (grant *ProjectGrant, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -154,11 +192,24 @@ func (q *Queries) ProjectGrantByIDAndGrantedOrg(ctx context.Context, id, granted
|
||||
return grant, err
|
||||
}
|
||||
|
||||
func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrantSearchQueries) (grants *ProjectGrants, err error) {
|
||||
func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrantSearchQueries, permissionCheck domain.PermissionCheck) (grants *ProjectGrants, err error) {
|
||||
permissionCheckV2 := PermissionV2(ctx, permissionCheck)
|
||||
projectsGrants, err := q.searchProjectGrants(ctx, queries, permissionCheckV2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if permissionCheck != nil && !authz.GetFeatures(ctx).PermissionCheckV2 {
|
||||
projectGrantsCheckPermission(ctx, projectsGrants, permissionCheck)
|
||||
}
|
||||
return projectsGrants, nil
|
||||
}
|
||||
|
||||
func (q *Queries) searchProjectGrants(ctx context.Context, queries *ProjectGrantSearchQueries, permissionCheckV2 bool) (grants *ProjectGrants, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareProjectGrantsQuery()
|
||||
query = projectGrantPermissionCheckV2(ctx, query, permissionCheckV2, queries)
|
||||
eq := sq.Eq{
|
||||
ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
@@ -179,6 +230,7 @@ func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrant
|
||||
return grants, err
|
||||
}
|
||||
|
||||
// SearchProjectGrantsByProjectIDAndRoleKey is used internally to remove the roles of a project grant, so no permission check necessary
|
||||
func (q *Queries) SearchProjectGrantsByProjectIDAndRoleKey(ctx context.Context, projectID, roleKey string) (projects *ProjectGrants, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -195,13 +247,33 @@ func (q *Queries) SearchProjectGrantsByProjectIDAndRoleKey(ctx context.Context,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q.SearchProjectGrants(ctx, searchQuery)
|
||||
return q.SearchProjectGrants(ctx, searchQuery, nil)
|
||||
}
|
||||
|
||||
func NewProjectGrantProjectIDSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(ProjectGrantColumnProjectID, value, TextEquals)
|
||||
}
|
||||
|
||||
func (q *ProjectGrantSearchQueries) AppendPermissionQueries(permissions []string) error {
|
||||
if !authz.HasGlobalPermission(permissions) {
|
||||
ids := authz.GetAllPermissionCtxIDs(permissions)
|
||||
query, err := NewProjectGrantIDsSearchQuery(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Queries = append(q.Queries, query)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewProjectGrantProjectIDsSearchQuery(ids []string) (SearchQuery, error) {
|
||||
list := make([]interface{}, len(ids))
|
||||
for i, value := range ids {
|
||||
list[i] = value
|
||||
}
|
||||
return NewListQuery(ProjectGrantColumnProjectID, list, ListIn)
|
||||
}
|
||||
|
||||
func NewProjectGrantIDsSearchQuery(values []string) (SearchQuery, error) {
|
||||
list := make([]interface{}, len(values))
|
||||
for i, value := range values {
|
||||
@@ -243,18 +315,6 @@ func (q *ProjectGrantSearchQueries) AppendGrantedOrgQuery(orgID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *ProjectGrantSearchQueries) AppendPermissionQueries(permissions []string) error {
|
||||
if !authz.HasGlobalPermission(permissions) {
|
||||
ids := authz.GetAllPermissionCtxIDs(permissions)
|
||||
query, err := NewProjectGrantIDsSearchQuery(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Queries = append(q.Queries, query)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *ProjectGrantSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||
query = q.SearchRequest.toQuery(query)
|
||||
for _, q := range q.Queries {
|
||||
|
||||
@@ -3,12 +3,14 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
@@ -80,7 +82,45 @@ type ProjectRoleSearchQueries struct {
|
||||
Queries []SearchQuery
|
||||
}
|
||||
|
||||
func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool, queries *ProjectRoleSearchQueries) (roles *ProjectRoles, err error) {
|
||||
func projectRolesCheckPermission(ctx context.Context, projectRoles *ProjectRoles, permissionCheck domain.PermissionCheck) {
|
||||
projectRoles.ProjectRoles = slices.DeleteFunc(projectRoles.ProjectRoles,
|
||||
func(projectRole *ProjectRole) bool {
|
||||
return projectRoleCheckPermission(ctx, projectRole.ResourceOwner, projectRole.Key, permissionCheck) != nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func projectRoleCheckPermission(ctx context.Context, resourceOwner string, grantID string, permissionCheck domain.PermissionCheck) error {
|
||||
return permissionCheck(ctx, domain.PermissionProjectGrantRead, resourceOwner, grantID)
|
||||
}
|
||||
|
||||
func projectRolePermissionCheckV2(ctx context.Context, query sq.SelectBuilder, enabled bool, queries *ProjectRoleSearchQueries) sq.SelectBuilder {
|
||||
if !enabled {
|
||||
return query
|
||||
}
|
||||
join, args := PermissionClause(
|
||||
ctx,
|
||||
ProjectRoleColumnResourceOwner,
|
||||
domain.PermissionProjectRoleRead,
|
||||
SingleOrgPermissionOption(queries.Queries),
|
||||
OwnedRowsPermissionOption(ProjectRoleColumnKey),
|
||||
)
|
||||
return query.JoinClause(join, args...)
|
||||
}
|
||||
|
||||
func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool, queries *ProjectRoleSearchQueries, permissionCheck domain.PermissionCheck) (roles *ProjectRoles, err error) {
|
||||
permissionCheckV2 := PermissionV2(ctx, permissionCheck)
|
||||
projectRoles, err := q.searchProjectRoles(ctx, shouldTriggerBulk, queries, permissionCheckV2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if permissionCheck != nil && !authz.GetFeatures(ctx).PermissionCheckV2 {
|
||||
projectRolesCheckPermission(ctx, projectRoles, permissionCheck)
|
||||
}
|
||||
return projectRoles, nil
|
||||
}
|
||||
|
||||
func (q *Queries) searchProjectRoles(ctx context.Context, shouldTriggerBulk bool, queries *ProjectRoleSearchQueries, permissionCheckV2 bool) (roles *ProjectRoles, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -94,6 +134,7 @@ func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool
|
||||
eq := sq.Eq{ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
|
||||
query, scan := prepareProjectRolesQuery()
|
||||
query = projectRolePermissionCheckV2(ctx, query, permissionCheckV2, queries)
|
||||
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
@@ -23,3 +25,7 @@ func NewAggregate(id, resourceOwner string) *Aggregate {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func AggregateFromWriteModel(ctx context.Context, wm *eventstore.WriteModel) *eventstore.Aggregate {
|
||||
return eventstore.AggregateFromWriteModelCtx(ctx, wm, AggregateType, AggregateVersion)
|
||||
}
|
||||
|
||||
@@ -184,10 +184,7 @@ func NewProjectChangeEvent(
|
||||
aggregate *eventstore.Aggregate,
|
||||
oldName string,
|
||||
changes []ProjectChanges,
|
||||
) (*ProjectChangeEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mV9xc", "Errors.NoChangesFound")
|
||||
}
|
||||
) *ProjectChangeEvent {
|
||||
changeEvent := &ProjectChangeEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
@@ -199,7 +196,7 @@ func NewProjectChangeEvent(
|
||||
for _, change := range changes {
|
||||
change(changeEvent)
|
||||
}
|
||||
return changeEvent, nil
|
||||
return changeEvent
|
||||
}
|
||||
|
||||
type ProjectChanges func(event *ProjectChangeEvent)
|
||||
|
||||
+132
-44
@@ -2678,6 +2678,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Get Project By ID
|
||||
//
|
||||
// Deprecated: [Get Project](apis/resources/project_service_v2/project-service-get-project.api.mdx) to get project by ID.
|
||||
//
|
||||
// Returns a project owned by the organization (no granted projects). A Project is a vessel for different applications sharing the same role context.
|
||||
rpc GetProjectByID(GetProjectByIDRequest) returns (GetProjectByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/projects/{id}"
|
||||
@@ -2690,8 +2695,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Get Project By ID";
|
||||
description: "Returns a project owned by the organization (no granted projects). A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2703,6 +2707,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Get Granted Project By ID
|
||||
//
|
||||
// Deprecated: [List Projects](apis/resources/project_service_v2/project-service-list-projects.api.mdx) to get granted projects.
|
||||
//
|
||||
// Returns a project owned by another organization and granted to my organization. A Project is a vessel for different applications sharing the same role context.
|
||||
rpc GetGrantedProjectByID(GetGrantedProjectByIDRequest) returns (GetGrantedProjectByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/granted_projects/{project_id}/grants/{grant_id}"
|
||||
@@ -2715,8 +2724,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Get Granted Project By ID";
|
||||
description: "Returns a project owned by another organization and granted to my organization. A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2728,6 +2736,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// List Projects
|
||||
//
|
||||
// Deprecated: [List Projects](apis/resources/project_service_v2/project-service-list-projects.api.mdx) to list all projects and granted projects.
|
||||
//
|
||||
// Lists projects my organization is the owner of (no granted projects). A Project is a vessel for different applications sharing the same role context.
|
||||
rpc ListProjects(ListProjectsRequest) returns (ListProjectsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/_search"
|
||||
@@ -2740,8 +2753,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Search Project";
|
||||
description: "Lists projects my organization is the owner of (no granted projects). A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2753,6 +2765,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// List Granted Projects
|
||||
//
|
||||
// Deprecated: [List Projects](apis/resources/project_service_v2/project-service-list-projects.api.mdx) to list all projects and granted projects.
|
||||
//
|
||||
// Lists projects my organization got granted from another organization. A Project is a vessel for different applications sharing the same role context.
|
||||
rpc ListGrantedProjects(ListGrantedProjectsRequest) returns (ListGrantedProjectsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/granted_projects/_search"
|
||||
@@ -2765,8 +2782,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Search Granted Project";
|
||||
description: "Lists projects my organization got granted from another organization. A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2828,6 +2844,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Create Project
|
||||
//
|
||||
// Deprecated: [Create Project](apis/resources/project_service_v2/project-service-create-project.api.mdx) to create a project.
|
||||
//
|
||||
// Create a new project. A Project is a vessel for different applications sharing the same role context.
|
||||
rpc AddProject(AddProjectRequest) returns (AddProjectResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects"
|
||||
@@ -2840,8 +2861,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Create Project";
|
||||
description: "Create a new project. A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2853,6 +2873,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Update Project
|
||||
//
|
||||
// Deprecated: [Update Project](apis/resources/project_service_v2/project-service-update-project.api.mdx) to update a project.
|
||||
//
|
||||
// Update a project and its settings. A Project is a vessel for different applications sharing the same role context.
|
||||
rpc UpdateProject(UpdateProjectRequest) returns (UpdateProjectResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/projects/{id}"
|
||||
@@ -2866,8 +2891,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Update Project";
|
||||
description: "Update a project and its settings. A Project is a vessel for different applications sharing the same role context."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2879,6 +2903,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Deactivate Project
|
||||
//
|
||||
// Deprecated: [Deactivate Project](apis/resources/project_service_v2/project-service-deactivate-project.api.mdx) to deactivate a project.
|
||||
//
|
||||
// Set the state of a project to deactivated. Request returns an error if the project is already deactivated.
|
||||
rpc DeactivateProject(DeactivateProjectRequest) returns (DeactivateProjectResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{id}/_deactivate"
|
||||
@@ -2892,8 +2921,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Deactivate Project";
|
||||
description: "Set the state of a project to deactivated. Request returns an error if the project is already deactivated."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2905,6 +2933,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Activate Project
|
||||
//
|
||||
// Deprecated: [Activate Project](apis/resources/project_service_v2/project-service-activate-project.api.mdx) to activate a project.
|
||||
//
|
||||
// Set the state of a project to active. Request returns an error if the project is not deactivated.
|
||||
rpc ReactivateProject(ReactivateProjectRequest) returns (ReactivateProjectResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{id}/_reactivate"
|
||||
@@ -2918,8 +2951,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Reactivate Project";
|
||||
description: "Set the state of a project to active. Request returns an error if the project is not deactivated."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2931,6 +2963,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Remove Project
|
||||
//
|
||||
// Deprecated: [Delete Project](apis/resources/project_service_v2/project-service-delete-project.api.mdx) to remove a project.
|
||||
//
|
||||
// Project and all its sub-resources like project grants, applications, roles and user grants will be removed.
|
||||
rpc RemoveProject(RemoveProjectRequest) returns (RemoveProjectResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/projects/{id}"
|
||||
@@ -2943,8 +2980,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Remove Project";
|
||||
description: "Project and all its sub-resources like project grants, applications, roles and user grants will be removed."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2956,6 +2992,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Search Project Roles
|
||||
//
|
||||
// Deprecated: [List Project Roles](apis/resources/project_service_v2/project-service-list-project-roles.api.mdx) to get project roles.
|
||||
//
|
||||
// Returns all roles of a project matching the search query.
|
||||
rpc ListProjectRoles(ListProjectRolesRequest) returns (ListProjectRolesResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/roles/_search"
|
||||
@@ -2969,8 +3010,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Roles";
|
||||
summary: "Search Project Roles";
|
||||
description: "Returns all roles of a project matching the search query."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -2982,6 +3022,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Add Project Role
|
||||
//
|
||||
// Deprecated: [Add Project Role](apis/resources/project_service_v2/project-service-add-project-role.api.mdx) to add a project role.
|
||||
//
|
||||
// Add a new project role to a project. The key must be unique within the project.\n\nDeprecated: please use user service v2 AddProjectRole.
|
||||
rpc AddProjectRole(AddProjectRoleRequest) returns (AddProjectRoleResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/roles"
|
||||
@@ -2995,8 +3040,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Roles";
|
||||
summary: "Add Project Role";
|
||||
description: "Add a new project role to a project. The key must be unique within the project."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3008,6 +3052,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Bulk add Project Role
|
||||
//
|
||||
// Deprecated: [Add Project Role](apis/resources/project_service_v2/project-service-add-project-role.api.mdx) to add a project role.
|
||||
//
|
||||
// Add a list of roles to a project. The keys must be unique within the project.
|
||||
rpc BulkAddProjectRoles(BulkAddProjectRolesRequest) returns (BulkAddProjectRolesResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/roles/_bulk"
|
||||
@@ -3021,8 +3070,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Roles";
|
||||
summary: "Bulk Add Project Role";
|
||||
description: "Add a list of roles to a project. The keys must be unique within the project."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3034,6 +3082,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Update Project Role
|
||||
//
|
||||
// Deprecated: [Update Project Role](apis/resources/project_service_v2/project-service-update-project-role.api.mdx) to update a project role.
|
||||
//
|
||||
// Change a project role. The key is not editable. If a key should change, remove the role and create a new one.
|
||||
rpc UpdateProjectRole(UpdateProjectRoleRequest) returns (UpdateProjectRoleResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/projects/{project_id}/roles/{role_key}"
|
||||
@@ -3047,8 +3100,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Roles";
|
||||
summary: "Change Project Role";
|
||||
description: "Change a project role. The key is not editable. If a key should change, remove the role and create a new one."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3060,6 +3112,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Remove Project Role
|
||||
//
|
||||
// Deprecated: [Delete Project Role](apis/resources/project_service_v2/project-service-update-project-role.api.mdx) to remove a project role.
|
||||
//
|
||||
// Removes the role from the project and on every resource it has a dependency. This includes project grants and user grants.
|
||||
rpc RemoveProjectRole(RemoveProjectRoleRequest) returns (RemoveProjectRoleResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/projects/{project_id}/roles/{role_key}"
|
||||
@@ -3072,8 +3129,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Roles";
|
||||
summary: "Remove Project Role";
|
||||
description: "Removes the role from the project and on every resource it has a dependency. This includes project grants and user grants."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3737,6 +3793,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Get Project Grant By ID
|
||||
//
|
||||
// Deprecated: [List Project Grants](apis/resources/project_service_v2/project-service-list-project-grants.api.mdx) to get a project grant.
|
||||
//
|
||||
// Returns a project grant. A project grant is when the organization grants its project to another organization.
|
||||
rpc GetProjectGrantByID(GetProjectGrantByIDRequest) returns (GetProjectGrantByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/projects/{project_id}/grants/{grant_id}"
|
||||
@@ -3748,8 +3809,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Projects";
|
||||
summary: "Project Grant By ID";
|
||||
description: "Returns a project grant. A project grant is when the organization grants its project to another organization."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3761,6 +3821,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// List Project Grants
|
||||
//
|
||||
// Deprecated: [List Project Grants](apis/resources/project_service_v2/project-service-list-project-grants.api.mdx) to list project grants.
|
||||
//
|
||||
// Returns a list of project grants for a specific project. A project grant is when the organization grants its project to another organization.
|
||||
rpc ListProjectGrants(ListProjectGrantsRequest) returns (ListProjectGrantsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/grants/_search"
|
||||
@@ -3774,8 +3839,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Search Project Grants from Project";
|
||||
description: "Returns a list of project grants for a specific project. A project grant is when the organization grants its project to another organization."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3787,6 +3851,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Search Project Grants
|
||||
//
|
||||
// Deprecated: [List Project Grants](apis/resources/project_service_v2/project-service-list-project-grants.api.mdx) to list project grants.
|
||||
//
|
||||
// Returns a list of project grants. A project grant is when the organization grants its project to another organization.
|
||||
rpc ListAllProjectGrants(ListAllProjectGrantsRequest) returns (ListAllProjectGrantsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projectgrants/_search"
|
||||
@@ -3799,8 +3868,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Search Project Grants";
|
||||
description: "Returns a list of project grants. A project grant is when the organization grants its project to another organization."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3812,6 +3880,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Add Project Grant
|
||||
//
|
||||
// Deprecated: [Create Project Grant](apis/resources/project_service_v2/project-service-create-project-grant.api.mdx) to add a project grant.
|
||||
//
|
||||
// Grant a project to another organization. The project grant will allow the granted organization to access the project and manage the authorizations for its users. Project Grant will be listed in the granted project of the granted organization.
|
||||
rpc AddProjectGrant(AddProjectGrantRequest) returns (AddProjectGrantResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/grants"
|
||||
@@ -3824,8 +3897,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Add Project Grant";
|
||||
description: "Grant a project to another organization. The project grant will allow the granted organization to access the project and manage the authorizations for its users. Project Grant will be listed in the granted project of the granted organization"
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3837,6 +3909,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Update Project Grant
|
||||
//
|
||||
// Deprecated: [Update Project Grant](apis/resources/project_service_v2/project-service-update-project-grant.api.mdx) to update a project grant.
|
||||
//
|
||||
// Change the roles of the project that is granted to another organization. The project grant will allow the granted organization to access the project and manage the authorizations for its users. Project Grant will be listed in the granted project of the granted organization.
|
||||
rpc UpdateProjectGrant(UpdateProjectGrantRequest) returns (UpdateProjectGrantResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/projects/{project_id}/grants/{grant_id}"
|
||||
@@ -3849,8 +3926,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Change Project Grant";
|
||||
description: "Change the roles of the project that is granted to another organization. The project grant will allow the granted organization to access the project and manage the authorizations for its users. Project Grant will be listed in the granted project of the granted organization"
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3862,6 +3938,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Deactivate Project Grant
|
||||
//
|
||||
// Deprecated: [Deactivate Project Grant](apis/resources/project_service_v2/project-service-deactivate-project-grant.api.mdx) to deactivate a project grant.
|
||||
//
|
||||
// Set the state of the project grant to deactivated. The grant has to be active to be able to deactivate.
|
||||
rpc DeactivateProjectGrant(DeactivateProjectGrantRequest) returns (DeactivateProjectGrantResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/grants/{grant_id}/_deactivate"
|
||||
@@ -3874,8 +3955,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Deactivate Project Grant";
|
||||
description: "Set the state of the project grant to deactivated. The grant has to be active to be able to deactivate."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3887,6 +3967,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Reactivate Project Grant
|
||||
//
|
||||
// Deprecated: [Activate Project Grant](apis/resources/project_service_v2/project-service-activate-project-grant.api.mdx) to activate a project grant.
|
||||
//
|
||||
// Set the state of the project grant to active. The grant has to be deactivated to be able to reactivate.
|
||||
rpc ReactivateProjectGrant(ReactivateProjectGrantRequest) returns (ReactivateProjectGrantResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/projects/{project_id}/grants/{grant_id}/_reactivate"
|
||||
@@ -3899,8 +3984,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Reactivate Project Grant";
|
||||
description: "Set the state of the project grant to active. The grant has to be deactivated to be able to reactivate."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
@@ -3912,6 +3996,11 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Remove Project Grant
|
||||
//
|
||||
// Deprecated: [Delete Project Grant](apis/resources/project_service_v2/project-service-delete-project-grant.api.mdx) to remove a project grant.
|
||||
//
|
||||
// Remove a project grant. All user grants for this project grant will also be removed. A user will not have access to the project afterward (if permissions are checked).
|
||||
rpc RemoveProjectGrant(RemoveProjectGrantRequest) returns (RemoveProjectGrantResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/projects/{project_id}/grants/{grant_id}"
|
||||
@@ -3923,8 +4012,7 @@ service ManagementService {
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Project Grants";
|
||||
summary: "Remove Project Grant";
|
||||
description: "Remove a project grant. All user grants for this project grant will also be removed. A user will not have access to the project afterward (if permissions are checked)."
|
||||
deprecated: true;
|
||||
parameters: {
|
||||
headers: {
|
||||
name: "x-zitadel-orgid";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,347 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.project.v2beta;
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/project/v2beta;project";
|
||||
|
||||
import "google/api/field_behavior.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
import "zitadel/filter/v2beta/filter.proto";
|
||||
|
||||
message ProjectGrant {
|
||||
// The unique identifier of the organization which granted the project to the granted_organization_id.
|
||||
string organization_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629012906488334\"";
|
||||
}
|
||||
];
|
||||
// The timestamp of the granted project creation.
|
||||
google.protobuf.Timestamp creation_date = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2024-12-18T07:50:47.492Z\"";
|
||||
}
|
||||
];
|
||||
// The timestamp of the last change to the granted project (e.g. creation, activation, deactivation).
|
||||
google.protobuf.Timestamp change_date = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2025-01-23T10:34:18.051Z\"";
|
||||
}
|
||||
];
|
||||
// The ID of the organization the project is granted to.
|
||||
string granted_organization_id = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
// The name of the organization the project is granted to.
|
||||
string granted_organization_name = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"Some Organization\""
|
||||
}
|
||||
];
|
||||
// The roles of the granted project.
|
||||
repeated string granted_role_keys = 7 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"role.super.man\"]"
|
||||
}
|
||||
];
|
||||
// The ID of the granted project.
|
||||
string project_id = 8 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
// The name of the granted project.
|
||||
string project_name = 9 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"ZITADEL\""
|
||||
}
|
||||
];
|
||||
// Describes the current state of the granted project.
|
||||
ProjectGrantState state = 10 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the project";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum ProjectGrantState {
|
||||
PROJECT_GRANT_STATE_UNSPECIFIED = 0;
|
||||
PROJECT_GRANT_STATE_ACTIVE = 1;
|
||||
PROJECT_GRANT_STATE_INACTIVE = 2;
|
||||
}
|
||||
|
||||
message Project {
|
||||
// The unique identifier of the project.
|
||||
string id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629012906488334\"";
|
||||
}
|
||||
];
|
||||
// The unique identifier of the organization the project belongs to.
|
||||
string organization_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629012906488334\"";
|
||||
}
|
||||
];
|
||||
// The timestamp of the project creation.
|
||||
google.protobuf.Timestamp creation_date = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2024-12-18T07:50:47.492Z\"";
|
||||
}
|
||||
];
|
||||
// The timestamp of the last change to the project (e.g. creation, activation, deactivation).
|
||||
google.protobuf.Timestamp change_date = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2025-01-23T10:34:18.051Z\"";
|
||||
}
|
||||
];
|
||||
// The name of the project.
|
||||
string name = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"ip_allow_list\"";
|
||||
}
|
||||
];
|
||||
// Describes the current state of the project.
|
||||
ProjectState state = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the project";
|
||||
}
|
||||
];
|
||||
// Describes if the roles of the user should be added to the token.
|
||||
bool project_role_assertion = 7;
|
||||
// When enabled ZITADEL will check if a user has an authorization to use this project assigned when login into an application of this project.
|
||||
bool authorization_required = 8;
|
||||
// When enabled ZITADEL will check if the organization of the user, that is trying to log in, has access to this project (either owns the project or is granted).
|
||||
bool project_access_required = 9;
|
||||
// Defines from where the private labeling should be triggered.
|
||||
PrivateLabelingSetting private_labeling_setting = 10;
|
||||
|
||||
// The ID of the organization the project is granted to.
|
||||
optional string granted_organization_id = 12 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
// The name of the organization the project is granted to.
|
||||
optional string granted_organization_name = 13 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"Some Organization\""
|
||||
}
|
||||
];
|
||||
// Describes the current state of the granted project.
|
||||
GrantedProjectState granted_state = 14 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the granted project";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum ProjectState {
|
||||
PROJECT_STATE_UNSPECIFIED = 0;
|
||||
PROJECT_STATE_ACTIVE = 1;
|
||||
PROJECT_STATE_INACTIVE = 2;
|
||||
}
|
||||
|
||||
enum GrantedProjectState {
|
||||
GRANTED_PROJECT_STATE_UNSPECIFIED = 0;
|
||||
GRANTED_PROJECT_STATE_ACTIVE = 1;
|
||||
GRANTED_PROJECT_STATE_INACTIVE = 2;
|
||||
}
|
||||
|
||||
enum PrivateLabelingSetting {
|
||||
PRIVATE_LABELING_SETTING_UNSPECIFIED = 0;
|
||||
PRIVATE_LABELING_SETTING_ENFORCE_PROJECT_RESOURCE_OWNER_POLICY = 1;
|
||||
PRIVATE_LABELING_SETTING_ALLOW_LOGIN_USER_RESOURCE_OWNER_POLICY = 2;
|
||||
}
|
||||
|
||||
enum ProjectFieldName {
|
||||
PROJECT_FIELD_NAME_UNSPECIFIED = 0;
|
||||
PROJECT_FIELD_NAME_ID = 1;
|
||||
PROJECT_FIELD_NAME_CREATION_DATE = 2;
|
||||
PROJECT_FIELD_NAME_CHANGE_DATE = 3;
|
||||
PROJECT_FIELD_NAME_NAME = 4;
|
||||
}
|
||||
|
||||
enum ProjectGrantFieldName {
|
||||
PROJECT_GRANT_FIELD_NAME_UNSPECIFIED = 0;
|
||||
PROJECT_GRANT_FIELD_NAME_PROJECT_ID = 1;
|
||||
PROJECT_GRANT_FIELD_NAME_CREATION_DATE = 2;
|
||||
PROJECT_GRANT_FIELD_NAME_CHANGE_DATE = 3;
|
||||
}
|
||||
|
||||
enum ProjectRoleFieldName {
|
||||
PROJECT_ROLE_FIELD_NAME_UNSPECIFIED = 0;
|
||||
PROJECT_ROLE_FIELD_NAME_KEY = 1;
|
||||
PROJECT_ROLE_FIELD_NAME_CREATION_DATE = 2;
|
||||
PROJECT_ROLE_FIELD_NAME_CHANGE_DATE = 3;
|
||||
}
|
||||
|
||||
message ProjectSearchFilter {
|
||||
oneof filter {
|
||||
option (validate.required) = true;
|
||||
|
||||
ProjectNameFilter project_name_filter = 1;
|
||||
InProjectIDsFilter in_project_ids_filter = 2;
|
||||
ProjectResourceOwnerFilter project_resource_owner_filter = 3;
|
||||
ProjectGrantResourceOwnerFilter project_grant_resource_owner_filter = 4;
|
||||
ProjectOrganizationIDFilter project_organization_id_filter = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message ProjectNameFilter {
|
||||
// Defines the name of the project to query for.
|
||||
string project_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"ip_allow_list\"";
|
||||
}
|
||||
];
|
||||
// Defines which text comparison method used for the name query.
|
||||
zitadel.filter.v2beta.TextFilterMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message InProjectIDsFilter {
|
||||
// Defines the ids to query for.
|
||||
repeated string project_ids = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the ids of the projects to include"
|
||||
example: "[\"69629023906488334\",\"69622366012355662\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectResourceOwnerFilter {
|
||||
// Defines the ID of organization the project belongs to query for.
|
||||
string project_resource_owner = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectGrantResourceOwnerFilter {
|
||||
// Defines the ID of organization the project grant belongs to query for.
|
||||
string project_grant_resource_owner = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectOrganizationIDFilter {
|
||||
// Defines the ID of organization the project and granted project belong to query for.
|
||||
string project_organization_id = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectGrantSearchFilter {
|
||||
oneof filter {
|
||||
option (validate.required) = true;
|
||||
|
||||
ProjectNameFilter project_name_filter = 1;
|
||||
ProjectRoleKeyFilter role_key_filter = 2;
|
||||
InProjectIDsFilter in_project_ids_filter = 3;
|
||||
ProjectResourceOwnerFilter project_resource_owner_filter = 4;
|
||||
ProjectGrantResourceOwnerFilter project_grant_resource_owner_filter = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message GrantedOrganizationIDFilter {
|
||||
// Defines the ID of organization the project is granted to query for.
|
||||
string granted_organization_id = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectRole {
|
||||
// ID of the project.
|
||||
string project_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629026806489455\"";
|
||||
}
|
||||
];
|
||||
// Key of the project role.
|
||||
string key = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"role.super.man\""
|
||||
}
|
||||
];
|
||||
// The timestamp of the project role creation.
|
||||
google.protobuf.Timestamp creation_date = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2024-12-18T07:50:47.492Z\"";
|
||||
}
|
||||
];
|
||||
// The timestamp of the last change to the project role.
|
||||
google.protobuf.Timestamp change_date = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"2025-01-23T10:34:18.051Z\"";
|
||||
}
|
||||
];
|
||||
// Display name of the project role.
|
||||
string display_name = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"Super man\""
|
||||
}
|
||||
];
|
||||
// Group of the project role.
|
||||
string group = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"people\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectRoleSearchFilter {
|
||||
oneof filter {
|
||||
option (validate.required) = true;
|
||||
|
||||
ProjectRoleKeyFilter role_key_filter = 1;
|
||||
ProjectRoleDisplayNameFilter display_name_filter = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ProjectRoleKeyFilter {
|
||||
string key = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"role.super.man\""
|
||||
}
|
||||
];
|
||||
// Defines which text comparison method used for the name query.
|
||||
zitadel.filter.v2beta.TextFilterMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true
|
||||
];
|
||||
}
|
||||
|
||||
message ProjectRoleDisplayNameFilter {
|
||||
string display_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"SUPER\""
|
||||
}
|
||||
];
|
||||
// Defines which text comparison method used for the name query.
|
||||
zitadel.filter.v2beta.TextFilterMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user