mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-25 10:07:43 +01:00
Merge pull request #6852 from heww/protect-api-using-rbac
Protect API using rbac
This commit is contained in:
commit
f7218f80e0
@ -38,11 +38,14 @@ const (
|
||||
ResourceHelmChartVersion = Resource("helm-chart-version")
|
||||
ResourceHelmChartVersionLabel = Resource("helm-chart-version-label")
|
||||
ResourceLabel = Resource("label")
|
||||
ResourceLabelResource = Resource("label-resource")
|
||||
ResourceLog = Resource("log")
|
||||
ResourceMember = Resource("member")
|
||||
ResourceMetadata = Resource("metadata")
|
||||
ResourceReplication = Resource("replication")
|
||||
ResourceReplicationJob = Resource("replication-job")
|
||||
ResourceRepository = Resource("repository")
|
||||
ResourceRepositoryLabel = Resource("repository-label")
|
||||
ResourceRepositoryTag = Resource("repository-tag")
|
||||
ResourceRepositoryTagLabel = Resource("repository-tag-label")
|
||||
ResourceRepositoryTagManifest = Resource("repository-tag-manifest")
|
||||
|
@ -52,6 +52,10 @@ func (ns *projectNamespace) IsPublic() bool {
|
||||
}
|
||||
|
||||
// NewProjectNamespace returns namespace for project
|
||||
func NewProjectNamespace(projectIDOrName interface{}, isPublic bool) Namespace {
|
||||
return &projectNamespace{projectIDOrName: projectIDOrName, isPublic: isPublic}
|
||||
func NewProjectNamespace(projectIDOrName interface{}, isPublic ...bool) Namespace {
|
||||
isPublicNamespace := false
|
||||
if len(isPublic) > 0 {
|
||||
isPublicNamespace = isPublic[0]
|
||||
}
|
||||
return &projectNamespace{projectIDOrName: projectIDOrName, isPublic: isPublicNamespace}
|
||||
}
|
||||
|
@ -23,9 +23,23 @@ var (
|
||||
publicProjectPolicies = []*rbac.Policy{
|
||||
{Resource: rbac.ResourceSelf, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionList},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPull},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagVulnerability, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagManifest, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionList},
|
||||
|
||||
@ -44,10 +58,16 @@ var (
|
||||
{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.ResourceReplication, Action: rbac.ActionList},
|
||||
{Resource: rbac.ResourceReplication, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceReplication, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceReplication, Action: rbac.ActionUpdate},
|
||||
{Resource: rbac.ResourceReplication, Action: rbac.ActionDelete},
|
||||
|
||||
@ -56,17 +76,25 @@ var (
|
||||
{Resource: rbac.ResourceReplicationJob, 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.ResourceLabelResource, 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.ActionPushPull}, // compatible with security all perm of project
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPush},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPull},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPush},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPushPull}, // compatible with security all perm of project
|
||||
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionDelete},
|
||||
@ -81,12 +109,14 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, 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},
|
||||
|
@ -31,6 +31,11 @@ var (
|
||||
{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.ResourceReplication, Action: rbac.ActionRead},
|
||||
@ -40,18 +45,25 @@ var (
|
||||
{Resource: rbac.ResourceReplicationJob, 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.ResourceLabelResource, 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.ActionPushPull}, // compatible with security all perm of project
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPush},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPull},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPushPull},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPush},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPushPull}, // compatible with security all perm of project
|
||||
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionDelete},
|
||||
@ -66,6 +78,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate}, // upload helm chart
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead}, // download helm chart
|
||||
@ -95,23 +108,34 @@ var (
|
||||
|
||||
{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.ResourceReplication, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceReplication, 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.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.ResourceRepositoryLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionList},
|
||||
@ -125,6 +149,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead},
|
||||
@ -140,7 +165,9 @@ var (
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionUpdate},
|
||||
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionList},
|
||||
},
|
||||
|
||||
"developer": {
|
||||
@ -150,11 +177,20 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceLog, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionRead},
|
||||
{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.ActionList},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPush},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPull},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionList},
|
||||
|
||||
@ -164,6 +200,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceHelmChart, Action: rbac.ActionRead},
|
||||
@ -177,6 +214,9 @@ var (
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionList},
|
||||
},
|
||||
|
||||
"guest": {
|
||||
@ -186,12 +226,20 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceLog, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionList},
|
||||
{Resource: rbac.ResourceRepository, Action: rbac.ActionPull},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRepositoryTag, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagVulnerability, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceRepositoryTagManifest, Action: rbac.ActionRead},
|
||||
@ -203,6 +251,9 @@ var (
|
||||
{Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceRobot, Action: rbac.ActionList},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -69,24 +69,6 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
func (s *SecurityContext) Can(action rbac.Action, resource rbac.Resource) bool {
|
||||
ns, err := resource.GetNamespace()
|
||||
|
@ -29,12 +29,6 @@ type Context interface {
|
||||
IsSysAdmin() bool
|
||||
// IsSolutionUser returns whether the user is solution user
|
||||
IsSolutionUser() bool
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
HasReadPerm(projectIDOrName interface{}) bool
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
HasWritePerm(projectIDOrName interface{}) bool
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
HasAllPerm(projectIDOrName interface{}) bool
|
||||
// Get current user's all project
|
||||
GetMyProjects() ([]*models.Project, error)
|
||||
// Get user's role in provided project
|
||||
|
@ -67,24 +67,6 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
func (s *SecurityContext) Can(action rbac.Action, resource rbac.Resource) bool {
|
||||
ns, err := resource.GetNamespace()
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/promgr"
|
||||
"github.com/goharbor/harbor/src/core/promgr/pmsdriver/local"
|
||||
@ -210,66 +211,73 @@ func TestIsSolutionUser(t *testing.T) {
|
||||
func TestHasReadPerm(t *testing.T) {
|
||||
// public project
|
||||
ctx := NewSecurityContext(nil, pm)
|
||||
assert.True(t, ctx.HasReadPerm("library"))
|
||||
|
||||
resource := rbac.NewProjectNamespace("library").Resource(rbac.ResourceRepository)
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
|
||||
// private project, unauthenticated
|
||||
ctx = NewSecurityContext(nil, pm)
|
||||
assert.False(t, ctx.HasReadPerm(private.Name))
|
||||
resource = rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
assert.False(t, ctx.Can(rbac.ActionPull, resource))
|
||||
|
||||
// private project, authenticated, has no perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pm)
|
||||
assert.False(t, ctx.HasReadPerm(private.Name))
|
||||
assert.False(t, ctx.Can(rbac.ActionPull, resource))
|
||||
|
||||
// private project, authenticated, has read perm
|
||||
ctx = NewSecurityContext(guestUser, pm)
|
||||
assert.True(t, ctx.HasReadPerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
|
||||
// private project, authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "admin",
|
||||
HasAdminRole: true,
|
||||
}, pm)
|
||||
assert.True(t, ctx.HasReadPerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestHasWritePerm(t *testing.T) {
|
||||
resource := rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, pm)
|
||||
assert.False(t, ctx.HasWritePerm(private.Name))
|
||||
assert.False(t, ctx.Can(rbac.ActionPush, resource))
|
||||
|
||||
// authenticated, has read perm
|
||||
ctx = NewSecurityContext(guestUser, pm)
|
||||
assert.False(t, ctx.HasWritePerm(private.Name))
|
||||
assert.False(t, ctx.Can(rbac.ActionPush, resource))
|
||||
|
||||
// authenticated, has write perm
|
||||
ctx = NewSecurityContext(developerUser, pm)
|
||||
assert.True(t, ctx.HasWritePerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPush, resource))
|
||||
|
||||
// authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "admin",
|
||||
HasAdminRole: true,
|
||||
}, pm)
|
||||
assert.True(t, ctx.HasReadPerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPush, resource))
|
||||
}
|
||||
|
||||
func TestHasAllPerm(t *testing.T) {
|
||||
resource := rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, pm)
|
||||
assert.False(t, ctx.HasAllPerm(private.Name))
|
||||
assert.False(t, ctx.Can(rbac.ActionPushPull, resource))
|
||||
|
||||
// authenticated, has all perms
|
||||
ctx = NewSecurityContext(projectAdminUser, pm)
|
||||
assert.True(t, ctx.HasAllPerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPushPull, resource))
|
||||
|
||||
// authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "admin",
|
||||
HasAdminRole: true,
|
||||
}, pm)
|
||||
assert.True(t, ctx.HasAllPerm(private.Name))
|
||||
assert.True(t, ctx.Can(rbac.ActionPushPull, resource))
|
||||
}
|
||||
|
||||
func TestHasAllPermWithGroup(t *testing.T) {
|
||||
@ -285,10 +293,13 @@ func TestHasAllPermWithGroup(t *testing.T) {
|
||||
developer.GroupList = []*models.UserGroup{
|
||||
{GroupName: "test_group", GroupType: 1, LdapGroupDN: "cn=harbor_user,dc=example,dc=com"},
|
||||
}
|
||||
|
||||
resource := rbac.NewProjectNamespace(project.Name).Resource(rbac.ResourceRepository)
|
||||
|
||||
ctx := NewSecurityContext(developer, pm)
|
||||
assert.False(t, ctx.HasAllPerm(project.Name))
|
||||
assert.True(t, ctx.HasWritePerm(project.Name))
|
||||
assert.True(t, ctx.HasReadPerm(project.Name))
|
||||
assert.False(t, ctx.Can(rbac.ActionPushPull, resource))
|
||||
assert.True(t, ctx.Can(rbac.ActionPush, resource))
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestGetMyProjects(t *testing.T) {
|
||||
|
@ -60,24 +60,6 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
||||
return s.Can(rbac.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// GetMyProjects no implementation
|
||||
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
|
@ -16,6 +16,7 @@ package robot
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
@ -26,7 +27,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/core/promgr/pmsdriver/local"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -147,7 +147,8 @@ func TestHasReadPerm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := NewSecurityContext(robot, pm, policies)
|
||||
assert.True(t, ctx.HasReadPerm(private.Name))
|
||||
resource := rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestHasWritePerm(t *testing.T) {
|
||||
@ -164,7 +165,8 @@ func TestHasWritePerm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := NewSecurityContext(robot, pm, policies)
|
||||
assert.True(t, ctx.HasWritePerm(private.Name))
|
||||
resource := rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
assert.True(t, ctx.Can(rbac.ActionPush, resource))
|
||||
}
|
||||
|
||||
func TestHasAllPerm(t *testing.T) {
|
||||
@ -180,7 +182,8 @@ func TestHasAllPerm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := NewSecurityContext(robot, pm, policies)
|
||||
assert.True(t, ctx.HasAllPerm(private.Name))
|
||||
resource := rbac.NewProjectNamespace(private.Name).Resource(rbac.ResourceRepository)
|
||||
assert.True(t, ctx.Can(rbac.ActionPushPull, resource))
|
||||
}
|
||||
|
||||
func TestGetMyProjects(t *testing.T) {
|
||||
|
@ -71,34 +71,9 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
return s.IsAuthenticated()
|
||||
}
|
||||
|
||||
// HasReadPerm returns true if the corresponding user of the secret
|
||||
// is jobservice or core service, otherwise returns false
|
||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
if s.store == nil {
|
||||
return false
|
||||
}
|
||||
return s.store.GetUsername(s.secret) == secret.JobserviceUser || s.store.GetUsername(s.secret) == secret.CoreUser
|
||||
}
|
||||
|
||||
// HasWritePerm returns true if the corresponding user of the secret
|
||||
// is jobservice or core service, otherwise returns false
|
||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
if s.store == nil {
|
||||
return false
|
||||
}
|
||||
return s.store.GetUsername(s.secret) == secret.JobserviceUser || s.store.GetUsername(s.secret) == secret.CoreUser
|
||||
}
|
||||
|
||||
// HasAllPerm returns true if the corresponding user of the secret
|
||||
// is jobservice or core service, otherwise returns false
|
||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
if s.store == nil {
|
||||
return false
|
||||
}
|
||||
return s.store.GetUsername(s.secret) == secret.JobserviceUser || s.store.GetUsername(s.secret) == secret.CoreUser
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
// returns true if the corresponding user of the secret
|
||||
// is jobservice or core service, otherwise returns false
|
||||
func (s *SecurityContext) Can(action rbac.Action, resource rbac.Resource) bool {
|
||||
if s.store == nil {
|
||||
return false
|
||||
@ -114,7 +89,9 @@ func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||
// GetProjectRoles return guest role if has read permission, otherwise return nil
|
||||
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
||||
roles := []int{}
|
||||
if s.HasReadPerm(projectIDOrName) {
|
||||
if s.store != nil &&
|
||||
(s.store.GetUsername(s.secret) == secret.JobserviceUser ||
|
||||
s.store.GetUsername(s.secret) == secret.CoreUser) {
|
||||
roles = append(roles, common.RoleGuest)
|
||||
}
|
||||
return roles
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -96,9 +97,11 @@ func TestIsSolutionUser(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHasReadPerm(t *testing.T) {
|
||||
readAction := rbac.Action("pull")
|
||||
resource := rbac.Resource("/project/project_name/repository")
|
||||
// secret store is null
|
||||
context := NewSecurityContext("", nil)
|
||||
hasReadPerm := context.HasReadPerm("project_name")
|
||||
hasReadPerm := context.Can(readAction, resource)
|
||||
assert.False(t, hasReadPerm)
|
||||
|
||||
// invalid secret
|
||||
@ -106,7 +109,7 @@ func TestHasReadPerm(t *testing.T) {
|
||||
secret.NewStore(map[string]string{
|
||||
"jobservice_secret": secret.JobserviceUser,
|
||||
}))
|
||||
hasReadPerm = context.HasReadPerm("project_name")
|
||||
hasReadPerm = context.Can(readAction, resource)
|
||||
assert.False(t, hasReadPerm)
|
||||
|
||||
// valid secret, project name
|
||||
@ -114,11 +117,12 @@ func TestHasReadPerm(t *testing.T) {
|
||||
secret.NewStore(map[string]string{
|
||||
"jobservice_secret": secret.JobserviceUser,
|
||||
}))
|
||||
hasReadPerm = context.HasReadPerm("project_name")
|
||||
hasReadPerm = context.Can(readAction, resource)
|
||||
assert.True(t, hasReadPerm)
|
||||
|
||||
// valid secret, project ID
|
||||
hasReadPerm = context.HasReadPerm(1)
|
||||
resource = rbac.Resource("/project/1/repository")
|
||||
hasReadPerm = context.Can(readAction, resource)
|
||||
assert.True(t, hasReadPerm)
|
||||
}
|
||||
|
||||
@ -128,12 +132,16 @@ func TestHasWritePerm(t *testing.T) {
|
||||
"secret": "username",
|
||||
}))
|
||||
|
||||
writeAction := rbac.Action("push")
|
||||
|
||||
// project name
|
||||
hasWritePerm := context.HasWritePerm("project_name")
|
||||
resource := rbac.Resource("/project/project_name/repository")
|
||||
hasWritePerm := context.Can(writeAction, resource)
|
||||
assert.False(t, hasWritePerm)
|
||||
|
||||
// project ID
|
||||
hasWritePerm = context.HasWritePerm(1)
|
||||
resource = rbac.Resource("/project/1/repository")
|
||||
hasWritePerm = context.Can(writeAction, resource)
|
||||
assert.False(t, hasWritePerm)
|
||||
}
|
||||
|
||||
@ -143,12 +151,16 @@ func TestHasAllPerm(t *testing.T) {
|
||||
"secret": "username",
|
||||
}))
|
||||
|
||||
allAction := rbac.Action("push+pull")
|
||||
|
||||
// project name
|
||||
hasAllPerm := context.HasAllPerm("project_name")
|
||||
resource := rbac.Resource("/project/project_name/repository")
|
||||
hasAllPerm := context.Can(allAction, resource)
|
||||
assert.False(t, hasAllPerm)
|
||||
|
||||
// project ID
|
||||
hasAllPerm = context.HasAllPerm(1)
|
||||
resource = rbac.Resource("/project/1/repository")
|
||||
hasAllPerm = context.Can(allAction, resource)
|
||||
assert.False(t, hasAllPerm)
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -45,12 +46,6 @@ func (cla *ChartLabelAPI) Prepare() {
|
||||
}
|
||||
cla.project = existingProject
|
||||
|
||||
// Check permission
|
||||
if !cla.checkPermissions(project) {
|
||||
cla.SendForbiddenError(errors.New(cla.SecurityCtx.GetUsername()))
|
||||
return
|
||||
}
|
||||
|
||||
// Check the existence of target chart
|
||||
chartName := cla.GetStringFromPath(nameParam)
|
||||
version := cla.GetStringFromPath(versionParam)
|
||||
@ -62,8 +57,23 @@ func (cla *ChartLabelAPI) Prepare() {
|
||||
cla.chartFullName = fmt.Sprintf("%s/%s:%s", project, chartName, version)
|
||||
}
|
||||
|
||||
func (cla *ChartLabelAPI) requireAccess(action rbac.Action) bool {
|
||||
resource := rbac.NewProjectNamespace(cla.project.ProjectID).Resource(rbac.ResourceHelmChartVersionLabel)
|
||||
|
||||
if !cla.SecurityCtx.Can(action, resource) {
|
||||
cla.HandleForbidden(cla.SecurityCtx.GetUsername())
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MarkLabel handles the request of marking label to chart.
|
||||
func (cla *ChartLabelAPI) MarkLabel() {
|
||||
if !cla.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
l := &models.Label{}
|
||||
cla.DecodeJSONReq(l)
|
||||
|
||||
@ -83,6 +93,10 @@ func (cla *ChartLabelAPI) MarkLabel() {
|
||||
|
||||
// RemoveLabel handles the request of removing label from chart.
|
||||
func (cla *ChartLabelAPI) RemoveLabel() {
|
||||
if !cla.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
lID, err := cla.GetInt64FromPath(idParam)
|
||||
if err != nil {
|
||||
cla.SendInternalServerError(err)
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/core/label"
|
||||
|
||||
"github.com/goharbor/harbor/src/chartserver"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
hlog "github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
@ -84,10 +85,35 @@ func (cra *ChartRepositoryAPI) Prepare() {
|
||||
cra.labelManager = &label.BaseManager{}
|
||||
}
|
||||
|
||||
func (cra *ChartRepositoryAPI) requireAccess(action rbac.Action, subresource ...rbac.Resource) bool {
|
||||
if len(subresource) == 0 {
|
||||
subresource = append(subresource, rbac.ResourceHelmChart)
|
||||
}
|
||||
resource := rbac.NewProjectNamespace(cra.namespace).Resource(subresource...)
|
||||
|
||||
if !cra.SecurityCtx.Can(action, resource) {
|
||||
if !cra.SecurityCtx.IsAuthenticated() {
|
||||
cra.SendUnAuthorizedError(errors.New("Unauthorized"))
|
||||
} else {
|
||||
cra.HandleForbidden(cra.SecurityCtx.GetUsername())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetHealthStatus handles GET /api/chartrepo/health
|
||||
func (cra *ChartRepositoryAPI) GetHealthStatus() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelSystem) {
|
||||
if !cra.SecurityCtx.IsAuthenticated() {
|
||||
cra.SendUnAuthorizedError(errors.New("Unauthorized"))
|
||||
return
|
||||
}
|
||||
|
||||
if !cra.SecurityCtx.IsSysAdmin() {
|
||||
cra.HandleForbidden(cra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
|
||||
@ -98,7 +124,7 @@ func (cra *ChartRepositoryAPI) GetHealthStatus() {
|
||||
// GetIndexByRepo handles GET /:repo/index.yaml
|
||||
func (cra *ChartRepositoryAPI) GetIndexByRepo() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelRead) {
|
||||
if !cra.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -109,7 +135,13 @@ func (cra *ChartRepositoryAPI) GetIndexByRepo() {
|
||||
// GetIndex handles GET /index.yaml
|
||||
func (cra *ChartRepositoryAPI) GetIndex() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelSystem) {
|
||||
if !cra.SecurityCtx.IsAuthenticated() {
|
||||
cra.SendUnAuthorizedError(errors.New("Unauthorized"))
|
||||
return
|
||||
}
|
||||
|
||||
if !cra.SecurityCtx.IsSysAdmin() {
|
||||
cra.HandleForbidden(cra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
|
||||
@ -136,7 +168,7 @@ func (cra *ChartRepositoryAPI) GetIndex() {
|
||||
// DownloadChart handles GET /:repo/charts/:filename
|
||||
func (cra *ChartRepositoryAPI) DownloadChart() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelRead) {
|
||||
if !cra.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -147,7 +179,7 @@ func (cra *ChartRepositoryAPI) DownloadChart() {
|
||||
// ListCharts handles GET /api/:repo/charts
|
||||
func (cra *ChartRepositoryAPI) ListCharts() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelRead) {
|
||||
if !cra.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -163,7 +195,7 @@ func (cra *ChartRepositoryAPI) ListCharts() {
|
||||
// ListChartVersions GET /api/:repo/charts/:name
|
||||
func (cra *ChartRepositoryAPI) ListChartVersions() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelRead) {
|
||||
if !cra.requireAccess(rbac.ActionList, rbac.ResourceHelmChartVersion) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -191,7 +223,7 @@ func (cra *ChartRepositoryAPI) ListChartVersions() {
|
||||
// GetChartVersion handles GET /api/:repo/charts/:name/:version
|
||||
func (cra *ChartRepositoryAPI) GetChartVersion() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelRead) {
|
||||
if !cra.requireAccess(rbac.ActionRead, rbac.ResourceHelmChartVersion) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -219,7 +251,7 @@ func (cra *ChartRepositoryAPI) GetChartVersion() {
|
||||
// DeleteChartVersion handles DELETE /api/:repo/charts/:name/:version
|
||||
func (cra *ChartRepositoryAPI) DeleteChartVersion() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelAll) {
|
||||
if !cra.requireAccess(rbac.ActionDelete, rbac.ResourceHelmChartVersion) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -244,7 +276,7 @@ func (cra *ChartRepositoryAPI) UploadChartVersion() {
|
||||
hlog.Debugf("Header of request of uploading chart: %#v, content-len=%d", cra.Ctx.Request.Header, cra.Ctx.Request.ContentLength)
|
||||
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelWrite) {
|
||||
if !cra.requireAccess(rbac.ActionCreate, rbac.ResourceHelmChartVersion) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -272,7 +304,7 @@ func (cra *ChartRepositoryAPI) UploadChartVersion() {
|
||||
// UploadChartProvFile handles POST /api/:repo/prov
|
||||
func (cra *ChartRepositoryAPI) UploadChartProvFile() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelWrite) {
|
||||
if !cra.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -297,7 +329,7 @@ func (cra *ChartRepositoryAPI) UploadChartProvFile() {
|
||||
// DeleteChart deletes all the chart versions of the specified chart.
|
||||
func (cra *ChartRepositoryAPI) DeleteChart() {
|
||||
// Check access
|
||||
if !cra.requireAccess(cra.namespace, accessLevelWrite) {
|
||||
if !cra.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -365,62 +397,6 @@ func (cra *ChartRepositoryAPI) requireNamespace(namespace string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the related access match the expected requirement
|
||||
// If with right access, return true
|
||||
// If without right access, return false
|
||||
func (cra *ChartRepositoryAPI) requireAccess(namespace string, accessLevel uint) bool {
|
||||
if accessLevel == accessLevelPublic {
|
||||
return true // do nothing
|
||||
}
|
||||
|
||||
theLevel := accessLevel
|
||||
// If repo is empty, system admin role must be required
|
||||
if len(namespace) == 0 {
|
||||
theLevel = accessLevelSystem
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
switch theLevel {
|
||||
// Should be system admin role
|
||||
case accessLevelSystem:
|
||||
if !cra.SecurityCtx.IsSysAdmin() {
|
||||
err = errors.New("permission denied: system admin role is required")
|
||||
}
|
||||
case accessLevelAll:
|
||||
if !cra.SecurityCtx.HasAllPerm(namespace) {
|
||||
err = errors.New("permission denied: project admin or higher role is required")
|
||||
}
|
||||
case accessLevelWrite:
|
||||
if !cra.SecurityCtx.HasWritePerm(namespace) {
|
||||
err = errors.New("permission denied: developer or higher role is required")
|
||||
}
|
||||
case accessLevelRead:
|
||||
if !cra.SecurityCtx.HasReadPerm(namespace) {
|
||||
err = errors.New("permission denied: guest or higher role is required")
|
||||
}
|
||||
default:
|
||||
// access rejected for invalid scope
|
||||
cra.SendForbiddenError(errors.New("unrecognized access scope"))
|
||||
return false
|
||||
}
|
||||
|
||||
// Access is not granted, check if user has authenticated
|
||||
if err != nil {
|
||||
// Unauthenticated, return 401
|
||||
if !cra.SecurityCtx.IsAuthenticated() {
|
||||
cra.SendUnAuthorizedError(errors.New("Unauthorized"))
|
||||
return false
|
||||
}
|
||||
|
||||
// Authenticated, return 403
|
||||
cra.SendForbiddenError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// formFile is used to represent the uploaded files in the form
|
||||
type formFile struct {
|
||||
// form field key contains the form file
|
||||
|
@ -17,29 +17,6 @@ var (
|
||||
crMockServer *httptest.Server
|
||||
)
|
||||
|
||||
// Test access checking
|
||||
func TestRequireAccess(t *testing.T) {
|
||||
chartAPI := &ChartRepositoryAPI{}
|
||||
chartAPI.SecurityCtx = &mockSecurityContext{}
|
||||
|
||||
ns := "library"
|
||||
if !chartAPI.requireAccess(ns, accessLevelPublic) {
|
||||
t.Fatal("expect true result (public access level is granted) but got false")
|
||||
}
|
||||
if !chartAPI.requireAccess(ns, accessLevelAll) {
|
||||
t.Fatal("expect true result (admin has all perm) but got false")
|
||||
}
|
||||
if !chartAPI.requireAccess(ns, accessLevelRead) {
|
||||
t.Fatal("expect true result (admin has read perm) but got false")
|
||||
}
|
||||
if !chartAPI.requireAccess(ns, accessLevelWrite) {
|
||||
t.Fatal("expect true result (admin has write perm) but got false")
|
||||
}
|
||||
if !chartAPI.requireAccess(ns, accessLevelSystem) {
|
||||
t.Fatal("expect true result (admin has system perm) but got false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMultipartFormData(t *testing.T) {
|
||||
req, err := createRequest(http.MethodPost, "/api/chartrepo/charts")
|
||||
if err != nil {
|
||||
@ -205,7 +182,7 @@ func TestDeleteChart(t *testing.T) {
|
||||
request: &testingRequest{
|
||||
url: "/api/chartrepo/library/charts/harbor",
|
||||
method: http.MethodDelete,
|
||||
credential: projDeveloper,
|
||||
credential: projAdmin,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
})
|
||||
@ -310,21 +287,6 @@ func (msc *mockSecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (msc *mockSecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
return msc.Can(rbac.ActionPull, rbac.NewProjectNamespace(projectIDOrName, false).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (msc *mockSecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
return msc.Can(rbac.ActionPush, rbac.NewProjectNamespace(projectIDOrName, false).Resource(rbac.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
func (msc *mockSecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
return msc.HasReadPerm(projectIDOrName) && msc.HasWritePerm(projectIDOrName)
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
func (msc *mockSecurityContext) Can(action rbac.Action, resource rbac.Resource) bool {
|
||||
namespace, err := resource.GetNamespace()
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
"github.com/goharbor/harbor/src/replication/core"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/models"
|
||||
@ -65,15 +66,36 @@ func (l *LabelAPI) Prepare() {
|
||||
return
|
||||
}
|
||||
|
||||
if label.Scope == common.LabelScopeGlobal && !l.SecurityCtx.IsSysAdmin() ||
|
||||
label.Scope == common.LabelScopeProject && !l.SecurityCtx.HasAllPerm(label.ProjectID) {
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
l.label = label
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LabelAPI) requireAccess(label *models.Label, action rbac.Action, subresources ...rbac.Resource) bool {
|
||||
var hasPermission bool
|
||||
|
||||
switch label.Scope {
|
||||
case common.LabelScopeGlobal:
|
||||
hasPermission = l.SecurityCtx.IsSysAdmin()
|
||||
case common.LabelScopeProject:
|
||||
if len(subresources) == 0 {
|
||||
subresources = append(subresources, rbac.ResourceLabel)
|
||||
}
|
||||
resource := rbac.NewProjectNamespace(label.ProjectID).Resource(subresources...)
|
||||
hasPermission = l.SecurityCtx.Can(action, resource)
|
||||
}
|
||||
|
||||
if !hasPermission {
|
||||
if !l.SecurityCtx.IsAuthenticated() {
|
||||
l.HandleUnauthorized()
|
||||
} else {
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Post creates a label
|
||||
func (l *LabelAPI) Post() {
|
||||
label := &models.Label{}
|
||||
@ -82,10 +104,6 @@ func (l *LabelAPI) Post() {
|
||||
|
||||
switch label.Scope {
|
||||
case common.LabelScopeGlobal:
|
||||
if !l.SecurityCtx.IsSysAdmin() {
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
label.ProjectID = 0
|
||||
case common.LabelScopeProject:
|
||||
exist, err := l.ProjectMgr.Exists(label.ProjectID)
|
||||
@ -98,10 +116,10 @@ func (l *LabelAPI) Post() {
|
||||
l.HandleNotFound(fmt.Sprintf("project %d not found", label.ProjectID))
|
||||
return
|
||||
}
|
||||
if !l.SecurityCtx.HasAllPerm(label.ProjectID) {
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !l.requireAccess(label, rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
labels, err := dao.ListLabels(&models.LabelQuery{
|
||||
@ -147,15 +165,8 @@ func (l *LabelAPI) Get() {
|
||||
return
|
||||
}
|
||||
|
||||
if label.Scope == common.LabelScopeProject {
|
||||
if !l.SecurityCtx.HasReadPerm(label.ProjectID) {
|
||||
if !l.SecurityCtx.IsAuthenticated() {
|
||||
l.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
if !l.requireAccess(label, rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
l.Data["json"] = label
|
||||
@ -189,7 +200,8 @@ func (l *LabelAPI) List() {
|
||||
return
|
||||
}
|
||||
|
||||
if !l.SecurityCtx.HasReadPerm(projectID) {
|
||||
resource := rbac.NewProjectNamespace(projectID).Resource(rbac.ResourceLabel)
|
||||
if !l.SecurityCtx.Can(rbac.ActionList, resource) {
|
||||
if !l.SecurityCtx.IsAuthenticated() {
|
||||
l.HandleUnauthorized()
|
||||
return
|
||||
@ -221,6 +233,10 @@ func (l *LabelAPI) List() {
|
||||
|
||||
// Put updates the label
|
||||
func (l *LabelAPI) Put() {
|
||||
if !l.requireAccess(l.label, rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
label := &models.Label{}
|
||||
l.DecodeJSONReq(label)
|
||||
|
||||
@ -259,6 +275,10 @@ func (l *LabelAPI) Put() {
|
||||
|
||||
// Delete the label
|
||||
func (l *LabelAPI) Delete() {
|
||||
if !l.requireAccess(l.label, rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
id := l.label.ID
|
||||
if err := dao.DeleteResourceLabelByLabel(id); err != nil {
|
||||
l.HandleInternalServerError(fmt.Sprintf("failed to delete resource label mappings of label %d: %v", id, err))
|
||||
@ -272,11 +292,6 @@ func (l *LabelAPI) Delete() {
|
||||
|
||||
// ListResources lists the resources that the label is referenced by
|
||||
func (l *LabelAPI) ListResources() {
|
||||
if !l.SecurityCtx.IsAuthenticated() {
|
||||
l.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
id, err := l.GetInt64FromPath(":id")
|
||||
if err != nil || id <= 0 {
|
||||
l.HandleBadRequest("invalid label ID")
|
||||
@ -294,9 +309,7 @@ func (l *LabelAPI) ListResources() {
|
||||
return
|
||||
}
|
||||
|
||||
if label.Scope == common.LabelScopeGlobal && !l.SecurityCtx.IsSysAdmin() ||
|
||||
label.Scope == common.LabelScopeProject && !l.SecurityCtx.HasAllPerm(label.ProjectID) {
|
||||
l.HandleForbidden(l.SecurityCtx.GetUsername())
|
||||
if !l.requireAccess(label, rbac.ActionList, rbac.ResourceLabelResource) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -22,23 +22,6 @@ func (lra *LabelResourceAPI) Prepare() {
|
||||
lra.labelManager = &label.BaseManager{}
|
||||
}
|
||||
|
||||
func (lra *LabelResourceAPI) checkPermissions(project string) bool {
|
||||
if lra.Ctx.Request.Method == http.MethodPost ||
|
||||
lra.Ctx.Request.Method == http.MethodDelete {
|
||||
if lra.SecurityCtx.HasWritePerm(project) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if lra.Ctx.Request.Method == http.MethodGet {
|
||||
if lra.SecurityCtx.HasReadPerm(project) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (lra *LabelResourceAPI) getLabelsOfResource(rType string, rIDOrName interface{}) {
|
||||
labels, err := lra.labelManager.GetLabelsOfResource(rType, rIDOrName)
|
||||
if err != nil {
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/promgr/metamgr"
|
||||
)
|
||||
@ -72,24 +73,6 @@ func (m *MetadataAPI) Prepare() {
|
||||
|
||||
m.project = project
|
||||
|
||||
switch m.Ctx.Request.Method {
|
||||
case http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete:
|
||||
if !(m.Ctx.Request.Method == http.MethodGet && project.IsPublic()) {
|
||||
if !m.SecurityCtx.IsAuthenticated() {
|
||||
m.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
if !m.SecurityCtx.HasReadPerm(project.ProjectID) {
|
||||
m.HandleForbidden(m.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Debugf("%s method not allowed", m.Ctx.Request.Method)
|
||||
m.RenderError(http.StatusMethodNotAllowed, "")
|
||||
return
|
||||
}
|
||||
|
||||
name := m.GetStringFromPath(":name")
|
||||
if len(name) > 0 {
|
||||
m.name = name
|
||||
@ -105,8 +88,27 @@ func (m *MetadataAPI) Prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MetadataAPI) requireAccess(action rbac.Action) bool {
|
||||
resource := rbac.NewProjectNamespace(m.project.ProjectID).Resource(rbac.ResourceMetadata)
|
||||
|
||||
if !m.SecurityCtx.Can(action, resource) {
|
||||
if !m.SecurityCtx.IsAuthenticated() {
|
||||
m.HandleUnauthorized()
|
||||
} else {
|
||||
m.HandleForbidden(m.SecurityCtx.GetUsername())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (m *MetadataAPI) Get() {
|
||||
if !m.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
var metas map[string]string
|
||||
var err error
|
||||
if len(m.name) > 0 {
|
||||
@ -125,6 +127,10 @@ func (m *MetadataAPI) Get() {
|
||||
|
||||
// Post ...
|
||||
func (m *MetadataAPI) Post() {
|
||||
if !m.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
var metas map[string]string
|
||||
m.DecodeJSONReq(&metas)
|
||||
|
||||
@ -161,6 +167,10 @@ func (m *MetadataAPI) Post() {
|
||||
|
||||
// Put ...
|
||||
func (m *MetadataAPI) Put() {
|
||||
if !m.requireAccess(rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
var metas map[string]string
|
||||
m.DecodeJSONReq(&metas)
|
||||
|
||||
@ -188,6 +198,10 @@ func (m *MetadataAPI) Put() {
|
||||
|
||||
// Delete ...
|
||||
func (m *MetadataAPI) Delete() {
|
||||
if !m.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.metaMgr.Delete(m.project.ProjectID, m.name); err != nil {
|
||||
m.HandleInternalServerError(fmt.Sprintf("failed to delete metadata %s of project %d: %v", m.name, m.project.ProjectID, err))
|
||||
return
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
errutil "github.com/goharbor/harbor/src/common/utils/error"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
@ -77,6 +78,25 @@ func (p *ProjectAPI) Prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ProjectAPI) requireAccess(action rbac.Action, subresource ...rbac.Resource) bool {
|
||||
if len(subresource) == 0 {
|
||||
subresource = append(subresource, rbac.ResourceSelf)
|
||||
}
|
||||
resource := rbac.NewProjectNamespace(p.project.ProjectID).Resource(subresource...)
|
||||
|
||||
if !p.SecurityCtx.Can(action, resource) {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
} else {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (p *ProjectAPI) Post() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
@ -187,16 +207,8 @@ func (p *ProjectAPI) Head() {
|
||||
|
||||
// Get ...
|
||||
func (p *ProjectAPI) Get() {
|
||||
if !p.project.IsPublic() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
if !p.SecurityCtx.HasReadPerm(p.project.ProjectID) {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
if !p.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
p.populateProperties(p.project)
|
||||
@ -207,13 +219,7 @@ func (p *ProjectAPI) Get() {
|
||||
|
||||
// Delete ...
|
||||
func (p *ProjectAPI) Delete() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
if !p.SecurityCtx.HasAllPerm(p.project.ProjectID) {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
if !p.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -248,13 +254,7 @@ func (p *ProjectAPI) Delete() {
|
||||
|
||||
// Deletable ...
|
||||
func (p *ProjectAPI) Deletable() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
if !p.SecurityCtx.HasAllPerm(p.project.ProjectID) {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
if !p.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -433,13 +433,7 @@ func (p *ProjectAPI) populateProperties(project *models.Project) {
|
||||
|
||||
// Put ...
|
||||
func (p *ProjectAPI) Put() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
if !p.SecurityCtx.HasAllPerm(p.project.ProjectID) {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
if !p.requireAccess(rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -458,13 +452,7 @@ func (p *ProjectAPI) Put() {
|
||||
|
||||
// Logs ...
|
||||
func (p *ProjectAPI) Logs() {
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
if !p.SecurityCtx.HasReadPerm(p.project.ProjectID) {
|
||||
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||
if !p.requireAccess(rbac.ActionList, rbac.ResourceLog) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
)
|
||||
@ -73,12 +74,6 @@ func (pma *ProjectMemberAPI) Prepare() {
|
||||
}
|
||||
pma.project = project
|
||||
|
||||
if !(pma.Ctx.Input.IsGet() && pma.SecurityCtx.HasReadPerm(pid) ||
|
||||
pma.SecurityCtx.HasAllPerm(pid)) {
|
||||
pma.HandleForbidden(pma.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
|
||||
pmid, err := pma.GetInt64FromPath(":pmid")
|
||||
if err != nil {
|
||||
log.Warningf("Failed to get pmid from path, error %v", err)
|
||||
@ -90,6 +85,22 @@ func (pma *ProjectMemberAPI) Prepare() {
|
||||
pma.id = int(pmid)
|
||||
}
|
||||
|
||||
func (pma *ProjectMemberAPI) requireAccess(action rbac.Action) bool {
|
||||
resource := rbac.NewProjectNamespace(pma.project.ProjectID).Resource(rbac.ResourceMember)
|
||||
|
||||
if !pma.SecurityCtx.Can(action, resource) {
|
||||
if !pma.SecurityCtx.IsAuthenticated() {
|
||||
pma.HandleUnauthorized()
|
||||
} else {
|
||||
pma.HandleForbidden(pma.SecurityCtx.GetUsername())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (pma *ProjectMemberAPI) Get() {
|
||||
projectID := pma.project.ProjectID
|
||||
@ -97,6 +108,9 @@ func (pma *ProjectMemberAPI) Get() {
|
||||
queryMember.ProjectID = projectID
|
||||
pma.Data["json"] = make([]models.Member, 0)
|
||||
if pma.id == 0 {
|
||||
if !pma.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
entityname := pma.GetString("entityname")
|
||||
memberList, err := project.SearchMemberByName(projectID, entityname)
|
||||
if err != nil {
|
||||
@ -119,6 +133,10 @@ func (pma *ProjectMemberAPI) Get() {
|
||||
pma.HandleNotFound(fmt.Sprintf("The project member does not exit, pmid:%v", pma.id))
|
||||
return
|
||||
}
|
||||
|
||||
if !pma.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
pma.Data["json"] = memberList[0]
|
||||
}
|
||||
pma.ServeJSON()
|
||||
@ -126,6 +144,9 @@ func (pma *ProjectMemberAPI) Get() {
|
||||
|
||||
// Post ... Add a project member
|
||||
func (pma *ProjectMemberAPI) Post() {
|
||||
if !pma.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
projectID := pma.project.ProjectID
|
||||
var request models.MemberReq
|
||||
pma.DecodeJSONReq(&request)
|
||||
@ -156,6 +177,9 @@ func (pma *ProjectMemberAPI) Post() {
|
||||
|
||||
// Put ... Update an exist project member
|
||||
func (pma *ProjectMemberAPI) Put() {
|
||||
if !pma.requireAccess(rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
pid := pma.project.ProjectID
|
||||
pmID := pma.id
|
||||
var req models.Member
|
||||
@ -173,6 +197,9 @@ func (pma *ProjectMemberAPI) Put() {
|
||||
|
||||
// Delete ...
|
||||
func (pma *ProjectMemberAPI) Delete() {
|
||||
if !pma.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
pmid := pma.id
|
||||
err := project.DeleteProjectMemberByID(pmid)
|
||||
if err != nil {
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
common_http "github.com/goharbor/harbor/src/common/http"
|
||||
common_job "github.com/goharbor/harbor/src/common/job"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
api_models "github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/core/utils"
|
||||
@ -80,7 +81,8 @@ func (ra *RepJobAPI) List() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasAllPerm(policy.ProjectIDs[0]) {
|
||||
resource := rbac.NewProjectNamespace(policy.ProjectIDs[0]).Resource(rbac.ResourceReplicationJob)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionList, resource) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
@ -190,7 +192,8 @@ func (ra *RepJobAPI) GetLog() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasAllPerm(policy.ProjectIDs[0]) {
|
||||
resource := rbac.NewProjectNamespace(policy.ProjectIDs[0]).Resource(rbac.ResourceReplicationJob)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
api_models "github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/core/promgr"
|
||||
@ -63,7 +64,8 @@ func (pa *RepPolicyAPI) Get() {
|
||||
return
|
||||
}
|
||||
|
||||
if !pa.SecurityCtx.HasAllPerm(policy.ProjectIDs[0]) {
|
||||
resource := rbac.NewProjectNamespace(policy.ProjectIDs[0]).Resource(rbac.ResourceReplication)
|
||||
if !pa.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
pa.HandleForbidden(pa.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
@ -105,7 +107,8 @@ func (pa *RepPolicyAPI) List() {
|
||||
if result != nil {
|
||||
total = result.Total
|
||||
for _, policy := range result.Policies {
|
||||
if !pa.SecurityCtx.HasAllPerm(policy.ProjectIDs[0]) {
|
||||
resource := rbac.NewProjectNamespace(policy.ProjectIDs[0]).Resource(rbac.ResourceReplication)
|
||||
if !pa.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
continue
|
||||
}
|
||||
ply, err := convertFromRepPolicy(pa.ProjectMgr, *policy)
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/common/utils/clair"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
@ -131,7 +132,8 @@ func (ra *RepositoryAPI) Get() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasReadPerm(projectID) {
|
||||
resource := rbac.NewProjectNamespace(projectID).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionList, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
@ -247,7 +249,8 @@ func (ra *RepositoryAPI) Delete() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasAllPerm(projectName) {
|
||||
resource := rbac.NewProjectNamespace(project.ProjectID).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionDelete, resource) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
@ -393,7 +396,8 @@ func (ra *RepositoryAPI) GetTag() {
|
||||
return
|
||||
}
|
||||
project, _ := utils.ParseRepository(repository)
|
||||
if !ra.SecurityCtx.HasReadPerm(project) {
|
||||
resource := rbac.NewProjectNamespace(project).Resource(rbac.ResourceRepositoryTag)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
@ -488,14 +492,16 @@ func (ra *RepositoryAPI) Retag() {
|
||||
}
|
||||
|
||||
// Check whether user has read permission to source project
|
||||
if !ra.SecurityCtx.HasReadPerm(srcImage.Project) {
|
||||
srcResource := rbac.NewProjectNamespace(srcImage.Project).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionPull, srcResource) {
|
||||
log.Errorf("user has no read permission to project '%s'", srcImage.Project)
|
||||
ra.HandleForbidden(fmt.Sprintf("%s has no read permission to project %s", ra.SecurityCtx.GetUsername(), srcImage.Project))
|
||||
return
|
||||
}
|
||||
|
||||
// Check whether user has write permission to target project
|
||||
if !ra.SecurityCtx.HasWritePerm(project) {
|
||||
destResource := rbac.NewProjectNamespace(project).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionPush, destResource) {
|
||||
log.Errorf("user has no write permission to project '%s'", project)
|
||||
ra.HandleForbidden(fmt.Sprintf("%s has no write permission to project %s", ra.SecurityCtx.GetUsername(), project))
|
||||
return
|
||||
@ -533,7 +539,8 @@ func (ra *RepositoryAPI) GetTags() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasReadPerm(projectName) {
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepositoryTag)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionList, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
@ -741,7 +748,8 @@ func (ra *RepositoryAPI) GetManifests() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasReadPerm(projectName) {
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepositoryTagManifest)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
@ -872,7 +880,8 @@ func (ra *RepositoryAPI) Put() {
|
||||
}
|
||||
|
||||
project, _ := utils.ParseRepository(name)
|
||||
if !ra.SecurityCtx.HasWritePerm(project) {
|
||||
resource := rbac.NewProjectNamespace(project).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionUpdate, resource) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
@ -906,7 +915,8 @@ func (ra *RepositoryAPI) GetSignatures() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ra.SecurityCtx.HasReadPerm(projectName) {
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepository)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
@ -949,7 +959,9 @@ func (ra *RepositoryAPI) ScanImage() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
if !ra.SecurityCtx.HasAllPerm(projectName) {
|
||||
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepositoryTagScanJob)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionCreate, resource) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
@ -980,7 +992,9 @@ func (ra *RepositoryAPI) VulnerabilityDetails() {
|
||||
return
|
||||
}
|
||||
project, _ := utils.ParseRepository(repository)
|
||||
if !ra.SecurityCtx.HasReadPerm(project) {
|
||||
|
||||
resource := rbac.NewProjectNamespace(project).Resource(rbac.ResourceRepositoryTagVulnerability)
|
||||
if !ra.SecurityCtx.Can(rbac.ActionList, resource) {
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
coreutils "github.com/goharbor/harbor/src/core/utils"
|
||||
)
|
||||
|
||||
@ -45,12 +45,6 @@ func (r *RepositoryLabelAPI) Prepare() {
|
||||
}
|
||||
|
||||
repository := r.GetString(":splat")
|
||||
project, _ := utils.ParseRepository(repository)
|
||||
if !r.checkPermissions(project) {
|
||||
r.SendForbiddenError(errors.New(r.SecurityCtx.GetUsername()))
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := dao.GetRepositoryByName(repository)
|
||||
if err != nil {
|
||||
r.SendInternalServerError(fmt.Errorf("failed to get repository %s: %v", repository, err))
|
||||
@ -77,25 +71,6 @@ func (r *RepositoryLabelAPI) Prepare() {
|
||||
r.tag = tag
|
||||
}
|
||||
|
||||
if r.Ctx.Request.Method == http.MethodPost {
|
||||
p, err := r.ProjectMgr.Get(project)
|
||||
if err != nil {
|
||||
r.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
l := &models.Label{}
|
||||
r.DecodeJSONReq(l)
|
||||
|
||||
label, ok := r.validate(l.ID, p.ProjectID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
r.label = label
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if r.Ctx.Request.Method == http.MethodDelete {
|
||||
labelID, err := r.GetInt64FromPath(":id")
|
||||
if err != nil {
|
||||
@ -112,13 +87,59 @@ func (r *RepositoryLabelAPI) Prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RepositoryLabelAPI) requireAccess(action rbac.Action, subresource ...rbac.Resource) bool {
|
||||
if len(subresource) == 0 {
|
||||
subresource = append(subresource, rbac.ResourceRepositoryLabel)
|
||||
}
|
||||
resource := rbac.NewProjectNamespace(r.repository.ProjectID).Resource(rbac.ResourceRepositoryLabel)
|
||||
|
||||
if !r.SecurityCtx.Can(action, resource) {
|
||||
if !r.SecurityCtx.IsAuthenticated() {
|
||||
r.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
||||
} else {
|
||||
r.SendForbiddenError(errors.New(r.SecurityCtx.GetUsername()))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *RepositoryLabelAPI) isValidLabelReq() bool {
|
||||
p, err := r.ProjectMgr.Get(r.repository.ProjectID)
|
||||
if err != nil {
|
||||
r.SendInternalServerError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
l := &models.Label{}
|
||||
r.DecodeJSONReq(l)
|
||||
|
||||
label, ok := r.validate(l.ID, p.ProjectID)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
r.label = label
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetOfImage returns labels of an image
|
||||
func (r *RepositoryLabelAPI) GetOfImage() {
|
||||
if !r.requireAccess(rbac.ActionList, rbac.ResourceRepositoryTagLabel) {
|
||||
return
|
||||
}
|
||||
|
||||
r.getLabelsOfResource(common.ResourceTypeImage, fmt.Sprintf("%s:%s", r.repository.Name, r.tag))
|
||||
}
|
||||
|
||||
// AddToImage adds the label to an image
|
||||
func (r *RepositoryLabelAPI) AddToImage() {
|
||||
if !r.requireAccess(rbac.ActionCreate, rbac.ResourceRepositoryTagLabel) || !r.isValidLabelReq() {
|
||||
return
|
||||
}
|
||||
|
||||
rl := &models.ResourceLabel{
|
||||
LabelID: r.label.ID,
|
||||
ResourceType: common.ResourceTypeImage,
|
||||
@ -129,17 +150,29 @@ func (r *RepositoryLabelAPI) AddToImage() {
|
||||
|
||||
// RemoveFromImage removes the label from an image
|
||||
func (r *RepositoryLabelAPI) RemoveFromImage() {
|
||||
if !r.requireAccess(rbac.ActionDelete, rbac.ResourceRepositoryTagLabel) {
|
||||
return
|
||||
}
|
||||
|
||||
r.removeLabelFromResource(common.ResourceTypeImage,
|
||||
fmt.Sprintf("%s:%s", r.repository.Name, r.tag), r.label.ID)
|
||||
}
|
||||
|
||||
// GetOfRepository returns labels of a repository
|
||||
func (r *RepositoryLabelAPI) GetOfRepository() {
|
||||
if !r.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
|
||||
r.getLabelsOfResource(common.ResourceTypeRepository, r.repository.RepositoryID)
|
||||
}
|
||||
|
||||
// AddToRepository adds the label to a repository
|
||||
func (r *RepositoryLabelAPI) AddToRepository() {
|
||||
if !r.requireAccess(rbac.ActionCreate) || !r.isValidLabelReq() {
|
||||
return
|
||||
}
|
||||
|
||||
rl := &models.ResourceLabel{
|
||||
LabelID: r.label.ID,
|
||||
ResourceType: common.ResourceTypeRepository,
|
||||
@ -150,6 +183,10 @@ func (r *RepositoryLabelAPI) AddToRepository() {
|
||||
|
||||
// RemoveFromRepository removes the label from a repository
|
||||
func (r *RepositoryLabelAPI) RemoveFromRepository() {
|
||||
if !r.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
r.removeLabelFromResource(common.ResourceTypeRepository, r.repository.RepositoryID, r.label.ID)
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,14 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/token"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// RobotAPI ...
|
||||
@ -83,17 +85,24 @@ func (r *RobotAPI) Prepare() {
|
||||
|
||||
r.robot = robot
|
||||
}
|
||||
}
|
||||
|
||||
if !(r.Ctx.Input.IsGet() && r.SecurityCtx.HasReadPerm(pid) ||
|
||||
r.SecurityCtx.HasAllPerm(pid)) {
|
||||
func (r *RobotAPI) requireAccess(action rbac.Action) bool {
|
||||
resource := rbac.NewProjectNamespace(r.project.ProjectID).Resource(rbac.ResourceRobot)
|
||||
if !r.SecurityCtx.Can(action, resource) {
|
||||
r.HandleForbidden(r.SecurityCtx.GetUsername())
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (r *RobotAPI) Post() {
|
||||
if !r.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
var robotReq models.RobotReq
|
||||
r.DecodeJSONReq(&robotReq)
|
||||
createdName := common.RobotPrefix + robotReq.Name
|
||||
@ -147,6 +156,10 @@ func (r *RobotAPI) Post() {
|
||||
|
||||
// List list all the robots of a project
|
||||
func (r *RobotAPI) List() {
|
||||
if !r.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
|
||||
query := models.RobotQuery{
|
||||
ProjectID: r.project.ProjectID,
|
||||
}
|
||||
@ -171,6 +184,10 @@ func (r *RobotAPI) List() {
|
||||
|
||||
// Get get robot by id
|
||||
func (r *RobotAPI) Get() {
|
||||
if !r.requireAccess(rbac.ActionRead) {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := r.GetInt64FromPath(":id")
|
||||
if err != nil || id <= 0 {
|
||||
r.HandleBadRequest(fmt.Sprintf("invalid robot ID: %s", r.GetStringFromPath(":id")))
|
||||
@ -193,6 +210,10 @@ func (r *RobotAPI) Get() {
|
||||
|
||||
// Put disable or enable a robot account
|
||||
func (r *RobotAPI) Put() {
|
||||
if !r.requireAccess(rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
var robotReq models.RobotReq
|
||||
r.DecodeJSONReqAndValidate(&robotReq)
|
||||
r.robot.Disabled = robotReq.Disabled
|
||||
@ -206,6 +227,10 @@ func (r *RobotAPI) Put() {
|
||||
|
||||
// Delete delete robot by id
|
||||
func (r *RobotAPI) Delete() {
|
||||
if !r.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := dao.DeleteRobot(r.robot.ID); err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to delete robot %d: %v", r.robot.ID, err))
|
||||
return
|
||||
|
@ -17,6 +17,7 @@ package api
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
common_http "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/utils"
|
||||
|
||||
@ -54,7 +55,9 @@ func (sj *ScanJobAPI) Prepare() {
|
||||
sj.CustomAbort(http.StatusInternalServerError, "Failed to get Job data")
|
||||
}
|
||||
projectName := strings.SplitN(data.Repository, "/", 2)[0]
|
||||
if !sj.SecurityCtx.HasReadPerm(projectName) {
|
||||
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepositoryTagScanJob)
|
||||
if !sj.SecurityCtx.Can(rbac.ActionRead, resource) {
|
||||
log.Errorf("User does not have read permission for project: %s", projectName)
|
||||
sj.HandleForbidden(sj.SecurityCtx.GetUsername())
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/docker/distribution/registry/auth/token"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
@ -158,24 +159,25 @@ func (rep repositoryFilter) filter(ctx security.Context, pm promgr.ProjectManage
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project := img.namespace
|
||||
projectName := img.namespace
|
||||
permission := ""
|
||||
|
||||
exist, err := pm.Exists(project)
|
||||
exist, err := pm.Exists(projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
log.Debugf("project %s does not exist, set empty permission", project)
|
||||
log.Debugf("project %s does not exist, set empty permission", projectName)
|
||||
a.Actions = []string{}
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.HasAllPerm(project) {
|
||||
resource := rbac.NewProjectNamespace(projectName).Resource(rbac.ResourceRepository)
|
||||
if ctx.Can(rbac.ActionPush, resource) && ctx.Can(rbac.ActionPull, resource) {
|
||||
permission = "RWM"
|
||||
} else if ctx.HasWritePerm(project) {
|
||||
} else if ctx.Can(rbac.ActionPush, resource) {
|
||||
permission = "RW"
|
||||
} else if ctx.HasReadPerm(project) {
|
||||
} else if ctx.Can(rbac.ActionPull, resource) {
|
||||
permission = "R"
|
||||
}
|
||||
|
||||
|
@ -252,15 +252,6 @@ func (f *fakeSecurityContext) IsSysAdmin() bool {
|
||||
func (f *fakeSecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
func (f *fakeSecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
return false
|
||||
}
|
||||
func (f *fakeSecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
return false
|
||||
}
|
||||
func (f *fakeSecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
return false
|
||||
}
|
||||
func (f *fakeSecurityContext) Can(action rbac.Action, resource rbac.Resource) bool {
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user