blob: dc939cc328099fa685cb6ce306448cb6d5e3ede0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 demo
import (
"embed"
"errors"
"strings"
"github.com/casbin/casbin/v2"
casbinFSAdapter "github.com/naucon/casbin-fs-adapter"
"github.com/apache/apisix-dashboard/api/pkg/iam"
)
var (
//go:embed model.conf policy.csv
fs embed.FS
// Ensure that demo Access conforms to the iam.Access interface definition
_ iam.Access = Access{}
)
type Access struct{}
func (Access) Check(identity, resource, action string) error {
// Load casbin model and adapter from Go embed FS
model, _ := casbinFSAdapter.NewModel(fs, "model.conf")
policies := casbinFSAdapter.NewAdapter(fs, "policy.csv")
policies.LoadPolicy(model)
// Create enforcer
enforce, err := casbin.NewEnforcer(model, policies)
if err != nil {
return err
}
enforce.AddFunction("identify", KeyMatchFunc)
// get all the permission the user has
pers, _ := enforce.GetImplicitPermissionsForUser("role_admin")
admin, _ := enforce.HasRoleForUser(identity, "role_admin")
if !admin {
for _, v := range pers {
if KeyMatch(resource, v[1]) && action == v[2] {
return errors.New("no permission")
}
}
}
// the normal url can be requested
return nil
}
// KeyMatchFunc wrap KeyMatch to meet with casbin's need of custom functions
func KeyMatchFunc(args ...interface{}) (interface{}, error) {
key1, key2 := args[0].(string), args[1].(string)
return (bool)(KeyMatch(key1, key2)), nil
}
// KeyMatch can match three patterns of route /* && /:id && /:id/*
func KeyMatch(key1 string, key2 string) bool {
i, j := strings.Index(key2, ":"), strings.Index(key2, "*")
if len(key1) < i+1 {
return false
}
if i != -1 {
ok := key1[:i-1] == key2[:i-1]
if j != -1 && ok {
k, p := strings.Index(key2[i:], "/"), strings.Index(key1[i:], "/")
if key2[i+k+1] == '*' {
return true
}
return key2[i+k:j] == key1[i+p:i+p+k+1]
}
return ok
} else if j != -1 {
ok := key1[:j-1] == key2[:j-1]
if i != -1 && ok {
k, p := strings.Index(key2[i:], "/"), strings.Index(key1[i:], "/")
if key2[i+k+1] == '*' {
return true
}
return key2[i+k:j] == key1[i+p:i+p+k+1]
}
return ok
}
return key1 == key2
}