mirror of
https://github.com/goharbor/harbor
synced 2025-05-15 02:05:38 +00: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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/casbin/casbin"
|
"github.com/casbin/casbin"
|
||||||
"github.com/casbin/casbin/model"
|
"github.com/casbin/casbin/model"
|
||||||
"github.com/casbin/casbin/persist"
|
"github.com/casbin/casbin/persist"
|
||||||
|
"github.com/casbin/casbin/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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 == '*')
|
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 {
|
type userAdapter struct {
|
||||||
User
|
User
|
||||||
}
|
}
|
||||||
@ -134,5 +161,8 @@ func (a *userAdapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex
|
|||||||
func enforcerForUser(user User) *casbin.Enforcer {
|
func enforcerForUser(user User) *casbin.Enforcer {
|
||||||
m := model.Model{}
|
m := model.Model{}
|
||||||
m.LoadModelFromText(modelText)
|
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",
|
name: "project create for user without roles",
|
||||||
args: args{
|
args: args{
|
||||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||||
"/project",
|
"/project",
|
||||||
"create",
|
"create",
|
||||||
},
|
},
|
||||||
@ -136,7 +136,7 @@ func TestHasPermissionUserWithoutRoles(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "project delete test for user without roles",
|
name: "project delete test for user without roles",
|
||||||
args: args{
|
args: args{
|
||||||
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
&userWithoutRoles{Username: "user1", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||||
"/project",
|
"/project",
|
||||||
"delete",
|
"delete",
|
||||||
},
|
},
|
||||||
@ -168,7 +168,7 @@ func TestHasPermissionUsernameEmpty(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "project create for user without roles",
|
name: "project create for user without roles",
|
||||||
args: args{
|
args: args{
|
||||||
&userWithoutRoles{Username: "", UserPolicies: []*Policy{{Resource: "project", Action: "create"}}},
|
&userWithoutRoles{Username: "", UserPolicies: []*Policy{{Resource: "/project", Action: "create"}}},
|
||||||
"/project",
|
"/project",
|
||||||
"create",
|
"create",
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user