mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-24 08:31:24 +01:00
Replace casbin builtin keyMatch2 with custom match func
Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
parent
8b5e68073d
commit
0ab7c93e16
@ -17,10 +17,13 @@ package rbac
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/casbin/casbin/model"
|
||||
"github.com/casbin/casbin/persist"
|
||||
"github.com/casbin/casbin/util"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -50,6 +53,30 @@ e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
|
||||
m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && (r.act == p.act || p.act == '*')
|
||||
`
|
||||
|
||||
// keyMatch2 determines whether key1 matches the pattern of key2, its behavior most likely the builtin KeyMatch2
|
||||
// except that the match of ("/project/1/robot", "/project/1") will return false
|
||||
func keyMatch2(key1 string, key2 string) bool {
|
||||
key2 = strings.Replace(key2, "/*", "/.*", -1)
|
||||
|
||||
re := regexp.MustCompile(`(.*):[^/]+(.*)`)
|
||||
for {
|
||||
if !strings.Contains(key2, "/:") {
|
||||
break
|
||||
}
|
||||
|
||||
key2 = re.ReplaceAllString(key2, "$1[^/]+$2")
|
||||
}
|
||||
|
||||
return util.RegexMatch(key1, "^"+key2+"$")
|
||||
}
|
||||
|
||||
func keyMatch2Func(args ...interface{}) (interface{}, error) {
|
||||
name1 := args[0].(string)
|
||||
name2 := args[1].(string)
|
||||
|
||||
return bool(keyMatch2(name1, name2)), nil
|
||||
}
|
||||
|
||||
type userAdapter struct {
|
||||
User
|
||||
}
|
||||
@ -134,5 +161,8 @@ func (a *userAdapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex
|
||||
func enforcerForUser(user User) *casbin.Enforcer {
|
||||
m := model.Model{}
|
||||
m.LoadModelFromText(modelText)
|
||||
return casbin.NewEnforcer(m, &userAdapter{User: user})
|
||||
|
||||
e := casbin.NewEnforcer(m, &userAdapter{User: user})
|
||||
e.AddFunction("keyMatch2", keyMatch2Func)
|
||||
return e
|
||||
}
|
||||
|
59
src/common/rbac/casbin_test.go
Normal file
59
src/common/rbac/casbin_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
// 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 rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_keyMatch2(t *testing.T) {
|
||||
type args struct {
|
||||
key1 string
|
||||
key2 string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "match /project/1/robot, /project/1",
|
||||
args: args{"/project/1/robot", "/project/1"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "match /project/1/robot, /project/:pid",
|
||||
args: args{"/project/1/robot", "/project/:pid"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "match /project/1/robot, /project/1/*",
|
||||
args: args{"/project/1/robot", "/project/1/*"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "match /project/1/robot, /project/:pid/robot",
|
||||
args: args{"/project/1/robot", "/project/:pid/robot"},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := keyMatch2(tt.args.key1, tt.args.key2); got != tt.want {
|
||||
t.Errorf("keyMatch2() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -127,7 +127,7 @@ func TestHasPermissionUserWithoutRoles(t *testing.T) {
|
||||
{
|
||||
name: "project create for user without roles",
|
||||
args: args{
|
||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||
"/project",
|
||||
"create",
|
||||
},
|
||||
@ -136,7 +136,7 @@ func TestHasPermissionUserWithoutRoles(t *testing.T) {
|
||||
{
|
||||
name: "project delete test for user without roles",
|
||||
args: args{
|
||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||
"/project",
|
||||
"delete",
|
||||
},
|
||||
@ -168,7 +168,7 @@ func TestHasPermissionUsernameEmpty(t *testing.T) {
|
||||
{
|
||||
name: "project create for user without roles",
|
||||
args: args{
|
||||
&userWithoutRoles{Username: "", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
||||
&userWithoutRoles{Username: "", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||
"/project",
|
||||
"create",
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user