Codeunit 9864 Permission Impl., source in 28

Source242526272829metadata in 28

src/System Application/App/Permission Sets/src/PermissionImpl.Codeunit.al341 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.Security.AccessControl;

using System.Reflection;

codeunit 9864 "Permission Impl."
{
    Access = Internal;
    InherentEntitlements = X;
    InherentPermissions = X;

    var
        AllObjTxt: Label 'All objects of type %1', Comment = '%1= type name, e.g. Table Data or Report or Page';
        AllObjExceptTxt: Label 'All objects of type %1 (except where otherwise stated)', Comment = '%1= type name, e.g. Table Data or Report or Page';
        SelectObjectsLbl: Label 'Select objects to add';
        SelectObjectLbl: Label 'Select object to add';
        PermissionAlreadyExistsWithDifferentTypeErr: Label 'The permission already exists with type %1', Comment = '%1 = the type of the existing permission';
        IncludeOption: Option " ",Yes,Indirect;
        IncludeDescriptionOption: Option "Specifies no permission","Specifies direct permission","Specifies indirect permission";
        ExcludeOption: Option " ",Exclude,"Reduce to indirect";
        ExcludeDescriptionOption: Option "No change to permission","Excludes any permission","Excludes any direct permission";
        PermissionUpdatedLbl: Label 'Tenant %1 permission for the App Id %2, Role %3, ObjectType %4, ObjectId %5  has been updated with the value: "%6", by the UserSecurityId %7.', Locked = true;
        MultiplePermissionsUpdatedLbl: Label 'The tenant permissions for the App Id %1, Role %2, ObjectType %3, ObjectId %4  have been updated with the following values - Read "%5", Insert "%6", Modify "%7" and Delete "%8" by the UserSecurityId %9.', Locked = true;

    procedure SelectPermissions(CurrAppId: Guid; CurrRoleID: Code[20]): Boolean
    var
        TempAllObjWithCaption: Record AllObjWithCaption temporary;
        Objects: Page Objects;
    begin
        SetupObjectsPage(SelectObjectsLbl, Objects, TempAllObjWithCaption);

        if Objects.RunModal() <> Action::LookupOK then
            exit(false);

        Clear(TempAllObjWithCaption);
        Objects.GetSelectedRecords(TempAllObjWithCaption);

        if TempAllObjWithCaption.FindSet() then
            repeat
                AddNewPermission(CurrAppId, CurrRoleID, TempAllObjWithCaption."Object Type", TempAllObjWithCaption."Object ID");
            until TempAllObjWithCaption.Next() = 0;

        exit(true);
    end;

    procedure LookupPermission(ObjectType: Option; var ObjectIDText: Text): Boolean
    var
        TempAllObjWithCaption: Record AllObjWithCaption temporary;
        Objects: Page Objects;
        ObjectID: Integer;
    begin
        TempAllObjWithCaption.SetRange("Object Type", ObjectType);
        TempAllObjWithCaption."Object Type" := ObjectType;
        if Evaluate(ObjectID, ObjectIDText) then
            TempAllObjWithCaption."Object ID" := ObjectID;

        SetupObjectsPage(SelectObjectLbl, Objects, TempAllObjWithCaption);

        if Objects.RunModal() <> Action::LookupOK then
            exit(false);

        Clear(TempAllObjWithCaption);
        Objects.GetRecord(TempAllObjWithCaption);

        ObjectIDText := Format(TempAllObjWithCaption."Object ID");
        exit(true);
    end;

    procedure UpdatePermissionLine(IsTypeChanged: Boolean; var TenantPermission: Record "Tenant Permission"; var ObjectCaption: Text; var ObjectName: Text; var ReadPermissionAsTxt: Text[50]; var InsertPermissionAsTxt: Text[50]; var ModifyPermissionAsTxt: Text[50]; var DeletePermissionAsTxt: Text[50]; var ExecutePermissionAsTxt: Text[50])
    begin
        GetObjectionCaptionAndName(TenantPermission, ObjectCaption, ObjectName);

        if IsTypeChanged then begin
            EmptyIrrelevantPermissionFields(TenantPermission);
            SetDefaultPermissionFields(TenantPermission);
        end;

        ReadPermissionAsTxt := GetPermissionAsTxt(TenantPermission.Type, TenantPermission."Read Permission");
        InsertPermissionAsTxt := GetPermissionAsTxt(TenantPermission.Type, TenantPermission."Insert Permission");
        ModifyPermissionAsTxt := GetPermissionAsTxt(TenantPermission.Type, TenantPermission."Modify Permission");
        DeletePermissionAsTxt := GetPermissionAsTxt(TenantPermission.Type, TenantPermission."Delete Permission");
        ExecutePermissionAsTxt := GetPermissionAsTxt(TenantPermission.Type, TenantPermission."Execute Permission");
    end;

    procedure UpdateSelectedPermissionLines(var TenantPermission: Record "Tenant Permission"; RIMDX: Text[1]; PermissionOption: Option)
    var
        ModifyPermissionLine: Boolean;
    begin
        if TenantPermission.FindSet() then
            repeat
                ModifyPermissionLine := false;
                case RIMDX of
                    'R':
                        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then
                            if TenantPermission."Read Permission" <> PermissionOption then begin
                                TenantPermission."Read Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Read Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                    'I':
                        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then
                            if TenantPermission."Insert Permission" <> PermissionOption then begin
                                TenantPermission."Insert Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Insert Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                    'M':
                        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then
                            if TenantPermission."Modify Permission" <> PermissionOption then begin
                                TenantPermission."Modify Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Modify Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                    'D':
                        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then
                            if TenantPermission."Delete Permission" <> PermissionOption then begin
                                TenantPermission."Delete Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Delete Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                    'X':
                        if TenantPermission."Object Type" <> TenantPermission."Object Type"::"Table Data" then
                            if TenantPermission."Execute Permission" <> PermissionOption then begin
                                TenantPermission."Execute Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Execute Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                    '*':
                        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then begin
                            if (TenantPermission."Read Permission" <> PermissionOption) or
                                (TenantPermission."Insert Permission" <> PermissionOption) or
                                (TenantPermission."Modify Permission" <> PermissionOption) or
                                (TenantPermission."Delete Permission" <> PermissionOption)
                            then begin
                                TenantPermission."Read Permission" := PermissionOption;
                                TenantPermission."Insert Permission" := PermissionOption;
                                TenantPermission."Modify Permission" := PermissionOption;
                                TenantPermission."Delete Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(MultiplePermissionsUpdatedLbl, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Read Permission", TenantPermission."Insert Permission", TenantPermission."Modify Permission", TenantPermission."Delete Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                        end else
                            if TenantPermission."Execute Permission" <> PermissionOption then begin
                                TenantPermission."Execute Permission" := PermissionOption;
                                ModifyPermissionLine := true;
                                Session.LogAuditMessage(StrSubstNo(PermissionUpdatedLbl, RIMDX, TenantPermission."App ID", TenantPermission."Role ID", TenantPermission."Object Type", TenantPermission."Object ID",
                                    TenantPermission."Execute Permission", UserSecurityId()), SecurityOperationResult::Success, AuditCategory::RoleManagement, 2, 0);
                            end;
                end;
                if ModifyPermissionLine then
                    TenantPermission.Modify();
            until TenantPermission.Next() = 0;
    end;

    procedure IsPermissionEmpty(var TenantPermission: Record "Tenant Permission"): Boolean
    begin
        exit(
            (TenantPermission."Execute Permission" = TenantPermission."Execute Permission"::" ") and
           (TenantPermission."Read Permission" = TenantPermission."Read Permission"::" ") and
           (TenantPermission."Insert Permission" = TenantPermission."Insert Permission"::" ") and
           (TenantPermission."Modify Permission" = TenantPermission."Modify Permission"::" ") and
           (TenantPermission."Delete Permission" = TenantPermission."Delete Permission"::" "));
    end;

    procedure VerifyPermissionAlreadyExists(var TenantPermissionRec: Record "Tenant Permission"): Boolean
    var
        TenantPermission: Record "Tenant Permission";
    begin
        if TenantPermission.Get(TenantPermissionRec."App ID", TenantPermissionRec."Role ID", TenantPermissionRec."Object Type", TenantPermissionRec."Object ID") then
            if TenantPermission.Type <> TenantPermissionRec.Type then
                Error(PermissionAlreadyExistsWithDifferentTypeErr, TenantPermission.Type);
    end;

    procedure EmptyIrrelevantPermissionFields(var TenantPermission: Record "Tenant Permission")
    begin
        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then
            TenantPermission."Execute Permission" := TenantPermission."Execute Permission"::" "
        else begin
            TenantPermission."Read Permission" := TenantPermission."Read Permission"::" ";
            TenantPermission."Insert Permission" := TenantPermission."Insert Permission"::" ";
            TenantPermission."Modify Permission" := TenantPermission."Modify Permission"::" ";
            TenantPermission."Delete Permission" := TenantPermission."Delete Permission"::" ";
        end;
    end;

    procedure SetDefaultPermissionFields(var TenantPermission: Record "Tenant Permission")
    begin
        if TenantPermission."Object Type" = TenantPermission."Object Type"::"Table Data" then begin
            TenantPermission."Read Permission" := TenantPermission."Read Permission"::Yes;
            TenantPermission."Insert Permission" := TenantPermission."Insert Permission"::" ";
            TenantPermission."Modify Permission" := TenantPermission."Modify Permission"::" ";
            TenantPermission."Delete Permission" := TenantPermission."Delete Permission"::" ";
        end else
            TenantPermission."Execute Permission" := TenantPermission."Execute Permission"::Yes;
    end;

    procedure GetObjectionCaptionAndName(var TenantPermission: Record "Tenant Permission"; var ObjectCaption: Text; var ObjectName: Text)
    var
        AllObj: Record AllObj;
    begin
        if TenantPermission."Object ID" <> 0 then begin
            TenantPermission.CalcFields("Object Name");
            ObjectCaption := TenantPermission."Object Name";
            ObjectName := '';
            if AllObj.Get(TenantPermission."Object Type", TenantPermission."Object ID") then
                ObjectName := AllObj."Object Name";
        end else begin
            ObjectName := CopyStr(StrSubstNo(AllObjTxt, TenantPermission."Object Type"), 1, MaxStrLen(TenantPermission."Object Name"));
            ObjectCaption := ObjectName;
        end;
    end;

    procedure GetObjectCaptionAndName(var MetadataPermission: Record "Metadata Permission"; var ObjectCaption: Text; var ObjectName: Text)
    var
        AllObj: Record AllObj;
    begin
        if MetadataPermission."Object ID" <> 0 then begin
            MetadataPermission.CalcFields("Object Name");
            ObjectCaption := MetadataPermission."Object Name";
            ObjectName := '';
            if AllObj.Get(MetadataPermission."Object Type", MetadataPermission."Object ID") then
                ObjectName := AllObj."Object Name";
        end else begin
            ObjectName := CopyStr(StrSubstNo(AllObjTxt, MetadataPermission."Object Type"), 1, MaxStrLen(MetadataPermission."Object Name"));
            ObjectCaption := ObjectName;
        end;
    end;

    procedure GetObjectCaptionAndName(var ExpandedPermission: Record "Expanded Permission"; var ObjectCaption: Text; var ObjectName: Text)
    var
        AllObj: Record AllObj;
    begin
        if ExpandedPermission."Object ID" <> 0 then begin
            ExpandedPermission.CalcFields("Object Name");
            ObjectCaption := ExpandedPermission."Object Name";
            ObjectName := '';
            if AllObj.Get(ExpandedPermission."Object Type", ExpandedPermission."Object ID") then
                ObjectName := AllObj."Object Name";
        end else begin
            ObjectName := CopyStr(StrSubstNo(AllObjExceptTxt, ExpandedPermission."Object Type"), 1, MaxStrLen(ExpandedPermission."Object Name"));
            ObjectCaption := ObjectName;
        end;
    end;

    procedure GetObjectName(var ExpandedPermission: Record "Expanded Permission"; var ObjectName: Text)
    begin
        if ExpandedPermission."Object ID" <> 0 then begin
            ExpandedPermission.CalcFields("Object Name");
            ObjectName := ExpandedPermission."Object Name";
        end else
            ObjectName := CopyStr(StrSubstNo(AllObjExceptTxt, ExpandedPermission."Object Type"), 1, MaxStrLen(ExpandedPermission."Object Name"));
    end;

    procedure GetPermission(PermissionType: Option Include,Exclude; PermissionAsTxt: Text): Option " ",Yes,Indirect
    begin
        case PermissionAsTxt of
            Format(IncludeOption::Yes), Format(ExcludeOption::Exclude):
                exit(IncludeOption::Yes);
            Format(IncludeOption::Indirect), Format(ExcludeOption::"Reduce to indirect"):
                exit(IncludeOption::Indirect);
            else
                exit(IncludeOption::" ")
        end;
    end;

    procedure GetPermissionAsTxt(IncludeExcludeOption: Option Include,Exclude; PermissionOption: Option " ",Yes,Indirect) Result: Text[50]
    begin
        if IncludeExcludeOption = IncludeExcludeOption::Exclude then
            case PermissionOption of
                PermissionOption::" ":
                    exit(Format(ExcludeOption::" "));
                PermissionOption::Yes:
                    exit(Format(ExcludeOption::Exclude));
                PermissionOption::Indirect:
                    exit(Format(ExcludeOption::"Reduce to indirect"));
            end
        else
            exit(Format(PermissionOption));
    end;

    procedure FillLookupBuffer(var PermissionLookupBuffer: Record "Permission Lookup Buffer" temporary)
    begin
        if PermissionLookupBuffer.GetFilter("Lookup Type") = '' then
            exit;

        PermissionLookupBuffer.DeleteAll();

        AddOption(1, Format(IncludeOption::" "), Format(IncludeDescriptionOption::"Specifies no permission"), PermissionLookupBuffer."Lookup Type"::Include, PermissionLookupBuffer);
        AddOption(1, Format(ExcludeOption::" "), Format(ExcludeDescriptionOption::"No change to permission"), PermissionLookupBuffer."Lookup Type"::Exclude, PermissionLookupBuffer);
        AddOption(2, Format(IncludeOption::Yes), Format(IncludeDescriptionOption::"Specifies direct permission"), PermissionLookupBuffer."Lookup Type"::Include, PermissionLookupBuffer);
        AddOption(2, Format(ExcludeOption::Exclude), Format(ExcludeDescriptionOption::"Excludes any permission"), PermissionLookupBuffer."Lookup Type"::Exclude, PermissionLookupBuffer);
        AddOption(3, Format(IncludeOption::Indirect), Format(IncludeDescriptionOption::"Specifies indirect permission"), PermissionLookupBuffer."Lookup Type"::Include, PermissionLookupBuffer);
        AddOption(3, Format(ExcludeOption::"Reduce to indirect"), Format(ExcludeDescriptionOption::"Excludes any direct permission"), PermissionLookupBuffer."Lookup Type"::Exclude, PermissionLookupBuffer);
    end;

    local procedure AddOption(RecId: Integer; Caption: Text[50]; Description: Text[100]; LookupType: Option Include,Exclude; var PermissionLookupBuffer: Record "Permission Lookup Buffer" temporary)
    begin
        PermissionLookupBuffer.Init();
        PermissionLookupBuffer.ID := RecId;
        PermissionLookupBuffer."Option Caption" := Caption;
        PermissionLookupBuffer."Option Description" := CopyStr(Description, 1, MaxStrLen(PermissionLookupBuffer."Option Description"));
        PermissionLookupBuffer."Lookup Type" := LookupType;
        PermissionLookupBuffer.Insert();
    end;

    local procedure AddNewPermission(AppId: Guid; RoleId: Code[20]; PermissionObjectType: Option; ObjectID: Integer)
    var
        TenantPermission: Record "Tenant Permission";
    begin
        TenantPermission."App ID" := AppId;
        TenantPermission."Role ID" := RoleId;
        TenantPermission."Object Type" := PermissionObjectType;
        TenantPermission."Object ID" := ObjectID;

        VerifyPermissionAlreadyExists(TenantPermission);
        EmptyIrrelevantPermissionFields(TenantPermission);
        SetDefaultPermissionFields(TenantPermission);

        TenantPermission.Insert();
    end;

    local procedure SetupObjectsPage(PageCaption: Text; var Objects: Page Objects; var TempAllObjWithCaption: Record AllObjWithCaption temporary)
    begin
        Objects.SetTableView(TempAllObjWithCaption);
        Objects.SetObjectTypeVisible(true);
        Objects.SetObjectNameVisible(true);
        Objects.SetObjectCaptionVisible(false);
        Objects.Caption(PageCaption);
        Objects.LookupMode(true);
    end;
}