Working with Access Mask

An access mask is used to grant access permissions on objects, set audit and keep history in relevant properties and methods. This mask is based on values of the MetabaseObjectPredefinedRights enumeration. If specific operations are available for an object, mask value is filled with values of one of the following enumerations:

It is not difficult to create a mask value from values of specified enumerations while granting permissions, setting audit and history. It is necessary to use logical Or to make combinations.

Mask := MetabaseObjectPredefinedRights.Access Or MetabaseObjectPredefinedRights.Delete;

If there is a reverse situation when it is necessary to determine which operations are available by the given mask, it is necessary to write custom function to analyze mask value.

Example 1

Consider the example of mask analysis returned by the GetEffectiveRights method. Mask value is a 4-byte binary number converted to decimal form. To analyze a mask, it is necessary to have a function that makes inverse conversion from decimal into binary form:

Function DecToBin(Value: Double): String;
Var
    i, k: Integer;
    Str, Str2: String;
Begin
    // Take into account 32 bit of the mask, which presence makes the value negative
    If Value < 0 Then
        Str := "1";
        Value := (Value - Integer.MinValue) As Double;
        k := 29 - (Math.Trunc(Math.Log(Value, 2), 0As Integer);
        For i := 0 To k Do
            Str := Str + "0";
        End For;
    End If;
    While Value > 1 Do
        k := (Value - (2 * Math.Quotient(Value, 2))) As Integer;
        Value := Math.Trunc(Value / 20);
        Str := Str + k.ToString;
    End While;
    Str := Str + Value.ToString;
    For i := 0 To Str.Length - 1 Do
        Str2 := Str2 + Str.SubString(Str.Length - i - 11);
    End For;
    Return Str2;
End Function DecToBin;

This function returns a binary number as a character string.

Suppose there is an object with the Obj_1 identifier in the repository. The TestUser user is created in the security manager of the platform.

Create a form and put a button on it. Create the OnClick event handler for a button and write the following code:

Sub Button1OnClick(Sender: Object; Args: IMouseEventArgs);
Var
    MB: IMetabase;
    MDesc: IMetabaseObjectDescriptor;
    SecDesc: ISecurityDescriptor;
    Subj: ISecuritySubject;
    Rights: Integer;
    BinRights: String;
Begin
    MB := MetabaseClass.Active;
    //Security subject
    Subj := MB.Security.ResolveName("TestUser");
    //Object on which effective permissions will be determined for security subject
    MDesc := MB.ItemById("Obj_1");
    SecDesc := MDesc.SecurityDescriptor;
    //Get effective permissions in decimal form
    Rights := SecDesc.GetEffectiveRights(Subj);
    //Display effective permissions in binary form
    BinRights := DecToBin(Rights);
End Sub Button1OnClick;

On clicking the button the Rights variable will contain values corresponding with effective user permissions on a specified object displayed in binary form. The BinRights variable will contain the same value displayed in binary form.

Suppose that only basic and additional operations are available for the Obj_1 object, and the method returned the following value:

Rights := 114440 and BinRights := 11011111100001000. Each mask bit corresponds with one of the operations. If bit value is 0, the operation for the user is undefined (operation value is not set or forbidden). If bit value is 1, operation is allowed for the user.

To compare operations and bits in binary mask, make inverse conversion of each bit particularly into decimal form. Conversion from decimal form into binary form means to raise a number 2 to the power that equals to bit number. Bit numeration starts with 0, at the same time binary number is considered from right to left.

In the specified enumerations each value according to any operation also equals certain power of number 2 (MetabaseObjectPredefinedRights.All = 1 = 2^0; MetabaseObjectPredefinedRights.Print = 16384 = 2^14, and so on.). That is why to check mask bits, raise number 2 to the power that equals to bit number and compare received value with values in enumerations.

To compare values with values of enumerations, write the following function:

Public Function CheckRight(Right: Double): String;
Begin
    Select Case Right
        //Basic permissions
        Case MetabaseObjectPredefinedRights.All:
            Return "All";
        Case MetabaseObjectPredefinedRights.Read:
            Return "Read";
        Case MetabaseObjectPredefinedRights.Write:
            Return "Write";
        Case MetabaseObjectPredefinedRights.Access:
            Return "Access";
        Case MetabaseObjectPredefinedRights.Delete:
            Return "Delete";
        Case MetabaseObjectPredefinedRights.ReadDescr:
            Return "ReadDescr";
        Case MetabaseObjectPredefinedRights.WriteDescr:
            Return "WriteDescr";
        Case MetabaseObjectPredefinedRights.ReadPars:
            Return "ReadPars";
        Case MetabaseObjectPredefinedRights.WritePars:
            Return "WritePars";
        Case MetabaseObjectPredefinedRights.ReadBody:
            Return "ReadBody";
        Case MetabaseObjectPredefinedRights.WriteBody:
            Return "WriteBody";
        Case MetabaseObjectPredefinedRights.Create_:
            Return "Create_";
        //additional permissions
        Case MetabaseObjectPredefinedRights.Print:
            Return "Print";
        Case MetabaseObjectPredefinedRights.ExportData:
            Return "ExportData";
        Case MetabaseObjectPredefinedRights.ImportData:
            Return "ImportData";
        Else
            Return "Unknown rights"
    End Select;
End Function CheckRight;

This function returns its name by operation value. If the passed value is absent among values used in enumerations, the function will return "Unknown rights".

Create an additional procedure to check all bits of a mask.

Sub CheckBits(BinRights: String);
Var
    i: Integer;
    TwoPower: Double;
    c: Char;
Begin
    //Check bits of binary mask
    //Inverse cycle to view a string from right to left
    For i := BinRights.Length To 1 Step - 1 Do
        //As indexing in character string begins with 0 decrement current position by 1
        //It is necessary for correct work of the String.Chars property
        c := BinRights.Chars(i - 1);
        //Bits numbering is from right to left. To get bit number, subtract
        //the current position from general length.
        //Get decimal value for corresponding bit by raising 2 to the power,
        //that equals to bit number.
        TwoPower := Math.Power(2, BinRights.Length - i);
        //If the current bit value is 1, operation is available
        //If the current bit value is 0, the operation is not determined or forbidden
        If c = '1' Then
            Debug.WriteLine("Available operation: " + CheckRight(TwoPower));
        Else
            Debug.WriteLine("Undefined/Forbidden operation: " + CheckRight(TwoPower));
        End If;
    End For;
End Sub CheckBits;

In this procedure, the mask is viewed from right to left. Information about available and not determined operations will be displayed in the development environment console.

It is necessary to add a procedure call in a button click handler:

    //...
    //Get effective permissions in decimal form
    Rights := SecDesc.GetEffectiveRights(Subj);
    //Display effective permissions in binary form
    BinRights := DecToBin(Rights);
    CheckBits(BinRights);
    //...

For specified above mask values (Rights := 114440 and BinRights := 11011111100001000) the following values will be displayed in the development environment console:

Bit number: 0 Undefined/Forbidden operation: All

Bit number: 1 Undefined/Forbidden operation: Read

Bit number: 2 Undefined/Forbidden operation: Write

Bit number: 3 Available operation: Access

Bit number: 4 Undefined/Forbidden operation: Delete

Bit number: 5 Undefined/Forbidden operation: Unknown rights

Bit number: 6 Undefined/Forbidden operation: Unknown rights

Bit number: 7 Undefined/Forbidden operation: Unknown rights

Bit number: 8 Available operation: ReadDescr

Bit number: 9 Available operation: WriteDescr

Bit number: 10 Available operation: ReadPars

Bit number: 11 Available operation: WritePars

Bit number: 12 Available operation: ReadBody

Bit number: 13 Available operation: WriteBody

Bit number: 14 Undefined/Forbidden operation: Print

Bit number: 15 Available operation: ExportData

Bit number: 16 Available operation: ImportData

For 5-7 bits values are unknown because they are not used in enumerations to assign operation.

The CheckRight function can be easily improved to check specific operations depending on object class.

Example 2

The above analyzed example is used to check all access mask bits. If it is required to check existence of permissions for certain operations, it can be done in an easier way. As mask is a binary number, the logical And can be used to check bits values. If the result does not equal to zero, the 1 value is set in a relevant bit, which mean availability of permissions on operation:

Sub UserProc;
Var
    MB: IMetabase;
    MDesc: IMetabaseObjectDescriptor;
    SecDesc: ISecurityDescriptor;
    Subj: ISecuritySubject;
    Rights: Integer;
Begin
    MB := MetabaseClass.Active;
    //Security subject
    Subj := MB.Security.ResolveName("TestUser");
    //Object, on which effective permissions will be determined for security subject
    MDesc := MB.ItemById("Obj_1");
    SecDesc := MDesc.SecurityDescriptor;
    //Get effective permissions in decimal form
    Rights := SecDesc.GetEffectiveRights(Subj);
    //Check availability of permissions to delete object
    If (Rights And MetabaseObjectPredefinedRights.Delete) <> 0 Then
        Debug.WriteLine("Delete allowed");
    Else
        Debug.WriteLine("Delete denied");
    End If;
End Sub UserProc;

See also:

Examples