mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-15 14:56:13 +01:00
Merge pull request #2193 from ywk253100/170502_security_ctx_db
Implement security context interface
This commit is contained in:
commit
13d9b05dcb
@ -24,6 +24,11 @@ const (
|
||||
LDAPScopeOnelevel = "2"
|
||||
LDAPScopeSubtree = "3"
|
||||
|
||||
RoleSystemAdmin = 1
|
||||
RoleProjectAdmin = 2
|
||||
RoleDeveloper = 3
|
||||
RoleGuest = 4
|
||||
|
||||
ExtEndpoint = "ext_endpoint"
|
||||
AUTHMode = "auth_mode"
|
||||
DatabaseType = "database_type"
|
||||
|
@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package db
|
@ -13,3 +13,120 @@
|
||||
// limitations under the License.
|
||||
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/pms"
|
||||
)
|
||||
|
||||
// SecurityContext implements security.Context interface based on database
|
||||
type SecurityContext struct {
|
||||
user *models.User
|
||||
pms pms.PMS
|
||||
}
|
||||
|
||||
// NewSecurityContext ...
|
||||
func NewSecurityContext(user *models.User, pms pms.PMS) *SecurityContext {
|
||||
return &SecurityContext{
|
||||
user: user,
|
||||
pms: pms,
|
||||
}
|
||||
}
|
||||
|
||||
// IsAuthenticated returns true if the user has been authenticated
|
||||
func (s *SecurityContext) IsAuthenticated() bool {
|
||||
return s.user != nil
|
||||
}
|
||||
|
||||
// GetUsername returns the username of the authenticated user
|
||||
// It returns null if the user has not been authenticated
|
||||
func (s *SecurityContext) GetUsername() string {
|
||||
if !s.IsAuthenticated() {
|
||||
return ""
|
||||
}
|
||||
return s.user.Username
|
||||
}
|
||||
|
||||
// IsSysAdmin returns whether the authenticated user is system admin
|
||||
// It returns false if the user has not been authenticated
|
||||
func (s *SecurityContext) IsSysAdmin() bool {
|
||||
if !s.IsAuthenticated() {
|
||||
return false
|
||||
}
|
||||
return s.user.HasAdminRole == 1
|
||||
}
|
||||
|
||||
// HasReadPerm returns whether the user has read permission to the project
|
||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||
// public project
|
||||
if s.pms.IsPublic(projectIDOrName) {
|
||||
return true
|
||||
}
|
||||
|
||||
// private project
|
||||
if !s.IsAuthenticated() {
|
||||
return false
|
||||
}
|
||||
|
||||
// system admin
|
||||
if s.IsSysAdmin() {
|
||||
return true
|
||||
}
|
||||
|
||||
roles := s.pms.GetRoles(s.GetUsername(), projectIDOrName)
|
||||
for _, role := range roles {
|
||||
switch role {
|
||||
case common.RoleProjectAdmin,
|
||||
common.RoleDeveloper,
|
||||
common.RoleGuest:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// HasWritePerm returns whether the user has write permission to the project
|
||||
func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
||||
if !s.IsAuthenticated() {
|
||||
return false
|
||||
}
|
||||
|
||||
// system admin
|
||||
if s.IsSysAdmin() {
|
||||
return true
|
||||
}
|
||||
|
||||
roles := s.pms.GetRoles(s.GetUsername(), projectIDOrName)
|
||||
for _, role := range roles {
|
||||
switch role {
|
||||
case common.RoleProjectAdmin,
|
||||
common.RoleDeveloper:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// HasAllPerm returns whether the user has all permissions to the project
|
||||
func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
||||
if !s.IsAuthenticated() {
|
||||
return false
|
||||
}
|
||||
// system admin
|
||||
if s.IsSysAdmin() {
|
||||
return true
|
||||
}
|
||||
|
||||
roles := s.pms.GetRoles(s.GetUsername(), projectIDOrName)
|
||||
for _, role := range roles {
|
||||
switch role {
|
||||
case common.RoleProjectAdmin:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
185
src/common/security/rbac/context_test.go
Normal file
185
src/common/security/rbac/context_test.go
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
)
|
||||
|
||||
type fakePMS struct {
|
||||
public string
|
||||
roles map[string][]int
|
||||
}
|
||||
|
||||
func (f *fakePMS) IsPublic(projectIDOrName interface{}) bool {
|
||||
return f.public == projectIDOrName.(string)
|
||||
}
|
||||
func (f *fakePMS) GetRoles(username string, projectIDOrName interface{}) []int {
|
||||
return f.roles[projectIDOrName.(string)]
|
||||
}
|
||||
|
||||
func TestIsAuthenticated(t *testing.T) {
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, nil)
|
||||
assert.False(t, ctx.IsAuthenticated())
|
||||
|
||||
// authenticated
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, nil)
|
||||
assert.True(t, ctx.IsAuthenticated())
|
||||
}
|
||||
|
||||
func TestGetUsername(t *testing.T) {
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, nil)
|
||||
assert.Equal(t, "", ctx.GetUsername())
|
||||
|
||||
// authenticated
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, nil)
|
||||
assert.Equal(t, "test", ctx.GetUsername())
|
||||
}
|
||||
|
||||
func TestIsSysAdmin(t *testing.T) {
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, nil)
|
||||
assert.False(t, ctx.IsSysAdmin())
|
||||
|
||||
// authenticated, non admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, nil)
|
||||
assert.False(t, ctx.IsSysAdmin())
|
||||
|
||||
// authenticated, admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
HasAdminRole: 1,
|
||||
}, nil)
|
||||
assert.True(t, ctx.IsSysAdmin())
|
||||
}
|
||||
|
||||
func TestHasReadPerm(t *testing.T) {
|
||||
pms := &fakePMS{
|
||||
public: "public_project",
|
||||
roles: map[string][]int{
|
||||
"has_read_perm_project": []int{common.RoleGuest},
|
||||
},
|
||||
}
|
||||
|
||||
// public project, unauthenticated
|
||||
ctx := NewSecurityContext(nil, pms)
|
||||
assert.True(t, ctx.HasReadPerm("public_project"))
|
||||
|
||||
// private project, unauthenticated
|
||||
ctx = NewSecurityContext(nil, pms)
|
||||
assert.False(t, ctx.HasReadPerm("has_read_perm_project"))
|
||||
|
||||
// private project, authenticated, has no perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.False(t, ctx.HasReadPerm("has_no_perm_project"))
|
||||
|
||||
// private project, authenticated, has read perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasReadPerm("has_read_perm_project"))
|
||||
|
||||
// private project, authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
HasAdminRole: 1,
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasReadPerm("has_no_perm_project"))
|
||||
}
|
||||
|
||||
func TestHasWritePerm(t *testing.T) {
|
||||
pms := &fakePMS{
|
||||
roles: map[string][]int{
|
||||
"has_read_perm_project": []int{common.RoleGuest},
|
||||
"has_write_perm_project": []int{common.RoleGuest, common.RoleDeveloper},
|
||||
},
|
||||
}
|
||||
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, pms)
|
||||
assert.False(t, ctx.HasWritePerm("has_write_perm_project"))
|
||||
|
||||
// authenticated, has read perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.False(t, ctx.HasWritePerm("has_read_perm_project")) // authenticated, has read perm
|
||||
|
||||
// authenticated, has write perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasWritePerm("has_write_perm_project"))
|
||||
|
||||
// authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
HasAdminRole: 1,
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasReadPerm("has_no_perm_project"))
|
||||
}
|
||||
|
||||
func TestHasAllPerm(t *testing.T) {
|
||||
pms := &fakePMS{
|
||||
roles: map[string][]int{
|
||||
"has_read_perm_project": []int{common.RoleGuest},
|
||||
"has_write_perm_project": []int{common.RoleGuest, common.RoleDeveloper},
|
||||
"has_all_perm_project": []int{common.RoleGuest, common.RoleDeveloper, common.RoleProjectAdmin},
|
||||
},
|
||||
}
|
||||
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, pms)
|
||||
assert.False(t, ctx.HasAllPerm("has_all_perm_project"))
|
||||
|
||||
// authenticated, has read perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.False(t, ctx.HasAllPerm("has_read_perm_project"))
|
||||
|
||||
// authenticated, has write perm
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.False(t, ctx.HasAllPerm("has_write_perm_project"))
|
||||
|
||||
// authenticated, has all perms
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasAllPerm("has_all_perm_project"))
|
||||
|
||||
// authenticated, system admin
|
||||
ctx = NewSecurityContext(&models.User{
|
||||
Username: "test",
|
||||
HasAdminRole: 1,
|
||||
}, pms)
|
||||
assert.True(t, ctx.HasReadPerm("has_no_perm_project"))
|
||||
}
|
@ -12,9 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package project
|
||||
package pms
|
||||
|
||||
// PMS is the project mamagement service which abstracts
|
||||
// the operations related to projects
|
||||
type PMS interface {
|
||||
IsPublic(projectIDOrName interface{}) bool
|
||||
GetRoles(username string, projectIDOrName interface{}) []int
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user