mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 12:15:20 +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'
|
$ref: '#/definitions/User'
|
||||||
'401':
|
'401':
|
||||||
description: User need to log in first.
|
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}':
|
'/users/{user_id}':
|
||||||
get:
|
get:
|
||||||
summary: Get a user's profile.
|
summary: Get a user's profile.
|
||||||
@ -4550,3 +4581,13 @@ definitions:
|
|||||||
error:
|
error:
|
||||||
type: string
|
type: string
|
||||||
description: (optional) The error message when the status is "unhealthy"
|
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 action variables
|
||||||
const (
|
const (
|
||||||
ActionAll = rbac.Action("*")
|
ActionAll = rbac.Action("*") // action match any other actions
|
||||||
ActionPull = rbac.Action("pull")
|
|
||||||
ActionPush = rbac.Action("push")
|
ActionPull = rbac.Action("pull") // pull repository tag
|
||||||
ActionPushPull = rbac.Action("push+pull")
|
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 resource variables
|
||||||
const (
|
const (
|
||||||
ResourceAll = rbac.Resource("*")
|
ResourceAll = rbac.Resource("*") // resource match any other resources
|
||||||
ResourceImage = rbac.Resource("image")
|
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 (
|
var (
|
||||||
// subresource policies for public project
|
// subresource policies for public project
|
||||||
publicProjectPolicies = []*rbac.Policy{
|
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
|
// all policies for the projects
|
||||||
systemAdminProjectPolicies = []*rbac.Policy{
|
allPolicies = []*rbac.Policy{
|
||||||
{Resource: ResourceAll, Action: ActionAll},
|
{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
|
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{}
|
policies := []*rbac.Policy{}
|
||||||
|
|
||||||
for _, policy := range systemAdminProjectPolicies {
|
for _, policy := range allPolicies {
|
||||||
policies = append(policies, &rbac.Policy{
|
policies = append(policies, &rbac.Policy{
|
||||||
Resource: namespace.Resource(policy.Resource),
|
Resource: namespace.Resource(policy.Resource),
|
||||||
Action: policy.Action,
|
Action: policy.Action,
|
||||||
|
@ -47,7 +47,7 @@ func (v *visitor) GetUserName() string {
|
|||||||
// GetPolicies returns policies of the visitor
|
// GetPolicies returns policies of the visitor
|
||||||
func (v *visitor) GetPolicies() []*rbac.Policy {
|
func (v *visitor) GetPolicies() []*rbac.Policy {
|
||||||
if v.ctx.IsSysAdmin() {
|
if v.ctx.IsSysAdmin() {
|
||||||
return policiesForSystemAdmin(v.namespace)
|
return GetAllPolicies(v.namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.namespace.IsPublic() {
|
if v.namespace.IsPublic() {
|
||||||
@ -59,7 +59,8 @@ func (v *visitor) GetPolicies() []*rbac.Policy {
|
|||||||
|
|
||||||
// GetRoles returns roles of the visitor
|
// GetRoles returns roles of the visitor
|
||||||
func (v *visitor) GetRoles() []rbac.Role {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +22,175 @@ import (
|
|||||||
var (
|
var (
|
||||||
rolePoliciesMap = map[string][]*rbac.Policy{
|
rolePoliciesMap = map[string][]*rbac.Policy{
|
||||||
"projectAdmin": {
|
"projectAdmin": {
|
||||||
{Resource: ResourceImage, Action: ActionPushPull}, // compatible with security all perm of project
|
{Resource: ResourceSelf, Action: ActionRead},
|
||||||
{Resource: ResourceImage, Action: ActionPush},
|
{Resource: ResourceSelf, Action: ActionUpdate},
|
||||||
{Resource: ResourceImage, Action: ActionPull},
|
{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": {
|
"developer": {
|
||||||
{Resource: ResourceImage, Action: ActionPush},
|
{Resource: ResourceSelf, Action: ActionRead},
|
||||||
{Resource: ResourceImage, Action: ActionPull},
|
|
||||||
|
{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": {
|
"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 {
|
switch role.roleID {
|
||||||
case common.RoleProjectAdmin:
|
case common.RoleProjectAdmin:
|
||||||
return "projectAdmin"
|
return "projectAdmin"
|
||||||
|
case common.RoleMaster:
|
||||||
|
return "master"
|
||||||
case common.RoleDeveloper:
|
case common.RoleDeveloper:
|
||||||
return "developer"
|
return "developer"
|
||||||
case common.RoleGuest:
|
case common.RoleGuest:
|
||||||
|
@ -66,10 +66,10 @@ func (suite *VisitorTestSuite) TestGetPolicies() {
|
|||||||
suite.Equal(authenticatedForPublicProject.GetPolicies(), policiesForPublicProject(publicNamespace))
|
suite.Equal(authenticatedForPublicProject.GetPolicies(), policiesForPublicProject(publicNamespace))
|
||||||
|
|
||||||
systemAdmin := NewUser(sysAdminCtx, namespace)
|
systemAdmin := NewUser(sysAdminCtx, namespace)
|
||||||
suite.Equal(systemAdmin.GetPolicies(), policiesForSystemAdmin(namespace))
|
suite.Equal(systemAdmin.GetPolicies(), GetAllPolicies(namespace))
|
||||||
|
|
||||||
systemAdminForPublicProject := NewUser(sysAdminCtx, publicNamespace)
|
systemAdminForPublicProject := NewUser(sysAdminCtx, publicNamespace)
|
||||||
suite.Equal(systemAdminForPublicProject.GetPolicies(), policiesForSystemAdmin(publicNamespace))
|
suite.Equal(systemAdminForPublicProject.GetPolicies(), GetAllPolicies(publicNamespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *VisitorTestSuite) TestGetRoles() {
|
func (suite *VisitorTestSuite) TestGetRoles() {
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
package rbac
|
package rbac
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,6 +31,27 @@ const (
|
|||||||
// Resource the type of resource
|
// Resource the type of resource
|
||||||
type Resource string
|
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 {
|
func (res Resource) String() string {
|
||||||
return string(res)
|
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
|
// HasReadPerm returns whether the user has read permission to the project
|
||||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// HasWritePerm returns whether the user has write permission to the project
|
||||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// HasAllPerm returns whether the user has all permissions to the project
|
||||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// 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
|
// HasReadPerm returns whether the user has read permission to the project
|
||||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// HasWritePerm returns whether the user has write permission to the project
|
||||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// HasAllPerm returns whether the user has all permissions to the project
|
||||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||||
isPublicProject, _ := s.pm.IsPublic(projectIDOrName)
|
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
|
// 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
|
// HasReadPerm returns whether the user has read permission to the project
|
||||||
func (msc *mockSecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
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
|
// HasWritePerm returns whether the user has write permission to the project
|
||||||
func (msc *mockSecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
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
|
// 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/config"
|
||||||
"github.com/goharbor/harbor/src/core/filter"
|
"github.com/goharbor/harbor/src/core/filter"
|
||||||
"github.com/goharbor/harbor/tests/apitests/apilib"
|
"github.com/goharbor/harbor/tests/apitests/apilib"
|
||||||
|
|
||||||
// "strconv"
|
// "strconv"
|
||||||
// "strings"
|
// "strings"
|
||||||
|
|
||||||
@ -103,6 +104,7 @@ func init() {
|
|||||||
beego.Router("/api/users/:id", &UserAPI{}, "get:Get")
|
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", &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([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/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
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
|
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.
|
// Mark a registered user as be removed.
|
||||||
func (a testapi) UsersDelete(userID int, authInfo usrInfo) (int, error) {
|
func (a testapi) UsersDelete(userID int, authInfo usrInfo) (int, error) {
|
||||||
_sling := sling.New().Delete(a.basePath)
|
_sling := sling.New().Delete(a.basePath)
|
||||||
|
@ -24,6 +24,8 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/dao"
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"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"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"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
|
// modifiable returns whether the modify is allowed based on current auth mode and context
|
||||||
func (ua *UserAPI) modifiable() bool {
|
func (ua *UserAPI) modifiable() bool {
|
||||||
if ua.AuthMode == common.DBAuth {
|
if ua.AuthMode == common.DBAuth {
|
||||||
|
@ -572,3 +572,28 @@ func TestModifiable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.True(ua4.modifiable())
|
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/:id", &api.UserAPI{}, "get:Get;delete:Delete;put:Put")
|
||||||
beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post")
|
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([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/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")
|
||||||
beego.Router("/api/usergroups/?:ugid([0-9]+)", &api.UserGroupAPI{})
|
beego.Router("/api/usergroups/?:ugid([0-9]+)", &api.UserGroupAPI{})
|
||||||
beego.Router("/api/ldap/ping", &api.LdapAPI{}, "post:Ping")
|
beego.Router("/api/ldap/ping", &api.LdapAPI{}, "post:Ping")
|
||||||
|
@ -53,3 +53,9 @@ type User struct {
|
|||||||
|
|
||||||
UpdateTime string `json:"update_time,omitempty"`
|
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