Merge pull request #2193 from ywk253100/170502_security_ctx_db

Implement security context interface
This commit is contained in:
Wenkai Yin 2017-05-04 12:15:44 +08:00 committed by GitHub
commit 13d9b05dcb
5 changed files with 310 additions and 16 deletions

View File

@ -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"

View File

@ -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

View File

@ -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
}

View 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"))
}

View File

@ -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
}