Coverage report for Casbin.Policy.

Generated at 18/02/2019 12:10:19 by DelphiCodeCoverage - an open source tool for Delphi Code Coverage.

Statistics for Casbin.Policy.pas

Number of lines covered450
Number of lines with code gen470
Line coverage95%


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.Policy;
15
16
interface
17
18
uses
19
  Casbin.Core.Base.Types, Casbin.Policy.Types, Casbin.Parser.Types,
20
  Casbin.Parser.AST.Types, Casbin.Adapter.Policy.Types, System.Rtti,
21
  System.Types, System.Classes, Casbin.Model.Sections.Types,
22
  System.Generics.Collections, Casbin.Watcher.Types;
23
24
type
25
  TPolicyManager = class(TBaseInterfacedObject, IPolicyManager)
26
  private
27
    fAdapter: IPolicyAdapter;
28
    fParser: IParser;    //PALOFF
29
    fNodes: TNodeCollection;
30
    fPoliciesList: TList<string>;
31
    fRolesList: TList<string>;
32
    fDomains: TList<string>;
33
    fWatchers: TList<IWatcher>;
34
    fRolesNodes: TObjectDictionary<string, TRoleNode>;
35
    fRolesLinks: TObjectDictionary<string, TStringList>;
36
    procedure loadPolicies;
37
    function findRolesNode(const aDomain, aValue: string): TRoleNode;
38
    function implicitPolicyExists(const aValue, aResource: string): Boolean;
39
    procedure loadRoles;
40
  private
41
{$REGION 'Interface'}
42
    function section (const aSlim: Boolean = true): string;
43
    function toOutputString: string;
44
    function getAdapter: IPolicyAdapter;
45
46
    // Policies
47
    function policies: TList<string>;
48
    procedure load (const aFilter: TFilterArray = []);
49
50
    function policy(const aFilter: TFilterArray = []): string;
51
    procedure clear;
52
    function policyExists(const aFilter: TFilterArray = []): Boolean;
53
    procedure removePolicy(const aFilter: TFilterArray = []; const aRoleMode:
54
        TRoleMode = rmImplicit);
55
    procedure addPolicy (const aSection: TSectionType; const aTag: string;
56
                              const aAssertion: string); overload;
57
    procedure addPolicy (const aSection: TSectionType;
58
                              const aAssertion: string); overload;
59
60
    // Roles
61
    procedure clearRoles;
62
    function roles: TList<string>;
63
    function domains: TList<string>;
64
    function roleExists (const aFilter: TFilterArray = []): Boolean;
65
    procedure addLink(const aBottom: string; const aTop: string); overload;
66
    procedure addLink(const aBottom: string;
67
                      const aTopDomain: string; const aTop: string); overload;
68
    procedure addLink(const aBottomDomain: string; const aBottom: string;
69
                      const aTopDomain: string; const aTop: string); overload;
70
    procedure removeLink(const aLeft, aRight: string); overload;
71
    procedure removeLink(const aLeft: string;
72
                      const aRightDomain: string; const aRight: string);
73
                                                                       overload;
74
    procedure removeLink(const aLeftDomain, aLeft, aRightDomain, aRight: string);
75
        overload;
76
    function linkExists(const aLeft: string; const aRight: string): Boolean;
77
        overload;
78
    function linkExists(const aLeft: string;
79
                      const aRightDomain: string; const aRight: string):boolean;
80
                                                                        overload;
81
    function linkExists(const aLeftDomain: string; const aLeft: string; const
82
        aRightDomain: string; const aRight: string): boolean; overload;
83
    function rolesForEntity(const aEntity: string; const aDomain: string = '';
84
        const aRoleMode: TRoleMode = rmNonImplicit): TStringDynArray;
85
    function entitiesForRole(const aEntity: string; const aDomain: string =''):
86
        TStringDynArray;
87
88
    // Watchers
89
    procedure registerWatcher (const aWatcher: IWatcher);
90
    procedure unregisterWatcher(const aWatcher: IWatcher);
91
    procedure notifyWatchers;
92
93
    //Permissions
94
    function permissionsForEntity(const aEntity: string): TStringDynArray;
95
    function permissionExists (const aEntity: string; const aPermission: string):
96
                                                              Boolean;
97
{$ENDREGION}
98
  public
