harbor/src/common/rbac/project/evaluator.go

107 lines
3.1 KiB
Go

// Copyright Project Harbor Authors
//
// 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 project
import (
"context"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/permission/evaluator"
"github.com/goharbor/harbor/src/pkg/permission/evaluator/namespace"
"github.com/goharbor/harbor/src/pkg/permission/evaluator/rbac"
"github.com/goharbor/harbor/src/pkg/permission/types"
proModels "github.com/goharbor/harbor/src/pkg/project/models"
)
// RBACUserBuilder builder to make types.RBACUser for the project
type RBACUserBuilder func(context.Context, *proModels.Project) types.RBACUser
// NewBuilderForUser create a builder for the local user
func NewBuilderForUser(user *models.User, ctl project.Controller) RBACUserBuilder {
return func(ctx context.Context, p *proModels.Project) types.RBACUser {
if user == nil {
// anonymous access
return &rbacUser{
project: p,
username: "anonymous",
}
}
roles, err := ctl.ListRoles(ctx, p.ProjectID, user)
if err != nil {
log.Errorf("failed to list roles: %v", err)
return nil
}
return &rbacUser{
project: p,
username: user.Username,
projectRoles: roles,
}
}
}
// NewBuilderForPolicies create a builder for the policies
func NewBuilderForPolicies(username string, policies []*types.Policy,
filters ...func(*proModels.Project, []*types.Policy) []*types.Policy) RBACUserBuilder {
return func(_ context.Context, p *proModels.Project) types.RBACUser {
for _, filter := range filters {
policies = filter(p, policies)
}
return &rbacUser{
project: p,
username: username,
policies: policies,
}
}
}
// NewEvaluator create evaluator for the project by builders
func NewEvaluator(ctl project.Controller, builders ...RBACUserBuilder) evaluator.Evaluator {
return namespace.New(NamespaceKind, func(ctx context.Context, ns types.Namespace) evaluator.Evaluator {
p, err := ctl.Get(ctx, ns.Identity().(int64), project.Metadata(true))
if err != nil {
if err != nil {
log.Warningf("Failed to get info of project %d for permission evaluator, error: %v", ns.Identity(), err)
}
return nil
}
var rbacUsers []types.RBACUser
for _, builder := range builders {
if rbacUser := builder(ctx, p); rbacUser != nil {
rbacUsers = append(rbacUsers, rbacUser)
}
}
switch len(rbacUsers) {
case 0:
return nil
case 1:
return rbac.New(rbacUsers[0])
default:
var evaluators evaluator.Evaluators
for _, rbacUser := range rbacUsers {
evaluators = evaluators.Add(rbac.New(rbacUser))
}
return evaluators
}
})
}