2022-02-13 23:39:27 +08:00
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
2022-01-01 16:28:06 +08:00
//
// 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 object
import (
2023-10-08 19:33:28 +08:00
"fmt"
2023-05-28 11:29:43 +08:00
"strings"
"github.com/casdoor/casdoor/conf"
2022-01-20 14:11:46 +08:00
"github.com/casdoor/casdoor/util"
2023-02-12 09:33:24 +08:00
"github.com/xorm-io/core"
2022-01-01 16:28:06 +08:00
)
type Permission struct {
Owner string ` xorm:"varchar(100) notnull pk" json:"owner" `
Name string ` xorm:"varchar(100) notnull pk" json:"name" `
CreatedTime string ` xorm:"varchar(100)" json:"createdTime" `
DisplayName string ` xorm:"varchar(100)" json:"displayName" `
2023-06-03 18:49:57 +08:00
Description string ` xorm:"varchar(100)" json:"description" `
2022-01-01 16:28:06 +08:00
2022-08-15 10:24:26 +08:00
Users [ ] string ` xorm:"mediumtext" json:"users" `
2023-09-06 00:10:33 +08:00
Groups [ ] string ` xorm:"mediumtext" json:"groups" `
2022-08-15 10:24:26 +08:00
Roles [ ] string ` xorm:"mediumtext" json:"roles" `
Domains [ ] string ` xorm:"mediumtext" json:"domains" `
2022-01-01 16:28:06 +08:00
2022-05-24 18:27:47 +08:00
Model string ` xorm:"varchar(100)" json:"model" `
2022-08-18 11:49:32 +08:00
Adapter string ` xorm:"varchar(100)" json:"adapter" `
2022-01-01 16:28:06 +08:00
ResourceType string ` xorm:"varchar(100)" json:"resourceType" `
Resources [ ] string ` xorm:"mediumtext" json:"resources" `
Actions [ ] string ` xorm:"mediumtext" json:"actions" `
Effect string ` xorm:"varchar(100)" json:"effect" `
2022-08-15 14:09:12 +08:00
IsEnabled bool ` json:"isEnabled" `
2022-01-01 16:28:06 +08:00
2022-08-15 14:09:12 +08:00
Submitter string ` xorm:"varchar(100)" json:"submitter" `
Approver string ` xorm:"varchar(100)" json:"approver" `
ApproveTime string ` xorm:"varchar(100)" json:"approveTime" `
State string ` xorm:"varchar(100)" json:"state" `
2022-01-01 16:28:06 +08:00
}
2023-08-11 02:45:11 +08:00
const builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
2023-01-15 12:06:10 +08:00
2023-05-30 15:49:39 +08:00
func GetPermissionCount ( owner , field , value string ) ( int64 , error ) {
2022-01-26 19:36:36 +08:00
session := GetSession ( owner , - 1 , - 1 , field , value , "" , "" )
2023-05-30 15:49:39 +08:00
return session . Count ( & Permission { } )
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
func GetPermissions ( owner string ) ( [ ] * Permission , error ) {
2022-01-01 16:28:06 +08:00
permissions := [ ] * Permission { }
2023-07-29 15:07:04 +08:00
err := ormer . Engine . Desc ( "created_time" ) . Find ( & permissions , & Permission { Owner : owner } )
2022-01-01 16:28:06 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return permissions , err
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
return permissions , nil
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
func GetPaginationPermissions ( owner string , offset , limit int , field , value , sortField , sortOrder string ) ( [ ] * Permission , error ) {
2022-01-01 16:28:06 +08:00
permissions := [ ] * Permission { }
session := GetSession ( owner , offset , limit , field , value , sortField , sortOrder )
err := session . Find ( & permissions )
if err != nil {
2023-05-30 15:49:39 +08:00
return permissions , err
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
return permissions , nil
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
func getPermission ( owner string , name string ) ( * Permission , error ) {
2022-01-01 16:28:06 +08:00
if owner == "" || name == "" {
2023-05-30 15:49:39 +08:00
return nil , nil
2022-01-01 16:28:06 +08:00
}
permission := Permission { Owner : owner , Name : name }
2023-07-29 15:07:04 +08:00
existed , err := ormer . Engine . Get ( & permission )
2022-01-01 16:28:06 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return & permission , err
2022-01-01 16:28:06 +08:00
}
if existed {
2023-05-30 15:49:39 +08:00
return & permission , nil
2022-01-01 16:28:06 +08:00
} else {
2023-05-30 15:49:39 +08:00
return nil , nil
2022-01-01 16:28:06 +08:00
}
}
2023-05-30 15:49:39 +08:00
func GetPermission ( id string ) ( * Permission , error ) {
2023-07-26 12:08:35 +07:00
owner , name := util . GetOwnerAndNameFromIdNoCheck ( id )
2022-01-01 16:28:06 +08:00
return getPermission ( owner , name )
}
2022-12-05 16:08:17 +08:00
// checkPermissionValid verifies if the permission is valid
2023-05-30 15:49:39 +08:00
func checkPermissionValid ( permission * Permission ) error {
2023-10-22 02:30:29 +08:00
enforcer , err := getPermissionEnforcer ( permission )
if err != nil {
return err
}
2022-12-05 16:08:17 +08:00
enforcer . EnableAutoSave ( false )
2023-01-17 09:27:02 +07:00
policies := getPolicies ( permission )
2023-10-22 02:30:29 +08:00
_ , err = enforcer . AddPolicies ( policies )
2023-01-17 09:27:02 +07:00
if err != nil {
2023-05-30 15:49:39 +08:00
return err
2023-01-17 09:27:02 +07:00
}
if ! HasRoleDefinition ( enforcer . GetModel ( ) ) {
permission . Roles = [ ] string { }
2023-05-30 15:49:39 +08:00
return nil
2023-01-17 09:27:02 +07:00
}
2023-12-02 15:26:52 +08:00
groupingPolicies , err := getGroupingPolicies ( permission )
if err != nil {
return err
}
2022-12-05 16:08:17 +08:00
if len ( groupingPolicies ) > 0 {
2023-10-22 02:30:29 +08:00
_ , err = enforcer . AddGroupingPolicies ( groupingPolicies )
2022-12-05 16:08:17 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return err
2022-12-05 16:08:17 +08:00
}
}
2023-05-30 15:49:39 +08:00
return nil
2022-12-05 16:08:17 +08:00
}
2023-05-30 15:49:39 +08:00
func UpdatePermission ( id string , permission * Permission ) ( bool , error ) {
err := checkPermissionValid ( permission )
if err != nil {
return false , err
}
2023-07-26 12:08:35 +07:00
owner , name := util . GetOwnerAndNameFromIdNoCheck ( id )
2023-05-30 15:49:39 +08:00
oldPermission , err := getPermission ( owner , name )
2022-07-13 00:34:35 +08:00
if oldPermission == nil {
2023-05-30 15:49:39 +08:00
return false , nil
2022-01-01 16:28:06 +08:00
}
2023-10-22 02:35:51 +08:00
if permission . ResourceType == "Application" && permission . Model != "" {
2025-03-20 09:05:27 +08:00
model , err := GetModelEx ( util . GetId ( permission . Owner , permission . Model ) )
2023-10-12 00:05:53 +08:00
if err != nil {
return false , err
2023-10-13 12:54:57 +08:00
} else if model == nil {
return false , fmt . Errorf ( "the model: %s for permission: %s is not found" , permission . Model , permission . GetId ( ) )
2023-10-12 00:05:53 +08:00
}
2023-10-13 12:54:57 +08:00
2023-10-12 00:05:53 +08:00
modelCfg , err := getModelCfg ( model )
if err != nil {
return false , err
}
if len ( strings . Split ( modelCfg [ "p" ] , "," ) ) != 3 {
2023-10-13 12:54:57 +08:00
return false , fmt . Errorf ( "the model: %s for permission: %s is not valid, Casbin model's [policy_defination] section should have 3 elements" , permission . Model , permission . GetId ( ) )
2023-10-12 00:05:53 +08:00
}
}
2023-07-29 15:07:04 +08:00
affected , err := ormer . Engine . ID ( core . PK { owner , name } ) . AllCols ( ) . Update ( permission )
2022-01-01 16:28:06 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return false , err
2022-01-01 16:28:06 +08:00
}
2022-07-13 00:34:35 +08:00
if affected != 0 {
2023-10-22 02:30:29 +08:00
err = removeGroupingPolicies ( oldPermission )
if err != nil {
return false , err
}
err = removePolicies ( oldPermission )
if err != nil {
return false , err
}
2024-07-09 11:35:22 +08:00
// if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter {
// isEmpty, _ := ormer.Engine.IsTableEmpty(oldPermission.Adapter)
// if isEmpty {
// err = ormer.Engine.DropTables(oldPermission.Adapter)
// if err != nil {
// return false, err
// }
// }
// }
2023-10-22 02:30:29 +08:00
err = addGroupingPolicies ( permission )
if err != nil {
return false , err
}
err = addPolicies ( permission )
if err != nil {
return false , err
}
2022-07-13 00:34:35 +08:00
}
2023-05-30 15:49:39 +08:00
return affected != 0 , nil
2022-01-01 16:28:06 +08:00
}
2023-05-30 15:49:39 +08:00
func AddPermission ( permission * Permission ) ( bool , error ) {
2023-07-29 15:07:04 +08:00
affected , err := ormer . Engine . Insert ( permission )
2022-01-01 16:28:06 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return false , err
2022-01-01 16:28:06 +08:00
}
2022-08-19 11:59:35 +08:00
if affected != 0 {
2023-10-22 02:30:29 +08:00
err = addGroupingPolicies ( permission )
if err != nil {
return false , err
}
err = addPolicies ( permission )
if err != nil {
return false , err
}
2022-08-19 11:59:35 +08:00
}
2023-05-30 15:49:39 +08:00
return affected != 0 , nil
2022-01-01 16:28:06 +08:00
}
2023-10-22 02:30:29 +08:00
func AddPermissions ( permissions [ ] * Permission ) ( bool , error ) {
2023-05-28 11:29:43 +08:00
if len ( permissions ) == 0 {
2023-10-22 02:30:29 +08:00
return false , nil
2023-05-28 11:29:43 +08:00
}
2023-07-29 15:07:04 +08:00
affected , err := ormer . Engine . Insert ( permissions )
2023-05-28 11:29:43 +08:00
if err != nil {
if ! strings . Contains ( err . Error ( ) , "Duplicate entry" ) {
2023-10-22 02:30:29 +08:00
return false , err
2023-05-28 11:29:43 +08:00
}
}
for _ , permission := range permissions {
// add using for loop
if affected != 0 {
2023-10-22 02:30:29 +08:00
err = addGroupingPolicies ( permission )
if err != nil {
return false , err
}
err = addPolicies ( permission )
if err != nil {
return false , err
}
2023-05-28 11:29:43 +08:00
}
}
2023-10-22 02:30:29 +08:00
return affected != 0 , nil
2023-05-28 11:29:43 +08:00
}
2023-10-22 02:30:29 +08:00
func AddPermissionsInBatch ( permissions [ ] * Permission ) ( bool , error ) {
2023-05-28 11:29:43 +08:00
batchSize := conf . GetConfigBatchSize ( )
if len ( permissions ) == 0 {
2023-10-22 02:30:29 +08:00
return false , nil
2023-05-28 11:29:43 +08:00
}
affected := false
2023-10-08 19:33:28 +08:00
for i := 0 ; i < len ( permissions ) ; i += batchSize {
start := i
end := i + batchSize
2023-05-28 11:29:43 +08:00
if end > len ( permissions ) {
end = len ( permissions )
}
tmp := permissions [ start : end ]
2023-10-08 19:33:28 +08:00
fmt . Printf ( "The syncer adds permissions: [%d - %d]\n" , start , end )
2023-10-22 02:30:29 +08:00
b , err := AddPermissions ( tmp )
if err != nil {
return false , err
}
if b {
2023-05-28 11:29:43 +08:00
affected = true
}
}
2023-10-22 02:30:29 +08:00
return affected , nil
2023-05-28 11:29:43 +08:00
}
2024-05-07 23:11:08 +08:00
func deletePermission ( permission * Permission ) ( bool , error ) {
2023-07-29 15:07:04 +08:00
affected , err := ormer . Engine . ID ( core . PK { permission . Owner , permission . Name } ) . Delete ( & Permission { } )
2022-01-01 16:28:06 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return false , err
2022-01-01 16:28:06 +08:00
}
2024-05-07 23:11:08 +08:00
return affected != 0 , nil
}
func DeletePermission ( permission * Permission ) ( bool , error ) {
affected , err := deletePermission ( permission )
if err != nil {
return false , err
}
if affected {
2023-10-22 02:30:29 +08:00
err = removeGroupingPolicies ( permission )
if err != nil {
return false , err
}
err = removePolicies ( permission )
if err != nil {
return false , err
}
2024-07-09 11:35:22 +08:00
// if permission.Adapter != "" && permission.Adapter != "permission_rule" {
// isEmpty, _ := ormer.Engine.IsTableEmpty(permission.Adapter)
// if isEmpty {
// err = ormer.Engine.DropTables(permission.Adapter)
// if err != nil {
// return false, err
// }
// }
// }
2022-07-13 00:34:35 +08:00
}
2024-05-07 23:11:08 +08:00
return affected , nil
2022-01-01 16:28:06 +08:00
}
2023-09-24 08:01:18 +08:00
func getPermissionsByUser ( userId string ) ( [ ] * Permission , error ) {
2022-07-30 17:31:56 +08:00
permissions := [ ] * Permission { }
2023-07-29 15:07:04 +08:00
err := ormer . Engine . Where ( "users like ?" , "%" + userId + "\"%" ) . Find ( & permissions )
2023-09-24 08:01:18 +08:00
if err != nil {
return permissions , err
}
2023-09-24 09:13:54 +08:00
res := [ ] * Permission { }
for _ , permission := range permissions {
if util . InSlice ( permission . Users , userId ) {
res = append ( res , permission )
}
}
return res , nil
}
func GetPermissionsByRole ( roleId string ) ( [ ] * Permission , error ) {
permissions := [ ] * Permission { }
err := ormer . Engine . Where ( "roles like ?" , "%" + roleId + "\"%" ) . Find ( & permissions )
if err != nil {
return permissions , err
}
res := [ ] * Permission { }
for _ , permission := range permissions {
if util . InSlice ( permission . Roles , roleId ) {
res = append ( res , permission )
}
}
return res , nil
}
func GetPermissionsByResource ( resourceId string ) ( [ ] * Permission , error ) {
permissions := [ ] * Permission { }
err := ormer . Engine . Where ( "resources like ?" , "%" + resourceId + "\"%" ) . Find ( & permissions )
if err != nil {
return permissions , err
}
res := [ ] * Permission { }
for _ , permission := range permissions {
if util . InSlice ( permission . Resources , resourceId ) {
res = append ( res , permission )
}
}
return res , nil
2023-09-24 08:01:18 +08:00
}
func getPermissionsAndRolesByUser ( userId string ) ( [ ] * Permission , [ ] * Role , error ) {
permissions , err := getPermissionsByUser ( userId )
2022-07-30 17:31:56 +08:00
if err != nil {
2023-06-16 21:44:21 +07:00
return nil , nil , err
2022-07-30 17:31:56 +08:00
}
2023-06-16 21:44:21 +07:00
existedPerms := map [ string ] struct { } { }
for _ , perm := range permissions {
perm . Users = nil
if _ , ok := existedPerms [ perm . Name ] ; ! ok {
existedPerms [ perm . Name ] = struct { } { }
}
2023-03-03 18:18:41 +08:00
}
2023-06-16 21:44:21 +07:00
permFromRoles := [ ] * Permission { }
2023-09-24 08:01:18 +08:00
roles , err := getRolesByUser ( userId )
2023-06-16 21:44:21 +07:00
if err != nil {
return nil , nil , err
}
for _ , role := range roles {
2023-09-24 08:01:18 +08:00
perms , err := GetPermissionsByRole ( role . GetId ( ) )
2023-06-16 21:44:21 +07:00
if err != nil {
return nil , nil , err
}
permFromRoles = append ( permFromRoles , perms ... )
}
for _ , perm := range permFromRoles {
perm . Users = nil
if _ , ok := existedPerms [ perm . Name ] ; ! ok {
existedPerms [ perm . Name ] = struct { } { }
permissions = append ( permissions , perm )
}
}
return permissions , roles , nil
2023-05-18 15:36:03 +07:00
}
2023-05-30 15:49:39 +08:00
func GetPermissionsBySubmitter ( owner string , submitter string ) ( [ ] * Permission , error ) {
2022-08-15 14:09:12 +08:00
permissions := [ ] * Permission { }
2023-07-29 15:07:04 +08:00
err := ormer . Engine . Desc ( "created_time" ) . Find ( & permissions , & Permission { Owner : owner , Submitter : submitter } )
2022-08-15 14:09:12 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return permissions , err
2022-08-15 14:09:12 +08:00
}
2023-05-30 15:49:39 +08:00
return permissions , nil
2022-08-15 14:09:12 +08:00
}
2022-09-02 12:03:13 +08:00
2023-05-30 15:49:39 +08:00
func GetPermissionsByModel ( owner string , model string ) ( [ ] * Permission , error ) {
2023-05-12 21:32:48 +08:00
permissions := [ ] * Permission { }
2023-07-29 15:07:04 +08:00
err := ormer . Engine . Desc ( "created_time" ) . Find ( & permissions , & Permission { Owner : owner , Model : model } )
2023-05-12 21:32:48 +08:00
if err != nil {
2023-05-30 15:49:39 +08:00
return permissions , err
2023-05-12 21:32:48 +08:00
}
2023-05-30 15:49:39 +08:00
return permissions , nil
2023-05-12 21:32:48 +08:00
}
2023-01-05 23:02:52 +07:00
func GetMaskedPermissions ( permissions [ ] * Permission ) [ ] * Permission {
for _ , permission := range permissions {
permission . Users = nil
permission . Submitter = ""
}
return permissions
}
2023-06-22 16:45:24 +07:00
// GroupPermissionsByModelAdapter group permissions by model and adapter.
// Every model and adapter will be a key, and the value is a list of permission ids.
// With each list of permission ids have the same key, we just need to init the
// enforcer and do the enforce/batch-enforce once (with list of permission ids
// as the policyFilter when the enforcer load policy).
func GroupPermissionsByModelAdapter ( permissions [ ] * Permission ) map [ string ] [ ] string {
m := make ( map [ string ] [ ] string )
for _ , permission := range permissions {
2023-12-20 11:41:54 +08:00
key := permission . GetModelAndAdapter ( )
2023-06-22 16:45:24 +07:00
permissionIds , ok := m [ key ]
if ! ok {
m [ key ] = [ ] string { permission . GetId ( ) }
} else {
m [ key ] = append ( permissionIds , permission . GetId ( ) )
}
}
return m
}
2023-09-15 02:47:53 +08:00
func ( p * Permission ) GetId ( ) string {
return util . GetId ( p . Owner , p . Name )
}
2023-12-20 11:41:54 +08:00
func ( p * Permission ) GetModelAndAdapter ( ) string {
return util . GetId ( p . Model , p . Adapter )
}
2023-09-15 02:47:53 +08:00
func ( p * Permission ) isUserHit ( name string ) bool {
2023-10-13 15:41:23 +08:00
targetOrg , targetName := util . GetOwnerAndNameFromId ( name )
2023-09-15 02:47:53 +08:00
for _ , user := range p . Users {
2023-12-22 14:16:00 +08:00
if user == "*" {
return true
}
2023-09-15 02:47:53 +08:00
userOrg , userName := util . GetOwnerAndNameFromId ( user )
2023-10-13 15:41:23 +08:00
if userOrg == targetOrg && ( userName == "*" || userName == targetName ) {
2023-09-15 02:47:53 +08:00
return true
}
}
return false
}
2023-10-17 01:35:13 -05:00
func ( p * Permission ) isRoleHit ( userId string ) bool {
targetRoles , err := getRolesByUser ( userId )
if err != nil {
return false
}
2023-12-22 14:16:00 +08:00
2023-10-17 01:35:13 -05:00
for _ , role := range p . Roles {
2023-12-22 14:16:00 +08:00
if role == "*" {
return true
}
2023-10-17 01:35:13 -05:00
for _ , targetRole := range targetRoles {
2023-12-22 14:16:00 +08:00
if role == targetRole . GetId ( ) {
2023-10-17 01:35:13 -05:00
return true
}
}
}
return false
}
2023-09-15 02:47:53 +08:00
func ( p * Permission ) isResourceHit ( name string ) bool {
for _ , resource := range p . Resources {
2023-10-13 15:41:23 +08:00
if resource == "*" || resource == name {
2023-09-15 02:47:53 +08:00
return true
}
}
return false
}