99
    constructor Create(const aPolicy: string); overload;
100
    constructor Create(const aAdapter: IPolicyAdapter); overload;
101
    constructor Create; overload;
102
    destructor Destroy; override;
103
  end;
104
105
implementation
106
107
uses
108
  Casbin.Adapter.Filesystem.Policy, Casbin.Exception.Types, Casbin.Parser,
109
  Casbin.Core.Utilities, Casbin.Core.Defaults, System.SysUtils,
110
  System.StrUtils, Casbin.Model.Sections.Default, Casbin.Adapter.Memory.Policy,
111
  Casbin.Parser.AST, ArrayHelper, System.RegularExpressions;
112
113
{ TPolicyManager }
114
115
constructor TPolicyManager.Create(const aPolicy: string);
116
begin
117
  Create(TPolicyFileAdapter.Create(aPolicy));
118
end;
119
120
procedure TPolicyManager.addLink(const aBottom, aTop: string);
121
begin
122
  addLink(DefaultDomain, aBottom, DefaultDomain, aTop);
123
end;
124
125
procedure TPolicyManager.addLink(const aBottomDomain, aBottom, aTopDomain,
126
  aTop: string);
127
var
128
  bottomNode: TRoleNode;
129
  topNode: TRoleNode;
130
  IDList: TStringList;
131
begin
132
  bottomNode:=findRolesNode(aBottomDomain, aBottom);
133
  if not Assigned(bottomNode) then
134
  begin
135
    bottomNode:=TRoleNode.Create(aBottom, aBottomDomain);
136
    fRolesNodes.add(bottomNode.ID, bottomNode);
137
  end;
138
139
  topNode:=findRolesNode(aTopDomain, aTop);
140
  if not Assigned(topNode) then
141
  begin
142
    topNode:=TRoleNode.Create(aTop, aTopDomain);
143
    fRolesNodes.add(topNode.ID, topNode);
144
  end;
145
146
  if not fRolesLinks.ContainsKey(bottomNode.ID) then
147
  begin
148
    IDList:=TStringList.Create;
149
    IDList.Sorted:=true;
150
    IDList.CaseSensitive:=False;
151
    fRolesLinks.add(bottomNode.ID, IDList);
152
  end;
153
154
  IDList:=fRolesLinks.Items[bottomNode.ID];
155
156
  if IDList.IndexOf(topNode.id)=-1 then
157
    IDList.add(topNode.ID);
158
159
end;
160
161
procedure TPolicyManager.addPolicy(const aSection: TSectionType;
162
  const aAssertion: string);
163
var
164
  arrStr: TArray<string>;
165
 begin
166
  if trim(aAssertion)='' then
167
    raise ECasbinException.Create('The Assertion is empty');
168
  arrStr:=aAssertion.Split([',']);
169
  if Length(arrStr)<=1 then
170
    raise ECasbinException.Create('The Assertion '+aAssertion+' is wrong');
171
172
  addPolicy(aSection, arrStr[0], string.Join(',', arrStr, 1, Length(arrStr)-1));
173
end;
174
175
procedure TPolicyManager.addPolicy(const aSection: TSectionType; const aTag,
176
  aAssertion: string);
177
begin
178
  if trim(aTag)='' then
179
    raise ECasbinException.Create('The Tag is empty');
180
  if trim(aAssertion)='' then
181
    raise ECasbinException.Create('The Assertion is empty');
182
  if not ((aSection=stDefault) or (aSection=stPolicyRules) or
183
                                            (aSection=stRoleRules)) then
184
    raise ECasbinException.Create('Wrong section type');
185
186
  fAdapter.add(Trim(aTag)+','+trim(aAssertion));
187
  fParser:=TParser.Create(fAdapter.toOutputString, ptPolicy);
188
  fParser.parse;
189
  if fParser.Status=psError then
190
    raise ECasbinException.Create('Parsing error in Model: '+fParser.ErrorMessage);
191
  fNodes:=fParser.Nodes;
192
  loadRoles;
193
  notifyWatchers;
194
end;
195
196
procedure TPolicyManager.addLink(const aBottom, aTopDomain, aTop: string);
197
begin
198
  addLink(DefaultDomain, aBottom, aTopDomain, aTop);
199
end;
200
201
procedure TPolicyManager.clear;
202
begin
203
  fAdapter.clear;
