diff --git a/src/common/rbac/project_evaluator.go b/src/common/rbac/project/evaluator.go similarity index 81% rename from src/common/rbac/project_evaluator.go rename to src/common/rbac/project/evaluator.go index 9ceafda78..d00c8b649 100644 --- a/src/common/rbac/project_evaluator.go +++ b/src/common/rbac/project/evaluator.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rbac +package project import ( "context" @@ -26,15 +26,15 @@ import ( "github.com/goharbor/harbor/src/pkg/permission/types" ) -// ProjectRBACUserBuilder builder to make types.RBACUser for the project -type ProjectRBACUserBuilder func(context.Context, *models.Project) types.RBACUser +// RBACUserBuilder builder to make types.RBACUser for the project +type RBACUserBuilder func(context.Context, *models.Project) types.RBACUser // NewBuilderForUser create a builder for the local user -func NewBuilderForUser(user *models.User, ctl project.Controller) ProjectRBACUserBuilder { +func NewBuilderForUser(user *models.User, ctl project.Controller) RBACUserBuilder { return func(ctx context.Context, p *models.Project) types.RBACUser { if user == nil { // anonymous access - return &projectRBACUser{ + return &rbacUser{ project: p, username: "anonymous", } @@ -46,7 +46,7 @@ func NewBuilderForUser(user *models.User, ctl project.Controller) ProjectRBACUse return nil } - return &projectRBACUser{ + return &rbacUser{ project: p, username: user.Username, projectRoles: roles, @@ -56,14 +56,14 @@ func NewBuilderForUser(user *models.User, ctl project.Controller) ProjectRBACUse // NewBuilderForPolicies create a builder for the policies func NewBuilderForPolicies(username string, policies []*types.Policy, - filters ...func(*models.Project, []*types.Policy) []*types.Policy) ProjectRBACUserBuilder { + filters ...func(*models.Project, []*types.Policy) []*types.Policy) RBACUserBuilder { return func(ctx context.Context, p *models.Project) types.RBACUser { for _, filter := range filters { policies = filter(p, policies) } - return &projectRBACUser{ + return &rbacUser{ project: p, username: username, policies: policies, @@ -71,9 +71,9 @@ func NewBuilderForPolicies(username string, policies []*types.Policy, } } -// NewProjectEvaluator create evaluator for the project by builders -func NewProjectEvaluator(ctl project.Controller, builders ...ProjectRBACUserBuilder) evaluator.Evaluator { - return namespace.New(ProjectNamespaceKind, func(ctx context.Context, ns types.Namespace) evaluator.Evaluator { +// NewEvaluator create evaluator for the project by builders +func NewEvaluator(ctl project.Controller, builders ...RBACUserBuilder) evaluator.Evaluator { + return namespace.New(NamespaceKind, func(ctx context.Context, ns types.Namespace) evaluator.Evaluator { p, err := ctl.Get(ctx, ns.Identity().(int64), project.Metadata(true)) if err != nil { if err != nil { diff --git a/src/common/rbac/project_evaluator_test.go b/src/common/rbac/project/evaluator_test.go similarity index 71% rename from src/common/rbac/project_evaluator_test.go rename to src/common/rbac/project/evaluator_test.go index 85ae0186b..d4ab2e7d8 100644 --- a/src/common/rbac/project_evaluator_test.go +++ b/src/common/rbac/project/evaluator_test.go @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rbac +package project import ( "context" + "github.com/goharbor/harbor/src/common/rbac" "testing" "github.com/goharbor/harbor/src/common" @@ -53,10 +54,10 @@ func TestAnonymousAccess(t *testing.T) { ctl := &projecttesting.Controller{} mock.OnAnything(ctl, "Get").Return(public, nil) - resource := NewProjectNamespace(public.ProjectID).Resource(ResourceRepository) + resource := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(nil, ctl)) - assert.True(evaluator.HasPermission(context.TODO(), resource, ActionPull)) + evaluator := NewEvaluator(ctl, NewBuilderForUser(nil, ctl)) + assert.True(evaluator.HasPermission(context.TODO(), resource, rbac.ActionPull)) } { @@ -64,10 +65,10 @@ func TestAnonymousAccess(t *testing.T) { ctl := &projecttesting.Controller{} mock.OnAnything(ctl, "Get").Return(private, nil) - resource := NewProjectNamespace(private.ProjectID).Resource(ResourceRepository) + resource := NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(nil, ctl)) - assert.False(evaluator.HasPermission(context.TODO(), resource, ActionPull)) + evaluator := NewEvaluator(ctl, NewBuilderForUser(nil, ctl)) + assert.False(evaluator.HasPermission(context.TODO(), resource, rbac.ActionPull)) } } @@ -83,9 +84,9 @@ func TestProjectRoleAccess(t *testing.T) { UserID: 1, Username: "username", } - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(user, ctl)) - resorce := NewProjectNamespace(public.ProjectID).Resource(ResourceRepository) - assert.True(evaluator.HasPermission(context.TODO(), resorce, ActionPush)) + evaluator := NewEvaluator(ctl, NewBuilderForUser(user, ctl)) + resorce := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) + assert.True(evaluator.HasPermission(context.TODO(), resorce, rbac.ActionPush)) } { @@ -97,9 +98,9 @@ func TestProjectRoleAccess(t *testing.T) { UserID: 1, Username: "username", } - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(user, ctl)) - resorce := NewProjectNamespace(public.ProjectID).Resource(ResourceRepository) - assert.False(evaluator.HasPermission(context.TODO(), resorce, ActionPush)) + evaluator := NewEvaluator(ctl, NewBuilderForUser(user, ctl)) + resorce := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) + assert.False(evaluator.HasPermission(context.TODO(), resorce, rbac.ActionPush)) } } @@ -112,12 +113,12 @@ func BenchmarkProjectEvaluator(b *testing.B) { UserID: 1, Username: "username", } - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(user, ctl)) - resource := NewProjectNamespace(public.ProjectID).Resource(ResourceRepository) + evaluator := NewEvaluator(ctl, NewBuilderForUser(user, ctl)) + resource := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) b.ResetTimer() for i := 0; i < b.N; i++ { - evaluator.HasPermission(context.TODO(), resource, ActionPull) + evaluator.HasPermission(context.TODO(), resource, rbac.ActionPull) } } @@ -130,12 +131,12 @@ func BenchmarkProjectEvaluatorParallel(b *testing.B) { UserID: 1, Username: "username", } - evaluator := NewProjectEvaluator(ctl, NewBuilderForUser(user, ctl)) - resource := NewProjectNamespace(public.ProjectID).Resource(ResourceRepository) + evaluator := NewEvaluator(ctl, NewBuilderForUser(user, ctl)) + resource := NewNamespace(public.ProjectID).Resource(rbac.ResourceRepository) b.RunParallel(func(pb *testing.PB) { for pb.Next() { - evaluator.HasPermission(context.TODO(), resource, ActionPull) + evaluator.HasPermission(context.TODO(), resource, rbac.ActionPull) } }) } diff --git a/src/common/rbac/project_namespace.go b/src/common/rbac/project/namespace.go similarity index 76% rename from src/common/rbac/project_namespace.go rename to src/common/rbac/project/namespace.go index db4019e6f..4c6965211 100644 --- a/src/common/rbac/project_namespace.go +++ b/src/common/rbac/project/namespace.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rbac +package project import ( "fmt" @@ -23,8 +23,8 @@ import ( ) const ( - // ProjectNamespaceKind kind for project namespace - ProjectNamespaceKind = "project" + // NamespaceKind kind for project projectNamespace + NamespaceKind = "project" ) var ( @@ -36,7 +36,7 @@ type projectNamespace struct { } func (ns *projectNamespace) Kind() string { - return ProjectNamespaceKind + return NamespaceKind } func (ns *projectNamespace) Resource(subresources ...types.Resource) types.Resource { @@ -51,13 +51,13 @@ func (ns *projectNamespace) GetPolicies() []*types.Policy { return GetPoliciesOfProject(ns.projectID) } -// NewProjectNamespace returns namespace for project -func NewProjectNamespace(projectID int64) types.Namespace { +// NewNamespace returns projectNamespace for project +func NewNamespace(projectID int64) types.Namespace { return &projectNamespace{projectID: projectID} } -// ProjectNamespaceParse ... -func ProjectNamespaceParse(resource types.Resource) (types.Namespace, bool) { +// NamespaceParse ... +func NamespaceParse(resource types.Resource) (types.Namespace, bool) { matches := projectNamespaceRe.FindStringSubmatch(resource.String()) if len(matches) <= 1 { @@ -69,9 +69,9 @@ func ProjectNamespaceParse(resource types.Resource) (types.Namespace, bool) { return nil, false } - return NewProjectNamespace(projectID), true + return NewNamespace(projectID), true } func init() { - types.RegistryNamespaceParse(ProjectNamespaceKind, ProjectNamespaceParse) + types.RegistryNamespaceParse(NamespaceKind, NamespaceParse) } diff --git a/src/common/rbac/project/rbac_role.go b/src/common/rbac/project/rbac_role.go new file mode 100644 index 000000000..dd4bfa27d --- /dev/null +++ b/src/common/rbac/project/rbac_role.go @@ -0,0 +1,368 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package project + +import ( + "github.com/goharbor/harbor/src/common" + "github.com/goharbor/harbor/src/common/rbac" + "github.com/goharbor/harbor/src/pkg/permission/types" +) + +var ( + rolePoliciesMap = map[string][]*types.Policy{ + "projectAdmin": { + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, + {Resource: rbac.ResourceSelf, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceSelf, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceMember, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceMember, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMember, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceMember, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceMember, Action: rbac.ActionList}, + + {Resource: rbac.ResourceMetadata, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceLog, Action: rbac.ActionList}, + + {Resource: rbac.ResourceLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionRead}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionList}, + + {Resource: rbac.ResourceQuota, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRepository, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPush}, + + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionRead}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionList}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionOperate}, + + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate}, // upload helm chart + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, // download helm chart + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionCreate}, // upload helm chart version + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, // read and download helm chart version + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead}, + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionUpdate}, + + {Resource: rbac.ResourceRobot, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionList}, + + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionList}, + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScan, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, + {Resource: rbac.ResourceScanner, Action: rbac.ActionCreate}, + + {Resource: rbac.ResourceArtifact, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, + {Resource: rbac.ResourceTag, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceTag, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourcePreatPolicy, Action: rbac.ActionCreate}, + {Resource: rbac.ResourcePreatPolicy, Action: rbac.ActionRead}, + {Resource: rbac.ResourcePreatPolicy, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourcePreatPolicy, Action: rbac.ActionDelete}, + {Resource: rbac.ResourcePreatPolicy, Action: rbac.ActionList}, + }, + + "maintainer": { + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceMember, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMember, Action: rbac.ActionList}, + + {Resource: rbac.ResourceMetadata, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceMetadata, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceLog, Action: rbac.ActionList}, + + {Resource: rbac.ResourceQuota, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionRead}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionList}, + + {Resource: rbac.ResourceRepository, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPush}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, + + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionRead}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionList}, + {Resource: rbac.ResourceTagRetention, Action: rbac.ActionOperate}, + + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceImmutableTag, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRobot, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionList}, + + {Resource: rbac.ResourceNotificationPolicy, Action: rbac.ActionList}, + + {Resource: rbac.ResourceScan, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceArtifact, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionDelete}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, + {Resource: rbac.ResourceTag, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceTag, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionDelete}, + }, + + "developer": { + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceMember, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMember, Action: rbac.ActionList}, + + {Resource: rbac.ResourceLog, Action: rbac.ActionList}, + + {Resource: rbac.ResourceLabel, Action: rbac.ActionRead}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionList}, + + {Resource: rbac.ResourceQuota, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRepository, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionUpdate}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPush}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, + + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete}, + + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRobot, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionList}, + + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceArtifact, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, + {Resource: rbac.ResourceTag, Action: rbac.ActionCreate}, + + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionCreate}, + {Resource: rbac.ResourceArtifactLabel, Action: rbac.ActionDelete}, + }, + + "guest": { + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceMember, Action: rbac.ActionRead}, + {Resource: rbac.ResourceMember, Action: rbac.ActionList}, + + {Resource: rbac.ResourceLog, Action: rbac.ActionList}, + + {Resource: rbac.ResourceLabel, Action: rbac.ActionRead}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionList}, + + {Resource: rbac.ResourceQuota, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRepository, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, + + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, + + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRobot, Action: rbac.ActionRead}, + {Resource: rbac.ResourceRobot, Action: rbac.ActionList}, + + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, + + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, + }, + + "limitedGuest": { + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceQuota, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, + + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, + + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, + + {Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, + + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, + + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, + }, + } +) + +// projectRBACRole implement the RBACRole interface +type projectRBACRole struct { + projectID int64 + roleID int +} + +// GetRoleName returns role name for the visitor role +func (role *projectRBACRole) GetRoleName() string { + switch role.roleID { + case common.RoleProjectAdmin: + return "projectAdmin" + case common.RoleMaintainer: + return "maintainer" + case common.RoleDeveloper: + return "developer" + case common.RoleGuest: + return "guest" + case common.RoleLimitedGuest: + return "limitedGuest" + default: + return "" + } +} + +// GetPolicies returns policies for the visitor role +func (role *projectRBACRole) GetPolicies() []*types.Policy { + policies := []*types.Policy{} + + roleName := role.GetRoleName() + if roleName == "" { + return policies + } + + namespace := NewNamespace(role.projectID) + for _, policy := range rolePoliciesMap[roleName] { + policies = append(policies, &types.Policy{ + Resource: namespace.Resource(policy.Resource), + Action: policy.Action, + Effect: policy.Effect, + }) + } + + return policies +} diff --git a/src/common/rbac/project_rbac_user.go b/src/common/rbac/project/rbac_user.go similarity index 86% rename from src/common/rbac/project_rbac_user.go rename to src/common/rbac/project/rbac_user.go index a93814bbd..76a1310e5 100644 --- a/src/common/rbac/project_rbac_user.go +++ b/src/common/rbac/project/rbac_user.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rbac +package project import ( "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/pkg/permission/types" ) -type projectRBACUser struct { +type rbacUser struct { project *models.Project username string projectRoles []int @@ -27,12 +27,12 @@ type projectRBACUser struct { } // GetUserName returns username of the visitor -func (pru *projectRBACUser) GetUserName() string { +func (pru *rbacUser) GetUserName() string { return pru.username } // GetPolicies returns policies of the visitor -func (pru *projectRBACUser) GetPolicies() []*types.Policy { +func (pru *rbacUser) GetPolicies() []*types.Policy { policies := pru.policies if pru.project.IsPublic() { @@ -43,7 +43,7 @@ func (pru *projectRBACUser) GetPolicies() []*types.Policy { } // GetRoles returns roles of the visitor -func (pru *projectRBACUser) GetRoles() []types.RBACRole { +func (pru *rbacUser) GetRoles() []types.RBACRole { roles := []types.RBACRole{} for _, roleID := range pru.projectRoles { roles = append(roles, &projectRBACRole{projectID: pru.project.ProjectID, roleID: roleID}) diff --git a/src/common/rbac/project_rbac_util.go b/src/common/rbac/project/rbac_util.go similarity index 61% rename from src/common/rbac/project_rbac_util.go rename to src/common/rbac/project/rbac_util.go index ea7e2198d..f652eefc1 100644 --- a/src/common/rbac/project_rbac_util.go +++ b/src/common/rbac/project/rbac_util.go @@ -12,37 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rbac +package project import ( + "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/pkg/permission/types" ) var ( // subresource policies for public project publicProjectPolicies = []*types.Policy{ - {Resource: ResourceSelf, Action: ActionRead}, + {Resource: rbac.ResourceSelf, Action: rbac.ActionRead}, - {Resource: ResourceLabel, Action: ActionRead}, - {Resource: ResourceLabel, Action: ActionList}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionRead}, + {Resource: rbac.ResourceLabel, Action: rbac.ActionList}, - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPull}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionList}, + {Resource: rbac.ResourceRepository, Action: rbac.ActionPull}, - {Resource: ResourceHelmChart, Action: ActionRead}, - {Resource: ResourceHelmChart, Action: ActionList}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChart, Action: rbac.ActionList}, - {Resource: ResourceHelmChartVersion, Action: ActionRead}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead}, + {Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList}, - {Resource: ResourceScan, Action: ActionRead}, - {Resource: ResourceScanner, Action: ActionRead}, + {Resource: rbac.ResourceScan, Action: rbac.ActionRead}, + {Resource: rbac.ResourceScanner, Action: rbac.ActionRead}, - {Resource: ResourceTag, Action: ActionList}, + {Resource: rbac.ResourceTag, Action: rbac.ActionList}, - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionRead}, + {Resource: rbac.ResourceArtifact, Action: rbac.ActionList}, + {Resource: rbac.ResourceArtifactAddition, Action: rbac.ActionRead}, } // sub policies for the projects @@ -52,7 +53,7 @@ var ( func getPoliciesForPublicProject(projectID int64) []*types.Policy { policies := []*types.Policy{} - namespace := NewProjectNamespace(projectID) + namespace := NewNamespace(projectID) for _, policy := range publicProjectPolicies { policies = append(policies, &types.Policy{ Resource: namespace.Resource(policy.Resource), @@ -64,11 +65,11 @@ func getPoliciesForPublicProject(projectID int64) []*types.Policy { return policies } -// GetPoliciesOfProject returns all policies for namespace of the project +// GetPoliciesOfProject returns all policies for projectNamespace of the project func GetPoliciesOfProject(projectID int64) []*types.Policy { policies := []*types.Policy{} - namespace := NewProjectNamespace(projectID) + namespace := NewNamespace(projectID) for _, policy := range subPoliciesForProject { policies = append(policies, &types.Policy{ Resource: namespace.Resource(policy.Resource), diff --git a/src/common/rbac/project_rbac_role.go b/src/common/rbac/project_rbac_role.go deleted file mode 100644 index bb79955bb..000000000 --- a/src/common/rbac/project_rbac_role.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright Project Harbor Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rbac - -import ( - "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/pkg/permission/types" -) - -var ( - rolePoliciesMap = map[string][]*types.Policy{ - "projectAdmin": { - {Resource: ResourceSelf, Action: ActionRead}, - {Resource: ResourceSelf, Action: ActionUpdate}, - {Resource: ResourceSelf, Action: ActionDelete}, - - {Resource: ResourceMember, Action: ActionCreate}, - {Resource: ResourceMember, Action: ActionRead}, - {Resource: ResourceMember, Action: ActionUpdate}, - {Resource: ResourceMember, Action: ActionDelete}, - {Resource: ResourceMember, Action: ActionList}, - - {Resource: ResourceMetadata, Action: ActionCreate}, - {Resource: ResourceMetadata, Action: ActionRead}, - {Resource: ResourceMetadata, Action: ActionUpdate}, - {Resource: ResourceMetadata, Action: ActionDelete}, - - {Resource: ResourceLog, Action: ActionList}, - - {Resource: ResourceLabel, Action: ActionCreate}, - {Resource: ResourceLabel, Action: ActionRead}, - {Resource: ResourceLabel, Action: ActionUpdate}, - {Resource: ResourceLabel, Action: ActionDelete}, - {Resource: ResourceLabel, Action: ActionList}, - - {Resource: ResourceQuota, Action: ActionRead}, - - {Resource: ResourceRepository, Action: ActionCreate}, - {Resource: ResourceRepository, Action: ActionRead}, - {Resource: ResourceRepository, Action: ActionUpdate}, - {Resource: ResourceRepository, Action: ActionDelete}, - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPull}, - {Resource: ResourceRepository, Action: ActionPush}, - - {Resource: ResourceTagRetention, Action: ActionCreate}, - {Resource: ResourceTagRetention, Action: ActionRead}, - {Resource: ResourceTagRetention, Action: ActionUpdate}, - {Resource: ResourceTagRetention, Action: ActionDelete}, - {Resource: ResourceTagRetention, Action: ActionList}, - {Resource: ResourceTagRetention, Action: ActionOperate}, - - {Resource: ResourceImmutableTag, Action: ActionCreate}, - {Resource: ResourceImmutableTag, Action: ActionUpdate}, - {Resource: ResourceImmutableTag, Action: ActionDelete}, - {Resource: ResourceImmutableTag, Action: ActionList}, - - {Resource: ResourceHelmChart, Action: ActionCreate}, // upload helm chart - {Resource: ResourceHelmChart, Action: ActionRead}, // download helm chart - {Resource: ResourceHelmChart, Action: ActionDelete}, - {Resource: ResourceHelmChart, Action: ActionList}, - - {Resource: ResourceHelmChartVersion, Action: ActionCreate}, // upload helm chart version - {Resource: ResourceHelmChartVersion, Action: ActionRead}, // read and download helm chart version - {Resource: ResourceHelmChartVersion, Action: ActionDelete}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, - - {Resource: ResourceHelmChartVersionLabel, Action: ActionCreate}, - {Resource: ResourceHelmChartVersionLabel, Action: ActionDelete}, - - {Resource: ResourceConfiguration, Action: ActionRead}, - {Resource: ResourceConfiguration, Action: ActionUpdate}, - - {Resource: ResourceRobot, Action: ActionCreate}, - {Resource: ResourceRobot, Action: ActionRead}, - {Resource: ResourceRobot, Action: ActionUpdate}, - {Resource: ResourceRobot, Action: ActionDelete}, - {Resource: ResourceRobot, Action: ActionList}, - - {Resource: ResourceNotificationPolicy, Action: ActionCreate}, - {Resource: ResourceNotificationPolicy, Action: ActionUpdate}, - {Resource: ResourceNotificationPolicy, Action: ActionDelete}, - {Resource: ResourceNotificationPolicy, Action: ActionList}, - {Resource: ResourceNotificationPolicy, Action: ActionRead}, - - {Resource: ResourceScan, Action: ActionCreate}, - {Resource: ResourceScan, Action: ActionRead}, - - {Resource: ResourceScanner, Action: ActionRead}, - {Resource: ResourceScanner, Action: ActionCreate}, - - {Resource: ResourceArtifact, Action: ActionCreate}, - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionDelete}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, - - {Resource: ResourceTag, Action: ActionList}, - {Resource: ResourceTag, Action: ActionCreate}, - {Resource: ResourceTag, Action: ActionDelete}, - - {Resource: ResourceArtifactLabel, Action: ActionCreate}, - {Resource: ResourceArtifactLabel, Action: ActionDelete}, - - {Resource: ResourcePreatPolicy, Action: ActionCreate}, - {Resource: ResourcePreatPolicy, Action: ActionRead}, - {Resource: ResourcePreatPolicy, Action: ActionUpdate}, - {Resource: ResourcePreatPolicy, Action: ActionDelete}, - {Resource: ResourcePreatPolicy, Action: ActionList}, - }, - - "maintainer": { - {Resource: ResourceSelf, Action: ActionRead}, - - {Resource: ResourceMember, Action: ActionRead}, - {Resource: ResourceMember, Action: ActionList}, - - {Resource: ResourceMetadata, Action: ActionCreate}, - {Resource: ResourceMetadata, Action: ActionRead}, - {Resource: ResourceMetadata, Action: ActionUpdate}, - {Resource: ResourceMetadata, Action: ActionDelete}, - - {Resource: ResourceLog, Action: ActionList}, - - {Resource: ResourceQuota, Action: ActionRead}, - - {Resource: ResourceLabel, Action: ActionCreate}, - {Resource: ResourceLabel, Action: ActionRead}, - {Resource: ResourceLabel, Action: ActionUpdate}, - {Resource: ResourceLabel, Action: ActionDelete}, - {Resource: ResourceLabel, Action: ActionList}, - - {Resource: ResourceRepository, Action: ActionCreate}, - {Resource: ResourceRepository, Action: ActionRead}, - {Resource: ResourceRepository, Action: ActionUpdate}, - {Resource: ResourceRepository, Action: ActionDelete}, - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPush}, - {Resource: ResourceRepository, Action: ActionPull}, - - {Resource: ResourceTagRetention, Action: ActionCreate}, - {Resource: ResourceTagRetention, Action: ActionRead}, - {Resource: ResourceTagRetention, Action: ActionUpdate}, - {Resource: ResourceTagRetention, Action: ActionDelete}, - {Resource: ResourceTagRetention, Action: ActionList}, - {Resource: ResourceTagRetention, Action: ActionOperate}, - - {Resource: ResourceImmutableTag, Action: ActionCreate}, - {Resource: ResourceImmutableTag, Action: ActionUpdate}, - {Resource: ResourceImmutableTag, Action: ActionDelete}, - {Resource: ResourceImmutableTag, Action: ActionList}, - - {Resource: ResourceHelmChart, Action: ActionCreate}, - {Resource: ResourceHelmChart, Action: ActionRead}, - {Resource: ResourceHelmChart, Action: ActionDelete}, - {Resource: ResourceHelmChart, Action: ActionList}, - - {Resource: ResourceHelmChartVersion, Action: ActionCreate}, - {Resource: ResourceHelmChartVersion, Action: ActionRead}, - {Resource: ResourceHelmChartVersion, Action: ActionDelete}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, - - {Resource: ResourceHelmChartVersionLabel, Action: ActionCreate}, - {Resource: ResourceHelmChartVersionLabel, Action: ActionDelete}, - - {Resource: ResourceConfiguration, Action: ActionRead}, - - {Resource: ResourceRobot, Action: ActionRead}, - {Resource: ResourceRobot, Action: ActionList}, - - {Resource: ResourceNotificationPolicy, Action: ActionList}, - - {Resource: ResourceScan, Action: ActionCreate}, - {Resource: ResourceScan, Action: ActionRead}, - - {Resource: ResourceScanner, Action: ActionRead}, - - {Resource: ResourceArtifact, Action: ActionCreate}, - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionDelete}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, - - {Resource: ResourceTag, Action: ActionList}, - {Resource: ResourceTag, Action: ActionCreate}, - {Resource: ResourceTag, Action: ActionDelete}, - - {Resource: ResourceArtifactLabel, Action: ActionCreate}, - {Resource: ResourceArtifactLabel, Action: ActionDelete}, - }, - - "developer": { - {Resource: ResourceSelf, Action: ActionRead}, - - {Resource: ResourceMember, Action: ActionRead}, - {Resource: ResourceMember, Action: ActionList}, - - {Resource: ResourceLog, Action: ActionList}, - - {Resource: ResourceLabel, Action: ActionRead}, - {Resource: ResourceLabel, Action: ActionList}, - - {Resource: ResourceQuota, Action: ActionRead}, - - {Resource: ResourceRepository, Action: ActionCreate}, - {Resource: ResourceRepository, Action: ActionRead}, - {Resource: ResourceRepository, Action: ActionUpdate}, - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPush}, - {Resource: ResourceRepository, Action: ActionPull}, - - {Resource: ResourceHelmChart, Action: ActionCreate}, - {Resource: ResourceHelmChart, Action: ActionRead}, - {Resource: ResourceHelmChart, Action: ActionList}, - - {Resource: ResourceHelmChartVersion, Action: ActionCreate}, - {Resource: ResourceHelmChartVersion, Action: ActionRead}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, - - {Resource: ResourceHelmChartVersionLabel, Action: ActionCreate}, - {Resource: ResourceHelmChartVersionLabel, Action: ActionDelete}, - - {Resource: ResourceConfiguration, Action: ActionRead}, - - {Resource: ResourceRobot, Action: ActionRead}, - {Resource: ResourceRobot, Action: ActionList}, - - {Resource: ResourceScan, Action: ActionRead}, - - {Resource: ResourceScanner, Action: ActionRead}, - - {Resource: ResourceArtifact, Action: ActionCreate}, - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, - - {Resource: ResourceTag, Action: ActionList}, - {Resource: ResourceTag, Action: ActionCreate}, - - {Resource: ResourceArtifactLabel, Action: ActionCreate}, - {Resource: ResourceArtifactLabel, Action: ActionDelete}, - }, - - "guest": { - {Resource: ResourceSelf, Action: ActionRead}, - - {Resource: ResourceMember, Action: ActionRead}, - {Resource: ResourceMember, Action: ActionList}, - - {Resource: ResourceLog, Action: ActionList}, - - {Resource: ResourceLabel, Action: ActionRead}, - {Resource: ResourceLabel, Action: ActionList}, - - {Resource: ResourceQuota, Action: ActionRead}, - - {Resource: ResourceRepository, Action: ActionRead}, - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPull}, - - {Resource: ResourceHelmChart, Action: ActionRead}, - {Resource: ResourceHelmChart, Action: ActionList}, - - {Resource: ResourceHelmChartVersion, Action: ActionRead}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, - - {Resource: ResourceConfiguration, Action: ActionRead}, - - {Resource: ResourceRobot, Action: ActionRead}, - {Resource: ResourceRobot, Action: ActionList}, - - {Resource: ResourceScan, Action: ActionRead}, - - {Resource: ResourceScanner, Action: ActionRead}, - - {Resource: ResourceTag, Action: ActionList}, - - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, - }, - - "limitedGuest": { - {Resource: ResourceSelf, Action: ActionRead}, - - {Resource: ResourceQuota, Action: ActionRead}, - - {Resource: ResourceRepository, Action: ActionList}, - {Resource: ResourceRepository, Action: ActionPull}, - - {Resource: ResourceHelmChart, Action: ActionRead}, - {Resource: ResourceHelmChart, Action: ActionList}, - - {Resource: ResourceHelmChartVersion, Action: ActionRead}, - {Resource: ResourceHelmChartVersion, Action: ActionList}, - - {Resource: ResourceConfiguration, Action: ActionRead}, - - {Resource: ResourceScan, Action: ActionRead}, - - {Resource: ResourceScanner, Action: ActionRead}, - - {Resource: ResourceTag, Action: ActionList}, - - {Resource: ResourceArtifact, Action: ActionRead}, - {Resource: ResourceArtifact, Action: ActionList}, - {Resource: ResourceArtifactAddition, Action: ActionRead}, - }, - } -) - -// projectRBACRole implement the RBACRole interface -type projectRBACRole struct { - projectID int64 - roleID int -} - -// GetRoleName returns role name for the visitor role -func (role *projectRBACRole) GetRoleName() string { - switch role.roleID { - case common.RoleProjectAdmin: - return "projectAdmin" - case common.RoleMaintainer: - return "maintainer" - case common.RoleDeveloper: - return "developer" - case common.RoleGuest: - return "guest" - case common.RoleLimitedGuest: - return "limitedGuest" - default: - return "" - } -} - -// GetPolicies returns policies for the visitor role -func (role *projectRBACRole) GetPolicies() []*types.Policy { - policies := []*types.Policy{} - - roleName := role.GetRoleName() - if roleName == "" { - return policies - } - - namespace := NewProjectNamespace(role.projectID) - for _, policy := range rolePoliciesMap[roleName] { - policies = append(policies, &types.Policy{ - Resource: namespace.Resource(policy.Resource), - Action: policy.Action, - Effect: policy.Effect, - }) - } - - return policies -} diff --git a/src/common/security/local/context.go b/src/common/security/local/context.go index 7e6077680..17f0778ba 100644 --- a/src/common/security/local/context.go +++ b/src/common/security/local/context.go @@ -16,10 +16,10 @@ package local import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "sync" "github.com/goharbor/harbor/src/common/models" - "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/pkg/permission/evaluator" "github.com/goharbor/harbor/src/pkg/permission/evaluator/admin" @@ -88,7 +88,7 @@ func (s *SecurityContext) Can(ctx context.Context, action types.Action, resource evaluators = evaluators.Add(admin.New(s.GetUsername())) } - evaluators = evaluators.Add(rbac.NewProjectEvaluator(s.ctl, rbac.NewBuilderForUser(s.user, s.ctl))) + evaluators = evaluators.Add(rbac_project.NewEvaluator(s.ctl, rbac_project.NewBuilderForUser(s.user, s.ctl))) s.evaluator = evaluators }) diff --git a/src/common/security/local/context_test.go b/src/common/security/local/context_test.go index 22f93e3b9..4e9404967 100644 --- a/src/common/security/local/context_test.go +++ b/src/common/security/local/context_test.go @@ -16,6 +16,7 @@ package local import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "testing" "github.com/goharbor/harbor/src/common" @@ -116,7 +117,7 @@ func TestHasPullPerm(t *testing.T) { ctx := NewSecurityContext(nil) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(1).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } @@ -127,7 +128,7 @@ func TestHasPullPerm(t *testing.T) { ctx := NewSecurityContext(nil) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.False(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } @@ -139,7 +140,7 @@ func TestHasPullPerm(t *testing.T) { ctx := NewSecurityContext(&models.User{Username: "test"}) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.False(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } @@ -151,7 +152,7 @@ func TestHasPullPerm(t *testing.T) { ctx := NewSecurityContext(guestUser) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } @@ -165,13 +166,13 @@ func TestHasPullPerm(t *testing.T) { SysAdminFlag: true, }) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } } func TestHasPushPerm(t *testing.T) { - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) { // unauthenticated @@ -218,7 +219,7 @@ func TestHasPushPerm(t *testing.T) { } func TestHasPushPullPerm(t *testing.T) { - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) { // unauthenticated @@ -266,7 +267,7 @@ func TestSysadminPerms(t *testing.T) { SysAdminFlag: true, }) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPush, resource) && ctx.Can(context.TODO(), rbac.ActionPull, resource)) assert.False(t, ctx.Can(context.TODO(), rbac.ActionScannerPull, resource)) diff --git a/src/common/security/proxycachesecret/context.go b/src/common/security/proxycachesecret/context.go index 4847def31..f77a88e9e 100644 --- a/src/common/security/proxycachesecret/context.go +++ b/src/common/security/proxycachesecret/context.go @@ -16,6 +16,7 @@ package proxycachesecret import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/utils" @@ -75,7 +76,7 @@ func (s *SecurityContext) Can(ctx context.Context, action types.Action, resource log.Debugf("unauthorized for action %s", action) return false } - namespace, ok := rbac.ProjectNamespaceParse(resource) + namespace, ok := rbac_project.NamespaceParse(resource) if !ok { log.Debugf("got no namespace from the resource %s", resource) return false diff --git a/src/common/security/proxycachesecret/context_test.go b/src/common/security/proxycachesecret/context_test.go index 238e42e08..87e67096b 100644 --- a/src/common/security/proxycachesecret/context_test.go +++ b/src/common/security/proxycachesecret/context_test.go @@ -17,6 +17,7 @@ package proxycachesecret import ( "context" "errors" + "github.com/goharbor/harbor/src/common/rbac/project" "testing" "github.com/goharbor/harbor/src/common/models" @@ -63,7 +64,7 @@ func (p *proxyCacheSecretTestSuite) TestIsSolutionUser() { func (p *proxyCacheSecretTestSuite) TestCan() { // the action isn't pull/push action := rbac.ActionDelete - resource := rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository) + resource := project.NewNamespace(1).Resource(rbac.ResourceRepository) p.False(p.sc.Can(context.TODO(), action, resource)) // the resource isn't repository @@ -73,7 +74,7 @@ func (p *proxyCacheSecretTestSuite) TestCan() { // the requested project not found action = rbac.ActionPull - resource = rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository) + resource = project.NewNamespace(2).Resource(rbac.ResourceRepository) p.ctl.On("Get", mock.Anything, mock.Anything).Return(nil, errors.New("not found")) p.False(p.sc.Can(context.TODO(), action, resource)) p.ctl.AssertExpectations(p.T()) @@ -83,7 +84,7 @@ func (p *proxyCacheSecretTestSuite) TestCan() { // pass for action pull action = rbac.ActionPull - resource = rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository) + resource = project.NewNamespace(1).Resource(rbac.ResourceRepository) p.ctl.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ ProjectID: 1, Name: "library", @@ -96,7 +97,7 @@ func (p *proxyCacheSecretTestSuite) TestCan() { // pass for action push action = rbac.ActionPush - resource = rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository) + resource = project.NewNamespace(1).Resource(rbac.ResourceRepository) p.ctl.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ ProjectID: 1, Name: "library", diff --git a/src/common/security/robot/context.go b/src/common/security/robot/context.go index 3cd7a28c0..69eeba24b 100644 --- a/src/common/security/robot/context.go +++ b/src/common/security/robot/context.go @@ -16,6 +16,7 @@ package robot import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/rbac/system" "github.com/goharbor/harbor/src/controller/robot" "strings" @@ -95,12 +96,12 @@ func (s *SecurityContext) Can(ctx context.Context, action types.Action, resource if len(sysPolicies) != 0 { evaluators = evaluators.Add(system.NewEvaluator(s.GetUsername(), sysPolicies)) } else if len(proPolicies) != 0 { - evaluators = evaluators.Add(rbac.NewProjectEvaluator(s.ctl, rbac.NewBuilderForPolicies(s.GetUsername(), proPolicies))) + evaluators = evaluators.Add(rbac_project.NewEvaluator(s.ctl, rbac_project.NewBuilderForPolicies(s.GetUsername(), proPolicies))) } s.evaluator = evaluators } else { - s.evaluator = rbac.NewProjectEvaluator(s.ctl, rbac.NewBuilderForPolicies(s.GetUsername(), s.policies, filterRobotPolicies)) + s.evaluator = rbac_project.NewEvaluator(s.ctl, rbac_project.NewBuilderForPolicies(s.GetUsername(), s.policies, filterRobotPolicies)) } }) @@ -108,7 +109,7 @@ func (s *SecurityContext) Can(ctx context.Context, action types.Action, resource } func filterRobotPolicies(p *models.Project, policies []*types.Policy) []*types.Policy { - namespace := rbac.NewProjectNamespace(p.ProjectID) + namespace := rbac_project.NewNamespace(p.ProjectID) var results []*types.Policy for _, policy := range policies { diff --git a/src/common/security/robot/context_test.go b/src/common/security/robot/context_test.go index 097c12adc..c14547bf8 100644 --- a/src/common/security/robot/context_test.go +++ b/src/common/security/robot/context_test.go @@ -17,6 +17,7 @@ package robot import ( "context" "fmt" + "github.com/goharbor/harbor/src/common/rbac/project" "reflect" "testing" @@ -97,7 +98,7 @@ func TestHasPullPerm(t *testing.T) { ctx := NewSecurityContext(robot, false, policies) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPull, resource)) } @@ -118,7 +119,7 @@ func TestHasPushPerm(t *testing.T) { ctx := NewSecurityContext(robot, false, policies) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPush, resource)) } @@ -143,7 +144,7 @@ func TestHasPushPullPerm(t *testing.T) { ctx := NewSecurityContext(robot, false, policies) ctx.ctl = ctl - resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository) + resource := project.NewNamespace(private.ProjectID).Resource(rbac.ResourceRepository) assert.True(t, ctx.Can(context.TODO(), rbac.ActionPush, resource) && ctx.Can(context.TODO(), rbac.ActionPull, resource)) } diff --git a/src/common/security/v2token/context.go b/src/common/security/v2token/context.go index b26f2b356..83f545e5c 100644 --- a/src/common/security/v2token/context.go +++ b/src/common/security/v2token/context.go @@ -2,6 +2,7 @@ package v2token import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "strings" registry_token "github.com/docker/distribution/registry/auth/token" @@ -55,7 +56,7 @@ func (t *tokenSecurityCtx) Can(ctx context.Context, action types.Action, resourc if !strings.HasSuffix(resource.String(), rbac.ResourceRepository.String()) { return false } - ns, ok := rbac.ProjectNamespaceParse(resource) + ns, ok := rbac_project.NamespaceParse(resource) if !ok { t.logger.Warningf("Failed to get namespace from resource: %s", resource) return false diff --git a/src/common/security/v2token/context_test.go b/src/common/security/v2token/context_test.go index cd1a52f5a..185556f0d 100644 --- a/src/common/security/v2token/context_test.go +++ b/src/common/security/v2token/context_test.go @@ -16,6 +16,7 @@ package v2token import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "testing" "github.com/docker/distribution/registry/auth/token" @@ -71,42 +72,42 @@ func TestAll(t *testing.T) { expect bool }{ { - resource: rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(1).Resource(rbac.ResourceRepository), action: rbac.ActionPush, expect: true, }, { - resource: rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(1).Resource(rbac.ResourceRepository), action: rbac.ActionScannerPull, expect: true, }, { - resource: rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(2).Resource(rbac.ResourceRepository), action: rbac.ActionPush, expect: true, }, { - resource: rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(2).Resource(rbac.ResourceRepository), action: rbac.ActionDelete, expect: true, }, { - resource: rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(2).Resource(rbac.ResourceRepository), action: rbac.ActionScannerPull, expect: false, }, { - resource: rbac.NewProjectNamespace(3).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(3).Resource(rbac.ResourceRepository), action: rbac.ActionPush, expect: false, }, { - resource: rbac.NewProjectNamespace(2).Resource(rbac.ResourceArtifact), + resource: rbac_project.NewNamespace(2).Resource(rbac.ResourceArtifact), action: rbac.ActionPush, expect: false, }, { - resource: rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository), + resource: rbac_project.NewNamespace(1).Resource(rbac.ResourceRepository), action: rbac.ActionCreate, expect: false, }, diff --git a/src/controller/robot/controller.go b/src/controller/robot/controller.go index b449112f3..22f31e46c 100644 --- a/src/controller/robot/controller.go +++ b/src/controller/robot/controller.go @@ -3,7 +3,7 @@ package robot import ( "context" "fmt" - rbac_common "github.com/goharbor/harbor/src/common/rbac" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/lib/errors" @@ -312,7 +312,7 @@ func (d *controller) convertScope(ctx context.Context, scope string) (kind, name namespace = "*" } else { kind = LEVELPROJECT - ns, ok := rbac_common.ProjectNamespaceParse(types.Resource(scope)) + ns, ok := rbac_project.NamespaceParse(types.Resource(scope)) if !ok { log.Debugf("got no namespace from the resource %s", scope) return "", "", errors.Errorf("got no namespace from the resource %s", scope) diff --git a/src/core/api/base.go b/src/core/api/base.go index 6d8b44228..974590f52 100644 --- a/src/core/api/base.go +++ b/src/core/api/base.go @@ -24,6 +24,7 @@ import ( "github.com/goharbor/harbor/src/common/api" "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/controller/p2p/preheat" @@ -84,7 +85,7 @@ func (b *BaseController) HasProjectPermission(projectIDOrName interface{}, actio return false, err } - resource := rbac.NewProjectNamespace(project.ProjectID).Resource(subresource...) + resource := rbac_project.NewNamespace(project.ProjectID).Resource(subresource...) if !b.SecurityCtx.Can(b.Context(), action, resource) { return false, nil } diff --git a/src/core/service/token/creator.go b/src/core/service/token/creator.go index 1b76e6f3a..45d58e949 100644 --- a/src/core/service/token/creator.go +++ b/src/core/service/token/creator.go @@ -17,6 +17,7 @@ package token import ( "context" "fmt" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "net/http" "net/url" "strings" @@ -182,7 +183,7 @@ func (rep repositoryFilter) filter(ctx context.Context, ctl project.Controller, return err } - resource := rbac.NewProjectNamespace(project.ProjectID).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(project.ProjectID).Resource(rbac.ResourceRepository) scopeList := make([]string, 0) for s := range resourceScopes(ctx, resource) { scopeList = append(scopeList, s) diff --git a/src/core/service/token/token_test.go b/src/core/service/token/token_test.go index 8a526a3c5..ec5b98c20 100644 --- a/src/core/service/token/token_test.go +++ b/src/core/service/token/token_test.go @@ -19,6 +19,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "github.com/goharbor/harbor/src/common/rbac/project" "io/ioutil" "net/url" "os" @@ -302,10 +303,10 @@ func TestResourceScopes(t *testing.T) { sctx := &fakeSecurityContext{ isAdmin: false, rcActions: map[rbac.Resource][]rbac.Action{ - rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull}, - rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull, rbac.ActionPush}, - rbac.NewProjectNamespace(3).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull, rbac.ActionPush, rbac.ActionDelete}, - rbac.NewProjectNamespace(4).Resource(rbac.ResourceRepository): {}, + project.NewNamespace(1).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull}, + project.NewNamespace(2).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull, rbac.ActionPush}, + project.NewNamespace(3).Resource(rbac.ResourceRepository): {rbac.ActionPull, rbac.ActionScannerPull, rbac.ActionPush, rbac.ActionDelete}, + project.NewNamespace(4).Resource(rbac.ResourceRepository): {}, }, } ctx := security.NewContext(context.TODO(), sctx) @@ -314,14 +315,14 @@ func TestResourceScopes(t *testing.T) { expect map[string]struct{} }{ { - rc: rbac.NewProjectNamespace(1).Resource(rbac.ResourceRepository), + rc: project.NewNamespace(1).Resource(rbac.ResourceRepository), expect: map[string]struct{}{ "pull": {}, "scanner-pull": {}, }, }, { - rc: rbac.NewProjectNamespace(2).Resource(rbac.ResourceRepository), + rc: project.NewNamespace(2).Resource(rbac.ResourceRepository), expect: map[string]struct{}{ "pull": {}, "scanner-pull": {}, @@ -329,7 +330,7 @@ func TestResourceScopes(t *testing.T) { }, }, { - rc: rbac.NewProjectNamespace(3).Resource(rbac.ResourceRepository), + rc: project.NewNamespace(3).Resource(rbac.ResourceRepository), expect: map[string]struct{}{ "pull": {}, "scanner-pull": {}, @@ -338,11 +339,11 @@ func TestResourceScopes(t *testing.T) { }, }, { - rc: rbac.NewProjectNamespace(4).Resource(rbac.ResourceRepository), + rc: project.NewNamespace(4).Resource(rbac.ResourceRepository), expect: map[string]struct{}{}, }, { - rc: rbac.NewProjectNamespace(5).Resource(rbac.ResourceRepository), + rc: project.NewNamespace(5).Resource(rbac.ResourceRepository), expect: map[string]struct{}{}, }, } diff --git a/src/server/middleware/util/util.go b/src/server/middleware/util/util.go index 615cfa274..8bd11a4d6 100644 --- a/src/server/middleware/util/util.go +++ b/src/server/middleware/util/util.go @@ -17,6 +17,7 @@ package util import ( "context" "fmt" + "github.com/goharbor/harbor/src/common/rbac/project" "net/http" "path" "strings" @@ -61,7 +62,7 @@ func SkipPolicyChecking(ctx context.Context, projectID int64) bool { // only scanner pull access can bypass. if ok && secCtx.Name() == "v2token" && - secCtx.Can(ctx, rbac.ActionScannerPull, rbac.NewProjectNamespace(projectID).Resource(rbac.ResourceRepository)) { + secCtx.Can(ctx, rbac.ActionScannerPull, project.NewNamespace(projectID).Resource(rbac.ResourceRepository)) { return true } diff --git a/src/server/middleware/v2auth/auth.go b/src/server/middleware/v2auth/auth.go index 102e03d1a..ff2ed6b74 100644 --- a/src/server/middleware/v2auth/auth.go +++ b/src/server/middleware/v2auth/auth.go @@ -17,6 +17,7 @@ package v2auth import ( "context" "fmt" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/rbac/system" "net/http" "net/url" @@ -67,7 +68,7 @@ func (rc *reqChecker) check(req *http.Request) (string, error) { if err != nil { return "", err } - resource := rbac.NewProjectNamespace(pid).Resource(rbac.ResourceRepository) + resource := rbac_project.NewNamespace(pid).Resource(rbac.ResourceRepository) if !securityCtx.Can(req.Context(), a.action, resource) { return getChallenge(req, al), fmt.Errorf("unauthorized to access repository: %s, action: %s", a.name, a.action) } diff --git a/src/server/v2.0/handler/base.go b/src/server/v2.0/handler/base.go index a50b75647..607a6620f 100644 --- a/src/server/v2.0/handler/base.go +++ b/src/server/v2.0/handler/base.go @@ -18,6 +18,7 @@ package handler import ( "context" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "github.com/goharbor/harbor/src/common/rbac/system" "net/http" "net/url" @@ -86,7 +87,7 @@ func (b *BaseAPI) HasProjectPermission(ctx context.Context, projectIDOrName inte projectID = p.ProjectID } - resource := rbac.NewProjectNamespace(projectID).Resource(subresource...) + resource := rbac_project.NewNamespace(projectID).Resource(subresource...) return b.HasPermission(ctx, action, resource) } diff --git a/src/server/v2.0/handler/robotV1.go b/src/server/v2.0/handler/robotV1.go index f6ead8e4f..30d3c9ee5 100644 --- a/src/server/v2.0/handler/robotV1.go +++ b/src/server/v2.0/handler/robotV1.go @@ -3,6 +3,7 @@ package handler import ( "context" "fmt" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" "regexp" "strings" @@ -256,7 +257,7 @@ func (rAPI *robotV1API) validate(ctx context.Context, params operation.CreateRob return err } - policies := rbac.GetPoliciesOfProject(pro.ProjectID) + policies := rbac_project.GetPoliciesOfProject(pro.ProjectID) mp := map[string]bool{} for _, policy := range policies {