mirror of
https://github.com/zitadel/zitadel.git
synced 2025-11-02 07:58:46 +00:00
fix: create project with the right permission (#10485)
# Which Problems Are Solved
When a user with an `ORG_PROJECT_CREATOR` role tries to create a
project, the request fails with `No matching permissions found
(AUTH-AWfge)` error. This is because `project.write` was set as the
required permission instead of `project.create` during project creation.
# How the Problems Are Solved
By setting the right required permission (`project.create`) while
creating new projects.
# Additional Changes
N/A
# Additional Context
- Closes #10399
(cherry picked from commit 0929c4d235)
This commit is contained in:
committed by
Livio Spring
parent
3156c5bc02
commit
62403d27e4
@@ -10,12 +10,16 @@ import (
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
internal_permission_v2beta "github.com/zitadel/zitadel/pkg/grpc/internal_permission/v2beta"
|
||||
project "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
|
||||
)
|
||||
|
||||
func TestServer_CreateProject(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
@@ -74,6 +78,7 @@ func TestServer_CreateProject(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
got, err := instance.Client.Projectv2Beta.CreateProject(tt.ctx, tt.req)
|
||||
changeDate := time.Now().UTC()
|
||||
@@ -88,6 +93,7 @@ func TestServer_CreateProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_CreateProject_Permission(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -129,6 +135,30 @@ func TestServer_CreateProject_Permission(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with ORG_PROJECT_CREATOR permission, same organization, ok",
|
||||
ctx: integration.WithAuthorizationToken(CTX, getOrgProjectCreatorToken(t, iamOwnerCtx, orgResp.GetOrganizationId(), orgResp.GetOrganizationId())),
|
||||
req: &project.CreateProjectRequest{
|
||||
Name: integration.ProjectName(),
|
||||
OrganizationId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
want: want{
|
||||
id: true,
|
||||
creationDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with ORG_PROJECT_CREATOR permission, other organization, ok",
|
||||
ctx: integration.WithAuthorizationToken(CTX, getOrgProjectCreatorToken(t, iamOwnerCtx, orgResp.GetOrganizationId(), instance.DefaultOrg.GetId())),
|
||||
req: &project.CreateProjectRequest{
|
||||
Name: integration.ProjectName(),
|
||||
OrganizationId: instance.DefaultOrg.GetId(),
|
||||
},
|
||||
want: want{
|
||||
id: true,
|
||||
creationDate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "organization owner, ok",
|
||||
ctx: instance.WithAuthorizationToken(CTX, integration.UserTypeOrgOwner),
|
||||
@@ -156,6 +186,7 @@ func TestServer_CreateProject_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
got, err := instance.Client.Projectv2Beta.CreateProject(tt.ctx, tt.req)
|
||||
changeDate := time.Now().UTC()
|
||||
@@ -169,6 +200,23 @@ func TestServer_CreateProject_Permission(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getOrgProjectCreatorToken(t *testing.T, ctx context.Context, orgId1, orgId2 string) string {
|
||||
// create a machine user in Org 1
|
||||
userResp := instance.CreateUserTypeMachine(ctx, orgId1)
|
||||
|
||||
// assign ORG_PROJECT_CREATOR role in Org 2
|
||||
_, err := instance.Client.InternalPermissionv2Beta.CreateAdministrator(ctx, &internal_permission_v2beta.CreateAdministratorRequest{
|
||||
Resource: &internal_permission_v2beta.ResourceType{
|
||||
Resource: &internal_permission_v2beta.ResourceType_OrganizationId{OrganizationId: orgId2},
|
||||
},
|
||||
UserId: userResp.GetId(),
|
||||
Roles: []string{domain.RoleOrgProjectCreator},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return instance.CreatePersonalAccessToken(ctx, userResp.GetId()).Token
|
||||
}
|
||||
|
||||
func assertCreateProjectResponse(t *testing.T, creationDate, changeDate time.Time, expectedCreationDate, expectedID bool, actualResp *project.CreateProjectResponse) {
|
||||
if expectedCreationDate {
|
||||
if !changeDate.IsZero() {
|
||||
@@ -188,6 +236,7 @@ func assertCreateProjectResponse(t *testing.T, creationDate, changeDate time.Tim
|
||||
}
|
||||
|
||||
func TestServer_UpdateProject(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -210,7 +259,6 @@ func TestServer_UpdateProject(t *testing.T) {
|
||||
name: "not existing",
|
||||
prepare: func(request *project.UpdateProjectRequest) {
|
||||
request.Id = "notexisting"
|
||||
return
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
@@ -278,6 +326,7 @@ func TestServer_UpdateProject(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
@@ -297,6 +346,7 @@ func TestServer_UpdateProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_UpdateProject_Permission(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -430,6 +480,7 @@ func TestServer_UpdateProject_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
@@ -461,6 +512,7 @@ func assertUpdateProjectResponse(t *testing.T, creationDate, changeDate time.Tim
|
||||
}
|
||||
|
||||
func TestServer_DeleteProject(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -516,6 +568,7 @@ func TestServer_DeleteProject(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var creationDate, deletionDate time.Time
|
||||
if tt.prepare != nil {
|
||||
creationDate, deletionDate = tt.prepare(tt.req)
|
||||
@@ -532,6 +585,7 @@ func TestServer_DeleteProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_DeleteProject_Permission(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -635,6 +689,7 @@ func TestServer_DeleteProject_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var creationDate, deletionDate time.Time
|
||||
if tt.prepare != nil {
|
||||
creationDate, deletionDate = tt.prepare(tt.req)
|
||||
@@ -663,6 +718,7 @@ func assertDeleteProjectResponse(t *testing.T, creationDate, deletionDate time.T
|
||||
}
|
||||
|
||||
func TestServer_DeactivateProject(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -685,7 +741,6 @@ func TestServer_DeactivateProject(t *testing.T) {
|
||||
name: "not existing",
|
||||
prepare: func(request *project.DeactivateProjectRequest) {
|
||||
request.Id = "notexisting"
|
||||
return
|
||||
},
|
||||
args: args{
|
||||
ctx: iamOwnerCtx,
|
||||
@@ -725,6 +780,7 @@ func TestServer_DeactivateProject(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
@@ -744,6 +800,7 @@ func TestServer_DeactivateProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_DeactivateProject_Permission(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -831,6 +888,7 @@ func TestServer_DeactivateProject_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
@@ -862,6 +920,7 @@ func assertDeactivateProjectResponse(t *testing.T, creationDate, changeDate time
|
||||
}
|
||||
|
||||
func TestServer_ActivateProject(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -936,6 +995,7 @@ func TestServer_ActivateProject(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
@@ -955,6 +1015,7 @@ func TestServer_ActivateProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_ActivateProject_Permission(t *testing.T) {
|
||||
t.Parallel()
|
||||
iamOwnerCtx := instance.WithAuthorizationToken(CTX, integration.UserTypeIAMOwner)
|
||||
orgResp := instance.CreateOrganization(iamOwnerCtx, integration.OrganizationName(), gofakeit.Email())
|
||||
|
||||
@@ -1047,6 +1108,7 @@ func TestServer_ActivateProject_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
creationDate := time.Now().UTC()
|
||||
tt.prepare(tt.args.req)
|
||||
|
||||
|
||||
@@ -64,6 +64,10 @@ func (c *Commands) checkPermissionUpdateUserCredentials(ctx context.Context, res
|
||||
return c.checkPermissionOnUser(ctx, domain.PermissionUserCredentialWrite)(resourceOwner, userID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionCreateProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectCreate, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectDelete, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (c *Commands) AddProject(ctx context.Context, add *AddProject) (_ *domain.O
|
||||
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 {
|
||||
if err := c.checkPermissionCreateProject(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const (
|
||||
PermissionOrgRead = "org.read"
|
||||
PermissionIDPRead = "iam.idp.read"
|
||||
PermissionOrgIDPRead = "org.idp.read"
|
||||
PermissionProjectCreate = "project.create"
|
||||
PermissionProjectWrite = "project.write"
|
||||
PermissionProjectRead = "project.read"
|
||||
PermissionProjectDelete = "project.delete"
|
||||
|
||||
@@ -295,8 +295,11 @@ func (i *Instance) CreateUserTypeHuman(ctx context.Context, email string) *user_
|
||||
}
|
||||
|
||||
func (i *Instance) CreateUserTypeMachine(ctx context.Context, orgId string) *user_v2.CreateUserResponse {
|
||||
if orgId == "" {
|
||||
orgId = i.DefaultOrg.GetId()
|
||||
}
|
||||
resp, err := i.Client.UserV2.CreateUser(ctx, &user_v2.CreateUserRequest{
|
||||
OrganizationId: i.DefaultOrg.GetId(),
|
||||
OrganizationId: orgId,
|
||||
UserType: &user_v2.CreateUserRequest_Machine_{
|
||||
Machine: &user_v2.CreateUserRequest_Machine{
|
||||
Name: "machine",
|
||||
|
||||
Reference in New Issue
Block a user