204
end;
205
206
procedure TPolicyManager.clearRoles;
207
begin
208
  fRolesLinks.Clear;
209
  fRolesNodes.Clear;
210
end;
211
212
constructor TPolicyManager.Create(const aAdapter: IPolicyAdapter);
213
begin
214
  if not Assigned(aAdapter) then
215
    raise ECasbinException.Create('Adapter is nil in '+Self.ClassName);
216
  inherited Create;
217
  fAdapter:=aAdapter;
218
  fPoliciesList:=TList<string>.Create;  //PALOFF
219
  fRolesList:=TList<string>.Create;  //PALOFF
220
  fRolesNodes:=TObjectDictionary<string, TRoleNode>.Create([doOwnsValues]);
221
  fRolesLinks:=TObjectDictionary<string, TStringList>.Create([doOwnsValues]);
222
  fDomains:=TList<string>.Create;
223
  fWatchers:=TList<IWatcher>.Create;
224
  loadPolicies;
225
  loadRoles;
226
end;
227
228
constructor TPolicyManager.Create;
229
begin
230
  Create(TPolicyMemoryAdapter.Create);
231
end;
232
233
procedure TPolicyManager.registerWatcher(const aWatcher: IWatcher);
234
begin
235
  if not fWatchers.Contains(aWatcher) then
236
    fWatchers.Add(aWatcher);
237
end;
238
239
procedure TPolicyManager.removeLink(const aLeftDomain, aLeft, aRightDomain,
240
    aRight: string);
241
var
242
  leftNode: TRoleNode;
243
  rightNode: TRoleNode;
244
  index: integer;
245
  list: TStringList;
246
begin
247
  leftNode:=findRolesNode(aLeftDomain, aLeft);
248
  if not Assigned(leftNode) then
249
    Exit;
250
251
  rightNode:=findRolesNode(aRightDomain, aRight);
252
  if not Assigned(rightNode) then
253
    Exit;
254
255
  list:=fRolesLinks.Items[leftNode.ID];
256
  if Assigned(list) then
257
  begin
258
    index:=list.IndexOf(rightNode.ID);
259
    if (index>-1) and (rightNode.Domain=aRightDomain) then
260
      list.Delete(index);
261
  end;
262
end;
263
264
procedure TPolicyManager.removePolicy(const aFilter: TFilterArray = []; const
265
    aRoleMode: TRoleMode = rmImplicit);
266
var
267
  arrString: TArrayRecord<string>;
268
  item: string;
269
  header: THeaderNode;
270
  child: TChildNode;
271
  outStr: string;
272
  itemString: string;
273
  regExp: TRegEx;
274
  match: TMatch;
275
  key: string;
276
  pType: Boolean;
277
begin
278
  arrString:=TArrayRecord<string>.Create(aFilter);
279
280
  itemString:=string.Join(',', aFilter);
