mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
Implement api for get current user permissions
Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
parent
6888c3247c
commit
8b5e68073d
@ -717,6 +717,37 @@ paths:
|
||||
$ref: '#/definitions/User'
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
/users/current/permissions:
|
||||
get:
|
||||
summary: Get current user permissions.
|
||||
description: |
|
||||
This endpoint is to get the current user permissions.
|
||||
parameters:
|
||||
- name: scope
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
description: Get permissions of the scope
|
||||
- name: relative
|
||||
in: query
|
||||
type: boolean
|
||||
required: false
|
||||
description: |
|
||||
If true, the resources in the response are relative to the scope,
|
||||
eg for resource '/project/1/repository' if relative is 'true' then the resource in response will be 'repository'.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Get current user permission successfully.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Permission'
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'500':
|
||||
description: Internal errors.
|
||||
'/users/{user_id}':
|
||||
get:
|
||||
summary: Get a user's profile.
|
||||
@ -4550,3 +4581,13 @@ definitions:
|
||||
error:
|
||||
type: string
|
||||
description: (optional) The error message when the status is "unhealthy"
|
||||
Permission:
|
||||
type: object
|
||||
description: The permission
|
||||
properties:
|
||||
resource:
|
||||
type: string
|
||||
description: The permission resoruce
|
||||
action:
|
||||
type: string
|
||||
description: The permission action
|
@ -20,14 +20,42 @@ import (
|
||||
|
||||
// const action variables
|
||||
const (
|
||||
ActionAll = rbac.Action("*")
|
||||
ActionPull = rbac.Action("pull")
|
||||
ActionPush = rbac.Action("push")
|
||||
ActionPushPull = rbac.Action("push+pull")
|
||||
ActionAll = rbac.Action("*") // action match any other actions
|
||||
|
||||
ActionPull = rbac.Action("pull") // pull repository tag
|
||||
ActionPush = rbac.Action("push") // push repository tag
|
||||
ActionPushPull = rbac.Action("push+pull") // compatible with security all perm of project
|
||||
|
||||
// create, read, update, delete, list actions compatible with restful api methods
|
||||
ActionCreate = rbac.Action("create")
|
||||
ActionRead = rbac.Action("read")
|
||||
ActionUpdate = rbac.Action("update")
|
||||
ActionDelete = rbac.Action("delete")
|
||||
ActionList = rbac.Action("list")
|
||||
|
||||
// execute replication for the replication policy (replication rule)
|
||||
ActionExecute = rbac.Action("execute")
|
||||
|
||||
// vulnerabilities scan for repository tag (aka, image tag)
|
||||
ActionScan = rbac.Action("scan")
|
||||
)
|
||||
|
||||
// const resource variables
|
||||
const (
|
||||
ResourceAll = rbac.Resource("*")
|
||||
ResourceImage = rbac.Resource("image")
|
||||
ResourceAll = rbac.Resource("*") // resource match any other resources
|
||||
ResourceSelf = rbac.Resource("") // subresource for project self
|
||||
ResourceMember = rbac.Resource("member")
|
||||
ResourceLog = rbac.Resource("log")
|
||||
ResourceReplication = rbac.Resource("replication")
|
||||
ResourceLabel = rbac.Resource("label")
|
||||
ResourceRepository = rbac.Resource("repository")
|
||||
ResourceRepositoryTag = rbac.Resource("repository-tag")
|
||||
ResourceRepositoryTagManifest = rbac.Resource("repository-tag-manifest")
|
||||
ResourceRepositoryTagVulnerability = rbac.Resource("repository-tag-vulnerability")
|
||||
ResourceRepositoryTagLabel = rbac.Resource("repository-tag-label")
|
||||
ResourceHelmChart = rbac.Resource("helm-chart")
|
||||
ResourceHelmChartVersion = rbac.Resource("helm-chart-version")
|
||||
ResourceHelmChartVersionLabel = rbac.Resource("helm-chart-version-label")
|
||||
ResourceConfiguration = rbac.Resource("configuration") // compatible for portal only
|
||||
ResourceRobot = rbac.Resource("robot")
|
||||
)
|
||||
|
@ -21,12 +21,81 @@ import (
|
||||
var (
|
||||
// subresource policies for public project
|
||||
publicProjectPolicies = []*rbac.Policy{
|
||||
{Resource: ResourceImage, Action: ActionPull},
|
||||
{Resource: ResourceSelf, 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},
|
||||
}
|
||||
|
||||
// subresource policies for system admin visitor
|
||||
systemAdminProjectPolicies = []*rbac.Policy{
|
||||
{Resource: ResourceAll, Action: ActionAll},
|
||||
// all policies for the projects
|
||||
allPolicies = []*rbac.Policy{
|
||||
{Resource: ResourceSelf, Action: ActionRead},
|
||||
{Resource: ResourceSelf, Action: ActionUpdate},
|
||||
{Resource: ResourceSelf, Action: ActionDelete},
|
||||
|
||||
{Resource: ResourceMember, Action: ActionCreate},
|
||||
{Resource: ResourceMember, Action: ActionUpdate},
|
||||
{Resource: ResourceMember, Action: ActionDelete},
|
||||
{Resource: ResourceMember, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLog, Action: ActionList},
|
||||
|
||||
{Resource: ResourceReplication, Action: ActionList},
|
||||
{Resource: ResourceReplication, Action: ActionCreate},
|
||||
{Resource: ResourceReplication, Action: ActionUpdate},
|
||||
{Resource: ResourceReplication, Action: ActionDelete},
|
||||
{Resource: ResourceReplication, Action: ActionExecute},
|
||||
|
||||
{Resource: ResourceLabel, Action: ActionCreate},
|
||||
{Resource: ResourceLabel, Action: ActionUpdate},
|
||||
{Resource: ResourceLabel, Action: ActionDelete},
|
||||
{Resource: ResourceLabel, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepository, Action: ActionCreate},
|
||||
{Resource: ResourceRepository, Action: ActionUpdate},
|
||||
{Resource: ResourceRepository, Action: ActionDelete},
|
||||
{Resource: ResourceRepository, Action: ActionList},
|
||||
{Resource: ResourceRepository, Action: ActionPushPull}, // compatible with security all perm of project
|
||||
{Resource: ResourceRepository, Action: ActionPush},
|
||||
{Resource: ResourceRepository, Action: ActionPull},
|
||||
|
||||
{Resource: ResourceRepositoryTag, Action: ActionDelete},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionList},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionScan},
|
||||
|
||||
{Resource: ResourceRepositoryTagVulnerability, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagManifest, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionCreate},
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionDelete},
|
||||
|
||||
{Resource: ResourceHelmChart, Action: ActionCreate},
|
||||
{Resource: ResourceHelmChart, Action: ActionRead},
|
||||
{Resource: ResourceHelmChart, Action: ActionDelete},
|
||||
{Resource: ResourceHelmChart, Action: ActionList},
|
||||
|
||||
{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: ResourceConfiguration, Action: ActionUpdate},
|
||||
|
||||
{Resource: ResourceRobot, Action: ActionCreate},
|
||||
{Resource: ResourceRobot, Action: ActionRead},
|
||||
{Resource: ResourceRobot, Action: ActionUpdate},
|
||||
{Resource: ResourceRobot, Action: ActionDelete},
|
||||
{Resource: ResourceRobot, Action: ActionList},
|
||||
}
|
||||
)
|
||||
|
||||
@ -44,10 +113,11 @@ func policiesForPublicProject(namespace rbac.Namespace) []*rbac.Policy {
|
||||
return policies
|
||||
}
|
||||
|
||||
func policiesForSystemAdmin(namespace rbac.Namespace) []*rbac.Policy {
|
||||
// GetAllPolicies returns all policies for namespace of the project
|
||||
func GetAllPolicies(namespace rbac.Namespace) []*rbac.Policy {
|
||||
policies := []*rbac.Policy{}
|
||||
|
||||
for _, policy := range systemAdminProjectPolicies {
|
||||
for _, policy := range allPolicies {
|
||||
policies = append(policies, &rbac.Policy{
|
||||
Resource: namespace.Resource(policy.Resource),
|
||||
Action: policy.Action,
|
||||
|
@ -47,7 +47,7 @@ func (v *visitor) GetUserName() string {
|
||||
// GetPolicies returns policies of the visitor
|
||||
func (v *visitor) GetPolicies() []*rbac.Policy {
|
||||
if v.ctx.IsSysAdmin() {
|
||||
return policiesForSystemAdmin(v.namespace)
|
||||
return GetAllPolicies(v.namespace)
|
||||
}
|
||||
|
||||
if v.namespace.IsPublic() {
|
||||
@ -59,7 +59,8 @@ func (v *visitor) GetPolicies() []*rbac.Policy {
|
||||
|
||||
// GetRoles returns roles of the visitor
|
||||
func (v *visitor) GetRoles() []rbac.Role {
|
||||
if !v.ctx.IsAuthenticated() {
|
||||
// Ignore roles when visitor is anonymous or system admin
|
||||
if !v.ctx.IsAuthenticated() || v.ctx.IsSysAdmin() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -22,18 +22,175 @@ import (
|
||||
var (
|
||||
rolePoliciesMap = map[string][]*rbac.Policy{
|
||||
"projectAdmin": {
|
||||
{Resource: ResourceImage, Action: ActionPushPull}, // compatible with security all perm of project
|
||||
{Resource: ResourceImage, Action: ActionPush},
|
||||
{Resource: ResourceImage, Action: ActionPull},
|
||||
{Resource: ResourceSelf, Action: ActionRead},
|
||||
{Resource: ResourceSelf, Action: ActionUpdate},
|
||||
{Resource: ResourceSelf, Action: ActionDelete},
|
||||
|
||||
{Resource: ResourceMember, Action: ActionCreate},
|
||||
{Resource: ResourceMember, Action: ActionUpdate},
|
||||
{Resource: ResourceMember, Action: ActionDelete},
|
||||
{Resource: ResourceMember, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLog, Action: ActionList},
|
||||
|
||||
{Resource: ResourceReplication, Action: ActionRead},
|
||||
{Resource: ResourceReplication, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLabel, Action: ActionCreate},
|
||||
{Resource: ResourceLabel, Action: ActionUpdate},
|
||||
{Resource: ResourceLabel, Action: ActionDelete},
|
||||
{Resource: ResourceLabel, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepository, Action: ActionCreate},
|
||||
{Resource: ResourceRepository, Action: ActionUpdate},
|
||||
{Resource: ResourceRepository, Action: ActionDelete},
|
||||
{Resource: ResourceRepository, Action: ActionList},
|
||||
{Resource: ResourceRepository, Action: ActionPushPull}, // compatible with security all perm of project
|
||||
{Resource: ResourceRepository, Action: ActionPush},
|
||||
{Resource: ResourceRepository, Action: ActionPull},
|
||||
|
||||
{Resource: ResourceRepositoryTag, Action: ActionDelete},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionList},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionScan},
|
||||
|
||||
{Resource: ResourceRepositoryTagVulnerability, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagManifest, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionCreate},
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionDelete},
|
||||
|
||||
{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},
|
||||
},
|
||||
|
||||
"master": {
|
||||
{Resource: ResourceSelf, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceMember, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLog, Action: ActionList},
|
||||
|
||||
{Resource: ResourceReplication, Action: ActionRead},
|
||||
{Resource: ResourceReplication, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLabel, Action: ActionCreate},
|
||||
{Resource: ResourceLabel, Action: ActionUpdate},
|
||||
{Resource: ResourceLabel, Action: ActionDelete},
|
||||
{Resource: ResourceLabel, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepository, Action: ActionCreate},
|
||||
{Resource: ResourceRepository, Action: ActionUpdate},
|
||||
{Resource: ResourceRepository, Action: ActionDelete},
|
||||
{Resource: ResourceRepository, Action: ActionList},
|
||||
{Resource: ResourceRepository, Action: ActionPush},
|
||||
{Resource: ResourceRepository, Action: ActionPull},
|
||||
|
||||
{Resource: ResourceRepositoryTag, Action: ActionDelete},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionList},
|
||||
{Resource: ResourceRepositoryTag, Action: ActionScan},
|
||||
|
||||
{Resource: ResourceRepositoryTagVulnerability, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagManifest, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionCreate},
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionDelete},
|
||||
|
||||
{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: ResourceConfiguration, Action: ActionUpdate},
|
||||
},
|
||||
|
||||
"developer": {
|
||||
{Resource: ResourceImage, Action: ActionPush},
|
||||
{Resource: ResourceImage, Action: ActionPull},
|
||||
{Resource: ResourceSelf, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceMember, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLog, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepository, Action: ActionCreate},
|
||||
{Resource: ResourceRepository, Action: ActionList},
|
||||
{Resource: ResourceRepository, Action: ActionPush},
|
||||
{Resource: ResourceRepository, Action: ActionPull},
|
||||
|
||||
{Resource: ResourceRepositoryTag, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagVulnerability, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagManifest, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionCreate},
|
||||
{Resource: ResourceRepositoryTagLabel, Action: ActionDelete},
|
||||
|
||||
{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},
|
||||
},
|
||||
|
||||
"guest": {
|
||||
{Resource: ResourceImage, Action: ActionPull},
|
||||
{Resource: ResourceSelf, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceMember, Action: ActionList},
|
||||
|
||||
{Resource: ResourceLog, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepository, Action: ActionList},
|
||||
{Resource: ResourceRepository, Action: ActionPull},
|
||||
|
||||
{Resource: ResourceRepositoryTag, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagVulnerability, Action: ActionList},
|
||||
|
||||
{Resource: ResourceRepositoryTagManifest, Action: ActionRead},
|
||||
|
||||
{Resource: ResourceHelmChart, Action: ActionRead},
|
||||
{Resource: ResourceHelmChart, Action: ActionList},
|
||||
|
||||
{Resource: ResourceHelmChartVersion, Action: ActionRead},
|
||||
{Resource: ResourceHelmChartVersion, Action: ActionList},
|
||||
|
||||
{Resource: ResourceConfiguration, Action: ActionRead},
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -49,6 +206,8 @@ func (role *visitorRole) GetRoleName() string {
|
||||
switch role.roleID {
|
||||
case common.RoleProjectAdmin:
|
||||
return "projectAdmin"
|
||||
case common.RoleMaster:
|
||||
return "master"
|
||||
case common.RoleDeveloper:
|
||||
return "developer"
|
||||
case common.RoleGuest:
|
||||
|
@ -66,10 +66,10 @@ func (suite *VisitorTestSuite) TestGetPolicies() {
|
||||
suite.Equal(authenticatedForPublicProject.GetPolicies(), policiesForPublicProject(publicNamespace))
|
||||
|
||||
systemAdmin := NewUser(sysAdminCtx, namespace)
|
||||
suite.Equal(systemAdmin.GetPolicies(), policiesForSystemAdmin(namespace))
|
||||
suite.Equal(systemAdmin.GetPolicies(), GetAllPolicies(namespace))
|
||||
|
||||
systemAdminForPublicProject := NewUser(sysAdminCtx, publicNamespace)
|
||||
suite.Equal(systemAdminForPublicProject.GetPolicies(), policiesForSystemAdmin(publicNamespace))
|
||||
suite.Equal(systemAdminForPublicProject.GetPolicies(), GetAllPolicies(publicNamespace))
|
||||
}
|
||||
|
||||
func (suite *VisitorTestSuite) TestGetRoles() {
|
||||
|
@ -15,8 +15,10 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -29,6 +31,27 @@ const (
|
||||
// Resource the type of resource
|
||||
type Resource string
|
||||
|
||||
// RelativeTo returns relative resource to other resource
|
||||
func (res Resource) RelativeTo(other Resource) (Resource, error) {
|
||||
prefix := other.String()
|
||||
str := res.String()
|
||||
|
||||
if !strings.HasPrefix(str, prefix) {
|
||||
return Resource(""), errors.New("value error")
|
||||
}
|
||||
|
||||
relative := strings.TrimPrefix(str, prefix)
|
||||
if strings.HasPrefix(relative, "/") {
|
||||
relative = relative[1:]
|
||||
}
|
||||
|
||||
if relative == "" {
|
||||
relative = "."
|
||||
}
|
||||
|
||||
return Resource(relative), nil
|
||||
}
|
||||
|
||||
func (res Resource) String() string {
|
||||
return string(res)
|
||||
}
|
||||
|
@ -390,3 +390,50 @@ func TestResource_GetNamespace(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResource_RelativeTo(t *testing.T) {
|
||||
type args struct {
|
||||
other Resource
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
res Resource
|
||||
args args
|
||||
want Resource
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "/project/1/image",
|
||||
res: Resource("/project/1/image"),
|
||||
args: args{other: Resource("/project/1")},
|
||||
want: Resource("image"),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "/project/1",
|
||||
res: Resource("/project/1"),
|
||||
args: args{other: Resource("/project/1")},
|
||||
want: Resource("."),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "/project/1",
|
||||
res: Resource("/project/1"),
|
||||
args: args{other: Resource("/system")},
|
||||
want: Resource(""),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.res.RelativeTo(tt.args.other)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Resource.RelativeTo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Resource.RelativeTo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -72,19 +72,19 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
// 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(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.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(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.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(project.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceRepository))
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
|
@ -70,19 +70,19 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
// 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(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.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(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.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(project.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceImage))
|
||||
return s.Can(project.ActionPushPull, rbac.NewProjectNamespace(projectIDOrName, isPublicProject).Resource(project.ResourceRepository))
|
||||
}
|
||||
|
||||
// Can returns whether the user can do action on resource
|
||||
|
@ -313,12 +313,12 @@ func (msc *mockSecurityContext) IsSolutionUser() bool {
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (msc *mockSecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
return msc.Can(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, false).Resource(project.ResourceImage))
|
||||
return msc.Can(project.ActionPull, rbac.NewProjectNamespace(projectIDOrName, false).Resource(project.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (msc *mockSecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
return msc.Can(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, false).Resource(project.ResourceImage))
|
||||
return msc.Can(project.ActionPush, rbac.NewProjectNamespace(projectIDOrName, false).Resource(project.ResourceRepository))
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/filter"
|
||||
"github.com/goharbor/harbor/tests/apitests/apilib"
|
||||
|
||||
// "strconv"
|
||||
// "strings"
|
||||
|
||||
@ -103,6 +104,7 @@ func init() {
|
||||
beego.Router("/api/users/:id", &UserAPI{}, "get:Get")
|
||||
beego.Router("/api/users", &UserAPI{}, "get:List;post:Post;delete:Delete;put:Put")
|
||||
beego.Router("/api/users/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword")
|
||||
beego.Router("/api/users/:id/permissions", &UserAPI{}, "get:ListUserPermissions")
|
||||
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
||||
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
||||
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
||||
@ -996,6 +998,23 @@ func (a testapi) UsersUpdatePassword(userID int, password apilib.Password, authI
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
func (a testapi) UsersGetPermissions(userID interface{}, scope string, authInfo usrInfo) (int, []apilib.Permission, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
// create path and map variables
|
||||
path := fmt.Sprintf("/api/users/%v/permissions", userID)
|
||||
_sling = _sling.Path(path)
|
||||
type QueryParams struct {
|
||||
Scope string `url:"scope,omitempty"`
|
||||
}
|
||||
_sling = _sling.QueryStruct(&QueryParams{Scope: scope})
|
||||
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
var successPayLoad []apilib.Permission
|
||||
if 200 == httpStatusCode && nil == err {
|
||||
err = json.Unmarshal(body, &successPayLoad)
|
||||
}
|
||||
return httpStatusCode, successPayLoad, err
|
||||
}
|
||||
|
||||
// Mark a registered user as be removed.
|
||||
func (a testapi) UsersDelete(userID int, authInfo usrInfo) (int, error) {
|
||||
_sling := sling.New().Delete(a.basePath)
|
||||
|
@ -24,6 +24,8 @@ 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/rbac/project"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
@ -339,6 +341,57 @@ func (ua *UserAPI) ToggleUserAdminRole() {
|
||||
}
|
||||
}
|
||||
|
||||
// ListUserPermissions handles GET to /api/users/{}/permissions
|
||||
func (ua *UserAPI) ListUserPermissions() {
|
||||
if ua.userID != ua.currentUserID {
|
||||
log.Warningf("Current user, id: %d can not view other user's permissions", ua.currentUserID)
|
||||
ua.RenderError(http.StatusForbidden, "User does not have permission")
|
||||
return
|
||||
}
|
||||
|
||||
relative := ua.Ctx.Input.Query("relative") == "true"
|
||||
|
||||
scope := rbac.Resource(ua.Ctx.Input.Query("scope"))
|
||||
policies := []*rbac.Policy{}
|
||||
|
||||
namespace, err := scope.GetNamespace()
|
||||
if err == nil {
|
||||
switch namespace.Kind() {
|
||||
case "project":
|
||||
for _, policy := range project.GetAllPolicies(namespace) {
|
||||
if ua.SecurityCtx.Can(policy.Action, policy.Resource) {
|
||||
policies = append(policies, policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results := []map[string]string{}
|
||||
for _, policy := range policies {
|
||||
var resource rbac.Resource
|
||||
|
||||
// for resource `/project/1/repository` if `relative` is `true` then the resource in response will be `repository`
|
||||
if relative {
|
||||
relativeResource, err := policy.Resource.RelativeTo(scope)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resource = relativeResource
|
||||
} else {
|
||||
resource = policy.Resource
|
||||
}
|
||||
|
||||
results = append(results, map[string]string{
|
||||
"resource": resource.String(),
|
||||
"action": policy.Action.String(),
|
||||
})
|
||||
}
|
||||
|
||||
ua.Data["json"] = results
|
||||
ua.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// modifiable returns whether the modify is allowed based on current auth mode and context
|
||||
func (ua *UserAPI) modifiable() bool {
|
||||
if ua.AuthMode == common.DBAuth {
|
||||
|
@ -572,3 +572,28 @@ func TestModifiable(t *testing.T) {
|
||||
}
|
||||
assert.True(ua4.modifiable())
|
||||
}
|
||||
|
||||
func TestUsersCurrentPermissions(t *testing.T) {
|
||||
fmt.Println("Testing Get Users Current Permissions")
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
httpStatusCode, permissions, err := apiTest.UsersGetPermissions("current", "/project/library", *projAdmin)
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
assert.NotEmpty(permissions, "permissions should not be empty")
|
||||
|
||||
httpStatusCode, permissions, err = apiTest.UsersGetPermissions("current", "/unsupport-scope", *projAdmin)
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
assert.Empty(permissions, "permissions should be empty")
|
||||
|
||||
httpStatusCode, _, err = apiTest.UsersGetPermissions(projAdminID, "/project/library", *projAdmin)
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
|
||||
httpStatusCode, _, err = apiTest.UsersGetPermissions(projDeveloperID, "/project/library", *projAdmin)
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(403), httpStatusCode, "httpStatusCode should be 403")
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ func initRouters() {
|
||||
beego.Router("/api/users/:id", &api.UserAPI{}, "get:Get;delete:Delete;put:Put")
|
||||
beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post")
|
||||
beego.Router("/api/users/:id([0-9]+)/password", &api.UserAPI{}, "put:ChangePassword")
|
||||
beego.Router("/api/users/:id/permissions", &api.UserAPI{}, "get:ListUserPermissions")
|
||||
beego.Router("/api/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")
|
||||
beego.Router("/api/usergroups/?:ugid([0-9]+)", &api.UserGroupAPI{})
|
||||
beego.Router("/api/ldap/ping", &api.LdapAPI{}, "post:Ping")
|
||||
|
@ -53,3 +53,9 @@ type User struct {
|
||||
|
||||
UpdateTime string `json:"update_time,omitempty"`
|
||||
}
|
||||
|
||||
// Permission the permission type
|
||||
type Permission struct {
|
||||
Resource string `json:"resource,omitempty"`
|
||||
Action string `json:"action,omitempty"`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user