Coverage report for Casbin.Resolve.
Generated at 18/02/2019 12:10:19 by DelphiCodeCoverage - an open source tool for Delphi Code Coverage.
Statistics for Casbin.Resolve.pas
| Number of lines covered | 59 |
| Number of lines with code gen | 67 |
| Line coverage | 88% |
| 1 | // Copyright 2018 by John Kouraklis and Contributors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | unit Casbin.Resolve; |
| 15 | |
| 16 | interface |
| 17 | |
| 18 | uses |
| 19 | Casbin.Types, Casbin.Resolve.Types, |
| 20 | System.Generics.Collections, Casbin.Effect.Types, Casbin.Functions.Types; |
| 21 | |
| 22 | function resolve (const aResolve: TList<string>; |
| 23 | const aResolveType: TResolveType; |
| 24 | const aAssertions: TList<string>): |
| 25 | TDictionary<string, string>; overload; |
| 26 | |
| 27 | function resolve(const aResolvedRequest, aResolvedPolicy: TDictionary<string, |
| 28 | string>; const aFunctions: IFunctions; const aMatcher: string): |
| 29 | TEffectResult; overload; |
| 30 | |
| 31 | implementation |
| 32 | |
| 33 | uses |
| 34 | Casbin.Exception.Types, System.SysUtils, Casbin.Matcher.Types, Casbin.Matcher, |
| 35 | Casbin.Core.Utilities, Classes; |
| 36 | |
| 37 | function resolve (const aResolve: TList<string>; |
| 38 | const aResolveType: TResolveType; |
| 39 | const aAssertions: TList<string>): |
| 40 | TDictionary<string, string>; |
| 41 | var |
| 42 | i: Integer; |
| 43 | index: Integer; |
| 44 | request: TEnforceParameters; |
| 45 | begin |
| 46 | if not Assigned(aAssertions) then |
| 47 | raise ECasbinException.Create('Assertions list is nil'); |
| 48 | Result:=TDictionary<string, string>.Create; |
| 49 | case aResolveType of |
| 50 | rtRequest, |
| 51 | rtPolicy: begin |
| 52 | SetLength(request, aResolve.Count); |
| 53 | for i:=0 to aResolve.Count-1 do |
| 54 | request[i]:=UpperCase(Trim(aResolve.Items[i])); |
| 55 | if (aResolveType=rtRequest) and |
| 56 | (Length(request)<>aAssertions.Count) then |
| 57 | raise ECasbinException.Create |
| 58 | ('The resolve param has more fields than the definition'); |
| 59 | for index:=0 to aAssertions.Count-1 do |
| 60 | Result.Add(UpperCase(aAssertions.Items[index]), |
| 61 | UpperCase(aResolve[index])); |
| 62 | end; |
| 63 | else |
| 64 | raise ECasbinException.Create('Resolve Type not correct'); |
| 65 | end; |
| 66 | end; |
| 67 | |
| 68 | function resolve(const aResolvedRequest, aResolvedPolicy: TDictionary<string, |
| 69 | string>; const aFunctions: IFunctions; const aMatcher: string): |
| 70 | TEffectResult; |
| 71 | var |
| 72 | matcher: IMatcher; |
| 73 | resolvedMatcher: string; |
| 74 | item: string; |
| 75 | args: string; |
| 76 | argsArray: TArray<string>; |
| 77 | endArgsPos: Integer; |
| 78 | startArgsPos: Integer; |
| 79 | startFunPos: Integer; |
| 80 | funcResult: Boolean; |
| 81 | replaceStr: string; |
| 82 | boolReplaceStr: string; |
| 83 | i: Integer; |
| 84 | begin |
| 85 | if not Assigned(aResolvedRequest) then |
| 86 | raise ECasbinException.Create('Resolved Request is nil'); |
| 87 | if not Assigned(aResolvedPolicy) then |
| 88 | raise ECasbinException.Create('Policy Request is nil'); |
| 89 | if not Assigned(aFunctions) then |
| 90 | raise ECasbinException.Create('Functions are nil'); |
| 91 | |
| 92 | resolvedMatcher:=UpperCase(Trim(aMatcher)); |
| 93 | matcher:=TMatcher.Create; |
| 94 | |
| 95 | // We replace first the ABAC related terms because a simple call to Replace |
| 96 | // does not respect whole words |
| 97 | // This assumes ABAC attributes are modeled with two 'dots'. e.g r.obj.owner |
| 98 | for item in aResolvedRequest.Keys do |
| 99 | begin |
| 100 | if item.CountChar('.')=2 then |
| 101 | resolvedMatcher:=resolvedMatcher.Replace |
| 102 | (UpperCase(item), |
| 103 | UpperCase(aResolvedRequest.Items[item]), |
| 104 | [rfIgnoreCase, rfReplaceAll]); |
| 105 | matcher.addIdentifier(UpperCase(aResolvedRequest.Items[item])); |
| 106 | end; |
| 107 | |
| 108 | for item in aResolvedRequest.Keys do |
| 109 | begin |
| 110 | if item.CountChar('.')=1 then |
| 111 | resolvedMatcher:=resolvedMatcher.Replace |
| 112 | (UpperCase(item), |
| 113 | UpperCase(aResolvedRequest.Items[item]), |
| 114 | [rfIgnoreCase, rfReplaceAll]); |
| 115 | |
| 116 | matcher.addIdentifier(UpperCase(aResolvedRequest.Items[item])); |
| 117 | end; |
| 118 | |
| 119 | for item in aResolvedPolicy.Keys do |
| 120 | begin |
| 121 | resolvedMatcher:=resolvedMatcher.Replace |
| 122 | (UpperCase(item), |
| 123 | UpperCase(aResolvedPolicy.Items[item]), |
| 124 | [rfReplaceAll]); |
| 125 | matcher.addIdentifier(UpperCase(aResolvedPolicy.Items[item])); |
| 126 | end; |
| 127 | |
| 128 | //Functions |
| 129 | for item in aFunctions.list do |
| 130 | begin |
| 131 | // We need to match individual words |
| 132 | // This is a workaround to avoid matching individual characters (eg. 'g') |
| 133 | if resolvedMatcher.Contains(UpperCase(item+'(')) or |
| 134 | resolvedMatcher.Contains(UpperCase(item+' (')) then |
| 135 | begin |
| 136 | //We need to find the arguments |
| 137 | startFunPos:=resolvedMatcher.IndexOf(UpperCase(item)); |
| 138 | startArgsPos:=startFunPos+Length(item)+1; |
| 139 | endArgsPos:=resolvedMatcher.IndexOfAny([')'], startArgsPos); |
| 140 | args:= Copy(resolvedMatcher, startArgsPos, endArgsPos-startArgsPos+1); |
| 141 | argsArray:=args.Split([',']); |
| 142 | |
| 143 | for i:=0 to Length(argsArray)-1 do |
| 144 | begin |
| 145 | argsArray[i]:=Trim(argsArray[i]); |
| 146 | if argsArray[i][findStartPos]='(' then |
| 147 | argsArray[i]:=Copy(argsArray[i],findStartPos+1, Length(argsArray[i])); |
| 148 | if argsArray[i][findEndPos(argsArray[i])]=')' then |
| 149 | argsArray[i]:=Copy(argsArray[i], findStartPos, Length(argsArray[i])-1); |
| 150 | end; |
| 151 | |
| 152 | if (UpperCase(item)='G') or (UpperCase(item)='G2') then |
| 153 | funcResult:=aFunctions.retrieveObjFunction(item)(argsArray) |
| 154 | else |
| 155 | funcResult:=aFunctions.retrieveFunction(item)(argsArray); |
| 156 | replaceStr:=UpperCase(item); |
| 157 | if args[findStartPos]<>'(' then |
| 158 | replaceStr:=replaceStr+'('; |
| 159 | replaceStr:=replaceStr+args; |
| 160 | if args[findEndPos(args)]<>')' then |
| 161 | replaceStr:=replaceStr+')'; |
| 162 | |
| 163 | if funcResult then |
| 164 | boolReplaceStr:='100 = 100' |
| 165 | else |
| 166 | boolReplaceStr:='100 = 90'; |
| 167 | |
| 168 | resolvedMatcher:=resolvedMatcher.Replace(replaceStr, boolReplaceStr, |
| 169 | [rfReplaceAll]); |
| 170 | |
| 171 | end; |
| 172 | end; |
| 173 | // Evaluation |
| 174 | Result:=matcher.evaluateMatcher(resolvedMatcher); |
| 175 | end; |
| 176 | |
| 177 | end. |