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 covered59
Number of lines with code gen67
Line coverage88%


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.