From ac7256efbdc78b60e99ee75906c6a46c6f76ac3d Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Tue, 2 May 2017 17:36:38 +0800 Subject: [PATCH] implement security context interface for database --- src/common/security/db/context.go | 73 ++++++++++++++ src/common/security/db/context_test.go | 134 +++++++++++++++++++++++++ src/ui/pms/service.go | 6 +- 3 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/common/security/db/context_test.go diff --git a/src/common/security/db/context.go b/src/common/security/db/context.go index 0086c5d31..54231c499 100644 --- a/src/common/security/db/context.go +++ b/src/common/security/db/context.go @@ -13,3 +13,76 @@ // limitations under the License. package db + +import ( + "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 + } + + return s.pms.HasReadPerm(s.GetUsername(), projectIDOrName) +} + +// HasWritePerm returns whether the user has write permission to the project +func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool { + if !s.IsAuthenticated() { + return false + } + return s.pms.HasWritePerm(s.GetUsername(), projectIDOrName) +} + +// HasAllPerm returns whether the user has all permissions to the project +func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool { + if !s.IsAuthenticated() { + return false + } + return s.pms.HasAllPerm(s.GetUsername(), projectIDOrName) +} diff --git a/src/common/security/db/context_test.go b/src/common/security/db/context_test.go new file mode 100644 index 000000000..f4ec10e98 --- /dev/null +++ b/src/common/security/db/context_test.go @@ -0,0 +1,134 @@ +// 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 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + //"github.com/stretchr/testify/require" + "github.com/vmware/harbor/src/common/models" +) + +type fakePMS struct { + public string +} + +func (f *fakePMS) IsPublic(projectIDOrName interface{}) bool { + return f.public == projectIDOrName.(string) +} +func (f *fakePMS) HasReadPerm(username string, projectIDOrName interface{}, + token ...string) bool { + return true +} +func (f *fakePMS) HasWritePerm(username string, projectIDOrName interface{}, + token ...string) bool { + return true +} +func (f *fakePMS) HasAllPerm(username string, projectIDOrName interface{}, + token ...string) bool { + return true +} + +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", + } + + // 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("private_project")) + + // private project, authenticated + ctx = NewSecurityContext(&models.User{ + Username: "test", + }, pms) + assert.True(t, ctx.HasReadPerm("private_project")) +} + +func TestHasWritePerm(t *testing.T) { + pms := &fakePMS{} + + // unauthenticated + ctx := NewSecurityContext(nil, pms) + assert.False(t, ctx.HasWritePerm("project")) + + // authenticated + ctx = NewSecurityContext(&models.User{ + Username: "test", + }, pms) + assert.True(t, ctx.HasWritePerm("project")) +} + +func TestHasAllPerm(t *testing.T) { + pms := &fakePMS{} + + // unauthenticated + ctx := NewSecurityContext(nil, pms) + assert.False(t, ctx.HasAllPerm("project")) + + // authenticated + ctx = NewSecurityContext(&models.User{ + Username: "test", + }, pms) + assert.True(t, ctx.HasAllPerm("project")) +} diff --git a/src/ui/pms/service.go b/src/ui/pms/service.go index 3fc83c9cd..6e916da11 100644 --- a/src/ui/pms/service.go +++ b/src/ui/pms/service.go @@ -12,9 +12,13 @@ // 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 + HasReadPerm(username string, projectIDOrName interface{}, token ...string) bool + HasWritePerm(username string, projectIDOrName interface{}, token ...string) bool + HasAllPerm(username string, projectIDOrName interface{}, token ...string) bool }