281
  while Pos(#32, itemString, findStartPos)<>0 do
282
    Delete(itemString, Pos(#32, itemString, findStartPos), 1);
283
284
  for header in fNodes.Headers do
285
  begin
286
    for child in header.ChildNodes do
287
    begin
288
      outStr:=child.toOutputString;
289
      pType:=UpperCase(outStr).Contains('P=');
290
      outStr:=outStr.Replace('p=',' ');
291
      outStr:=outStr.Replace('g=',' ');
292
      outStr:=outStr.Replace('g2=',' ');
293
      while Pos(#32, outStr, findStartPos)<>0 do
294
        Delete(outStr, Pos(#32, outStr, findStartPos), 1);
295
296
      if arrString.Contains('*') then
297
      begin
298
        key:='^';
299
        for item in arrString do
300
        begin
301
          if item<>'*' then
302
            key:=key+'(?=.*\b'+Trim(item)+'\b)';
303
        end;
304
        key:=key+'.*$';
305
        regExp:=TRegEx.Create(key);
306
        match:=regExp.Match(outStr);
307
        if match.Success then
308
        begin
309
          if (aRoleMode=rmImplicit) or
310
            ((aRoleMode=rmNonImplicit) and (not pType)) then
311
          begin
312
            fAdapter.remove(child.toOutputString.Replace('=',','));
313
            header.ChildNodes.Remove(child);
314
          end;
315
        end;
316
      end
317
      else
318
        if Trim(UpperCase(outStr)) = Trim(UpperCase(itemString)) then
319
        begin
320
          if (aRoleMode=rmImplicit) or
321
            ((aRoleMode=rmNonImplicit) and (not pType)) then
322
          begin
323
            fAdapter.remove(child.toOutputString.Replace('=',','));
324
            header.ChildNodes.Remove(child);
325
          end;
326
        end;
327
    end;
328
  end;
329
  loadRoles;
330
  notifyWatchers;
331
end;
332
333
procedure TPolicyManager.removeLink(const aLeft, aRightDomain, aRight: string);
334
begin
335
  removeLink(DefaultDomain, aLeft, aRightDomain, aRight);
336
end;
337
338
procedure TPolicyManager.removeLink(const aLeft, aRight: string);
339
begin
340
  removeLink(DefaultDomain, aLeft, DefaultDomain, aRight);
341
end;
342
343
destructor TPolicyManager.Destroy;
344
begin
345
  fPoliciesList.Free;
346
  fRolesList.Free;
347
  fRolesLinks.Free;
348
  fRolesNodes.Free;
349
  fDomains.Free;
350
  fWatchers.Free;
351
  inherited;
352
end;
353
354
function TPolicyManager.domains: TList<string>;
355
begin
356
  Result:=fDomains;
357
end;
358
359
function TPolicyManager.entitiesForRole(const aEntity: string; const aDomain:
360
    string =''): TStringDynArray;
361
var
362
  domain: string;
363
  entity: TRoleNode;
364
  id: string;
365
  linkID: string;
366
begin
367
  SetLength(Result, 0);
368
369
  if Trim(aDomain)='' then
370
    domain:=DefaultDomain
371
  else
372
    domain:=Trim(aDomain);
373
374
  for id in fRolesLinks.Keys do
375
  begin
376
    for linkID in fRolesLinks.Items[id] do
377
    begin
378
      if fRolesNodes.ContainsKey(linkID) then
379
      begin
380
        entity:=fRolesNodes.Items[linkID];
381
        if SameText(Trim(UpperCase(entity.Domain)), Trim(UpperCase(domain))) and
382
            SameText(Trim(UpperCase(entity.Value)), Trim(UpperCase(aEntity))) then
383
        begin
384
          SetLength(Result, Length(Result)+1);
385
          Result[Length(Result)-1]:=fRolesNodes.items[id].Value;
386
        end;
387
      end;
388
    end;
389
  end;
390
391
  TArray.Sort<string>(Result);
392
end;
393
394
function TPolicyManager.findRolesNode(const aDomain, aValue: string): TRoleNode;
395
var
396
  node: TRoleNode;
397
  itemNode: TRoleNode;
398
begin
399
  node:=nil;
400
  for itemNode in fRolesNodes.Values do
401
  begin
402
    if SameText(UpperCase(itemNode.Domain), UpperCase(Trim(aDomain))) and
403
          SameText(UpperCase(itemNode.Value), UpperCase(Trim(aValue))) then
404
    begin
405
      node:=itemNode;
406
      Break;
407
    end;
408
  end;
409
  Result := node;
410
end;
411
412
function TPolicyManager.getAdapter: IPolicyAdapter;
413
begin
414
  result:=fAdapter;
415
end;
416
417
function TPolicyManager.implicitPolicyExists(const aValue, aResource: string):
418
    Boolean;
419
var
420
  policyStr: string;
421
begin
422
  Result:=False;
423
  for policyStr in policies do
424
  begin
425
    if UpperCase(policyStr).Contains(Trim(UpperCase(aValue))) and
426
      UpperCase(policyStr).Contains(Trim(UpperCase(aResource))) then
427
    begin
428
      Result:=True;
429
      Break;
430
    end;
431
  end;
432
end;
433
434
function TPolicyManager.linkExists(const aLeft: string; const aRight: string):
435
    Boolean;
436
begin
437
  Result:=linkExists(DefaultDomain, aLeft, DefaultDomain, aRight);
438
end;
439
440
function TPolicyManager.linkExists(const aLeftDomain: string; const aLeft:
441
    string; const aRightDomain: string; const aRight: string): boolean;
442
var
443
  leftNode: TRoleNode;
444
  rightNode: TRoleNode;
445
  item: string;
446
  lDomain,
447
  rDomain,
448
  lItem,
449
  rItem: string;
450
begin
451
  lDomain:=Trim(aLeftDomain);
452
  rDomain:=Trim(aRightDomain);
453
  lItem:=Trim(aLeft);
454
  rItem:=Trim(aRight);
455
{$IFDEF DEBUG}
456
  fAdapter.Logger.log('   Roles for Left: '+lItem);
457
  fAdapter.Logger.log('      Roles: ');
458
  if Length(rolesForEntity(aLeft))=0 then
459
    fAdapter.Logger.log('         No Roles found')
460
  else
461
    for item in rolesForEntity(lItem) do
462
      fAdapter.Logger.log('         '+item);
463
464
  fAdapter.Logger.log('   Roles for Right: '+rItem);
465
  fAdapter.Logger.log('      Roles: ');
466
  if Length(rolesForEntity(rItem))=0 then
467
    fAdapter.Logger.log('         No Roles found')
468
  else
469
    for item in rolesForEntity(rItem) do
470
      fAdapter.Logger.log('         '+item);
471
472
473
{$ENDIF}
474
  Result:=False;
475
476
  if SameText(UpperCase(lDomain), UpperCase(rDomain)) and
477
      SameText(UpperCase(lItem), UpperCase(rItem)) or
478
        (IndexStr(lItem, builtinAccounts)>-1) then
479
  begin
480
    Result:=True;
481
    exit;
482
  end;
483
484
  leftNode:=findRolesNode(lDomain, lItem);
485
  if not Assigned(leftNode) then
486
    Exit;
487
488
  rightNode:=findRolesNode(rDomain, rItem);
489
  if not Assigned(rightNode) then
490
    Exit;
491
492
  if fRolesLinks.ContainsKey(leftNode.ID) then
493
  begin
494
    if fRolesLinks.Items[leftNode.ID].IndexOf(rightNode.ID)>-1 then
495
    begin
496
      Result:=True;
497
      Exit;
498
    end
499
    else
500
    begin
501
      for item in fRolesLinks.Items[leftNode.ID] do
502
      begin
503
        leftNode:=fRolesNodes.Items[item];
504
505
        Result:=linkExists(leftNode.Domain, leftNode.Value,
506
                              rightNode.Domain, rightNode.Value);
507
      end;
508
    end;
509
  end;
510
end;
511
512
function TPolicyManager.linkExists(const aLeft, aRightDomain,
513
  aRight: string): boolean;
514
begin
515
  Result:=linkExists(DefaultDomain, aLeft, aRightDomain, aRight);
516
end;
517
518
procedure TPolicyManager.load(const aFilter: TFilterArray);
519
begin
520
  fAdapter.clear;
521
  fAdapter.load(aFilter);
522
  loadPolicies;
523
  loadRoles;
524
end;
525
526
procedure TPolicyManager.loadPolicies;
527
begin
528
  fPoliciesList.Clear;
529
  fAdapter.clear;
530
  fAdapter.load(fAdapter.Filter);
531
  fParser:=TParser.Create(fAdapter.toOutputString, ptPolicy);
532
  fParser.parse;
533
  if fParser.Status=psError then
534
    raise ECasbinException.Create('Parsing error in Model: '+fParser.ErrorMessage);
535
  fNodes:=fParser.Nodes;
536
end;
537
538
procedure TPolicyManager.loadRoles;
539
var
540
  role: string;
541
  policyItem: string;
542
  roleList: TList<string>;
543
  sectionItem: TSection;
544
  useDomains: Boolean;
545
  tagArrayRec: TArrayRecord<string>;
546
  policyList: TList<string>;
547
begin
548
  useDomains:=False;
549
  clearRoles;
550
551
  // Domains
552
  fDomains.Clear;
553
554
  // We get the Role Rules
555
  sectionItem:=createDefaultSection(stRoleDefinition);
556
  for role in roles do
557
  begin
558
    roleList:=TList<string>.Create;
559
    roleList.AddRange(role.Split([',']));
560
    if roleList.Count>=3 then
561
    begin
562
      tagArrayRec:=TArrayRecord<string>.Create(sectionItem.Tag);
563
      if tagArrayRec.Contains(roleList[0]) then
564
      begin
565
        if roleList.Count=3 then  //No Domains
566
          addLink(roleList[1], roleList[2])
567
        else
568
        if roleList.Count=4 then  //Domains
569
        begin
570
         addLink(roleList[1], roleList[3], roleList[2]);
571
         if (trim(roleList[3])<>DefaultDomain) then
572
           fDomains.Add(trim(roleList[3]));
573
         useDomains:=true;
574
        end
575
        else
576
          raise ECasbinException.Create('The Role Rules are not correct.');
577
      end
578
      else
579
        raise ECasbinException.Create('The Role Rules are not correct.');
580
    end;
581
    roleList.Free;
582
  end;
583
584
  sectionItem.Free;
585
586
  fDomains.Sort;
587
588
  // We now need to transverse the other policy rules to build the links
589
  for policyItem in policies do
590
  begin
591
    tagArrayRec:=TArrayRecord<string>.Create(fDomains.ToArray);
592
    policyList:=TList<string>.Create;
593
    policyList.AddRange(policyItem.Split([',']));
594
    if useDomains then
595
    begin
596
      tagArrayRec.ForEach(procedure(var Value: string; Index: integer)
597
                          var
598
                            domIndex: integer;
599
                          begin
600
                            if policyItem.Contains(Value) then
601
                            begin
602
                              domIndex:=IndexStr(Value, policyList.ToArray);
603
                              if (domIndex-1>=0) and
604
                                    (domIndex+1<=policyList.Count-1) then
605
                                addLink(policyList[domIndex-1], Value,
606
                                          policyList[domIndex+1]);
607
                            end;
608
                          end);
609
    end
610
    else
611
      addLink(policyList[1], policyList[2]);
612
    policyList.Free;
613
  end;
614
end;
615
616
procedure TPolicyManager.notifyWatchers;
617
var
618
  watcher: IWatcher;
619
begin
620
  for watcher in fWatchers do
621
    watcher.update;
622
end;
623
624
function TPolicyManager.permissionExists(const aEntity,
625
  aPermission: string): Boolean;
626
var
627
  permArray: TStringDynArray;
628
  permArrRec: TArrayRecord<string>;
629
begin
630
  permArray:=permissionsForEntity(aEntity);
631
  permArrRec:=TArrayRecord<string>.Create(permArray);
632
  permArrRec.ForEach(procedure(var Value: string; Index: Integer)
633
                     begin
634
                       value:=trim(UpperCase(value));
635
                     end);
636
  Result:=permArrRec.Contains(UpperCase(aPermission));
637
end;
638
639
function TPolicyManager.permissionsForEntity(const aEntity: string):
640
    TStringDynArray;
641
var
642
  policyItem: string;
643
  polArray: TArrayRecord<string>;
644
  tmpArray: TArrayRecord<string>;
645
begin
646
  SetLength(Result, 0);
647
  if Trim(aEntity)<>'' then
648
  begin
649
    for policyItem in policies do
650
    begin
651
      polArray:=TArrayRecord<string>.Create(UpperCase(policyItem).Split([',']));
652
      polArray.ForEach(procedure(var Value: string; Index: Integer)
653
                       begin
654
                         value:=trim(value);
655
                       end);
656
657
      tmpArray:=TArrayRecord<string>.Create(policyItem.Split([',']));
658
      tmpArray.ForEach(procedure(var Value: string; Index: Integer)
659
                       begin
660
                         value:=trim(value);
661
                       end);
662
663
      if polArray.Contains(UpperCase(aEntity)) then
664
      begin
665
        SetLength(Result, Length(Result)+1);
666
        result[Length(Result)-1]:=tmpArray[tmpArray.Count-1];
667
      end;
668
    end;
669
  end;
670
end;
671
672
function TPolicyManager.policies: TList<string>;
673
var
674
  node: TChildNode;
675
  headerNode: THeaderNode;
676
  sectionItem: TSection;
677
  tag: string;
678
  foundTag: Boolean;
679
begin
680
  foundTag:=False;
681
  fPoliciesList.Clear;
682
  fRolesList.Clear;
683
  sectionItem:=createDefaultSection(stPolicyDefinition);
684
  for headerNode in fNodes.Headers do
685
    if (headerNode.SectionType=stPolicyRules) then
686
    begin
687
      for node in headerNode.ChildNodes do
688
      begin
689
        for tag in sectionItem.Tag do
690
          if node.Key=tag then
691
          begin
692
            foundTag:=True;
693
            Break;
694
          end
695
          else
696
            foundTag:=False;
697
        if foundTag then
698
          fPoliciesList.add(node.Key+AssignmentCharForPolicies+node.Value)
699
      end;
700
    end;
701
  sectionItem.Free;
702
  Result:=fPoliciesList;
703
end;
704
705
function TPolicyManager.policy(const aFilter: TFilterArray = []): string;
706
var
707
  i: Integer;
708
  policyItem: string;
709
  test: string;
710
  testPolicy: string;
711
  strArray: TFilterArray;
712
begin
713
  Result:='undefined';
714
715
  //Clean aFilter
716
  strArray:=aFilter;
717
  for i:=0 to Length(strArray)-1 do
718
  begin
719
    strArray[i]:=trim(strArray[i]);
720
  end;
721
  testPolicy:=String.Join(',', strArray);
722
723
  for policyItem in policies do
724
  begin
725
    strArray:=TFilterArray(policyItem.Split([','])); //PALOFF
726
    for i:=0 to Length(strArray)-1 do
727
    begin
728
      strArray[i]:=trim(strArray[i]);
729
    end;
730
    if Length(strArray)>=1 then
731
    begin
732
      test:=String.Join(',', strArray);
733
      if UpperCase(Copy(Trim(test), findStartPos,
734
                    findEndPos(testPolicy)))=UpperCase(Trim(testPolicy)) then
735
      begin
736
        Result:=Trim(strArray[Length(strArray)-1]);
737
        exit;
738
      end;
739
    end;
740
  end;
741
end;
742
743
function TPolicyManager.policyExists(const aFilter: TFilterArray): Boolean;
744
var
745
  policyItem: string;
746
  filterRec: TArrayRecord<string>;
747
  policyRec: TArrayRecord<string>;
748
  outcome: Boolean;
749
  policyStr: string;
750
begin
751
  Result:=False;
752
  if Length(aFilter)=0 then
753
    Exit;
754
755
  filterRec:=TArrayRecord<string>.Create(aFilter);
756
  filterRec.Remove('p');
757
  filterRec.Remove('P');
758
  filterRec.Remove('g');
759
  filterRec.Remove('G');
760
  filterRec.Remove('g2');
761
  filterRec.Remove('G2');
762
  filterRec.ForEach(procedure(var Value: string; Index: Integer)
763
                    begin
764
                      value:=Trim(value);
765
                    end);
766
767
  for policyItem in policies do
768
  begin
769
    policyRec:=TArrayRecord<string>.Create(policyItem.Split([',']));
770
    policyRec.Remove('p');
771
    policyRec.Remove('P');
772
    policyRec.Remove('g');
773
    policyRec.Remove('G');
774
    policyRec.Remove('g2');
775
    policyRec.Remove('G2');
776
    policyRec.ForEach(procedure(var Value: string; Index: Integer)
777
                      begin
778
                        value:=trim(value);
779
                      end);
780
781
    policyStr:=string.Join(',', policyRec.Items);
782
783
    outcome:=true;
784
    filterRec.ForEach(procedure(var Value: string; Index: Integer)
785
                   begin
786
                     outcome:= outcome and
787
                                UpperCase(policyStr).Contains(UpperCase(Value));
788
                   end);
789
    Result:=outcome;
790
791
    if Result then
792
      Break;
793
794
  end;
795
796
  if not Result then
797
    Result:=roleExists(aFilter);
798
end;
799
800
function TPolicyManager.roleExists(const aFilter: TFilterArray): Boolean;
801
var
802
  i: Integer;
803
  ruleItem: string;
804
  test: string;
805
  testRule: string;
806
begin
807
  Result:=False;
808
  if Length(aFilter)=0 then
809
    Exit;
810
811
  testRule:=string.Join(',', aFilter);
812
813
  while Pos(#32, testRule, findStartPos)<>0 do
814
    Delete(testRule, Pos(#32, testRule, findStartPos), 1);
815
816
  if UpperCase(testRule).StartsWith('P,') or
817
       UpperCase(testRule).StartsWith('G,') or
818
         UpperCase(testRule).StartsWith('G2,') then
819
  begin
820
    i:=Pos(',', testRule, findStartPos);
821
    Delete(testRule, findStartPos, i);
822
  end;
823
824
  for ruleItem in roles do
825
  begin
826
    test:=ruleItem;
827
828
    while Pos(#32, test, findStartPos)<>0 do
829
      Delete(test, Pos(#32, test, findStartPos), 1);
830
831
    if UpperCase(test).StartsWith('P,') or
832
         UpperCase(test).StartsWith('G,') or
833
           UpperCase(test).StartsWith('G2,') then
834
    begin
835
      i:=Pos(',', test, findStartPos);
836
      Delete(test, findStartPos, i);
837
    end;
838
839
    Result:=string.Compare(test, testRule, [coIgnoreCase]) = 0;
840
841
    if Result then
842
      Break;
843
844
  end;
845
end;
846
847
function TPolicyManager.roles: TList<string>;
848
var
849
  node: TChildNode;
850
  headerNode: THeaderNode;
851
  sectionItem: TSection;
852
  tag: string;
853
  foundTag: Boolean;
854
begin
855
  foundTag:=False;
856
  fRolesList.Clear;
857
  sectionItem:=createDefaultSection(stRoleDefinition);
858
  for headerNode in fNodes.Headers do
859
    if (headerNode.SectionType=stPolicyRules) then
860
    begin
861
      for node in headerNode.ChildNodes do
862
      begin
863
        for tag in sectionItem.Tag do
864
          if node.Key=tag then
865
          begin
866
            foundTag:=True;
867
            Break;
868
          end
869
          else
870
            foundTag:=False;
871
        if foundTag then
872
          fRolesList.add(node.Key+AssignmentCharForRoles+node.Value)
873
      end;
874
    end;
875
  sectionItem.Free;
876
  Result:=fRolesList;
877
end;
878
879
function TPolicyManager.rolesForEntity(const aEntity: string; const aDomain:
880
    string = ''; const aRoleMode: TRoleMode = rmNonImplicit): TStringDynArray;
881
var
882
  nodeEntity: TRoleNode;
883
  entity: TRoleNode;
884
  domain: string;
885
  id: string;
886
begin
887
  if Trim(aDomain)='' then
888
    domain:=DefaultDomain
889
  else
890
    domain:=Trim(aDomain);
891
892
  nodeEntity:=findRolesNode(domain, aEntity);
893
  if Assigned(nodeEntity) then
894
  begin
895
    if fRolesLinks.ContainsKey(nodeEntity.ID) then
896
    begin
897
      for id in fRolesLinks.Items[nodeEntity.ID] do
898
      begin
899
        entity:=fRolesNodes.Items[id];
900
901
        if (aRoleMode=rmImplicit) then
902
        begin
903
          SetLength(Result, Length(Result)+1);
904
          Result[Length(Result)-1]:=entity.Value;
905
        end
906
        else
907
        if not implicitPolicyExists(aEntity, entity.Value) then
908
        begin
909
          SetLength(Result, Length(Result)+1);
910
          Result[Length(Result)-1]:=entity.Value;
911
        end;
912
      end;
913
    end;
914
  end;
915
916
  TArray.Sort<string>(Result);
917
end;
918
919
function TPolicyManager.section(const aSlim: Boolean): string;
920
var
921
  headerNode: THeaderNode;
922
  strList: TStringList;
923
  policyItem: string;
924
begin
925
  Result:='';
926
  for headerNode in fNodes.Headers do
927
    if headerNode.SectionType=stPolicyRules then
928
    begin
929
      Result:=headerNode.toOutputString;
930
      strList:=TStringList.Create;
931
      strList.Text:=Result;
932
      if (strList.Count>1) then
933
      begin
934
        Result:='';
935
        if aSlim and (strList.Strings[0][findStartPos]='[') then
936
          strList.Delete(0);
937
        for policyItem in strList do
938
          Result:=Result+policyItem+sLineBreak;
939
      end;
940
      strList.Free;
941
      Exit;
942
    end;
943
end;
944
945
function TPolicyManager.toOutputString: string;
946
begin
947
  Result:=section;
948
end;
949
950
procedure TPolicyManager.unregisterWatcher(const aWatcher: IWatcher);
951
begin
952
  if fWatchers.Contains(aWatcher) then
953
    fWatchers.Remove(aWatcher);
954
end;
955
956
end.