четверг, 28 января 2010 г.

Чтение прав карточки в сценарии бизнес-процесса

Для решения одного инцидента нам было необходимо фиксировать какой набор прав установлен на карточке в определенный момент времени. Конкретно, в определенных местах бизнес-процесса. Был разработан скрипт, который делает это.


Данные пишутся в журнал бизнес-процесса, соответственно попадают они и в журнал Workflow в режиме отладочных сообщений. Информация выводится в следующем виде:

Карточка документа: CardID
SecurityDescriptor:
Дескриптор безопасности
Пользователь: учетная запись и SID
AccessMask: Маска доступа и расшифровка
AceFlags: флаги
InheritanceFlags:флаги наследования
IsInherited: унаследованные ли права
PropagationFlags: распространение наследования

В скрипте есть недоработка. Строка
Dim oAccountName As NTAccount = DirectCast(oAce.SecurityIdentifier.Translate(GetType(NTAccount)), NTAccount)
может вызвать ошибку в случае если учетка удалена и у неё остался только SID, - в этом случае нельзя получить по SID имя записи. Надо обернуть в Try - Catch.
Скрипт сделан для платформы DocsVision 4.3

Сценарий бизнес-процесса на vb.net:


Option Explicit On
Option Strict On

' подключение системных библиотек
Imports System
Imports System.Xml
Imports System.Security.AccessControl
Imports System.Security.Principal
Imports System.Collections
Imports Microsoft.VisualBasic.Constants
Imports Microsoft.VisualBasic.Strings

' подключение библиотек СУБП
Imports DocsVision.Workflow.Objects
Imports DocsVision.Workflow.Runtime
Imports DocsVision.Workflow.Gates
Imports DocsVision.Platform.HelperAPI
Imports DocsVision.Platform.SecurityManager


Namespace DVScriptHost

    Public Class DVScript
        Dim m_oGate As DVGate
        ' получаем сессию
        Dim m_oSession As DocsVision.Platform.ObjectManager.UserSession
        Dim m_oLastBytes As Byte()

        Private Enum DVRights As Integer

            READ = &H1              ' Чтение, специальное
            WRITE = &H2             ' Изменение
            CREATE_CONTENT = &H4    ' Создание дочерних
            DELETE_CONTENT = &H8    ' Удаление дочерних
            COPY = &H10             ' Копирование

            ' Standard rights
            DELETE = &H10000        ' Удаление
            READ_CONTROL = &H20000  ' Чтение, стандартное
            WRITE_DAC = &H40000     ' Изменение разрешений
            WRITE_OWNER = &H80000   ' Смена владельца
            SYNCHRONIZE = &H100000  ' Не используется

            ACCESS_SYSTEM_SECURITY = &H1000000  ' Изменение параметров безопасности

            ' Generic rights
            GENERIC_ALL = &H10000000        ' Полный доступ
            GENERIC_EXECUTE = &H20000000    ' Выполнение
            GENERIC_WRITE = &H40000000      ' Изменение
            GENERIC_READ = &H80000000       ' Чтение

        End Enum
        Public Sub Execute(ByVal process As ProcessInfo, ByVal passInfo As PassState)

            Try
                ' получаем шлюз
                m_oGate = CType(process.Gates(DVGate.GateID), DVGate)
                ' получаем сессию
                m_oSession = m_oGate.Session

                Dim varDocCard As ProcessVariable
                varDocCard = process.GetVariableByName("Карточка")


                Dim oCard As DVCard = CType(varDocCard.Value, DVCard)

                Dim oAccounts As New ArrayList

                Dim oSecurityDesc As CommonSecurityDescriptor = GetCardDescriptor(process, oCard.ID)

                oAccounts = GetAccountsFromDescriptor(oSecurityDesc)

                process.LogMessage(GetLogMessage(oCard.ID, oAccounts))


            Catch Err As Exception

                ' запись в журнал ошибки исполнения
                process.LogMessage("Ошибка выполнения скрипта:" + Err.Message)

            End Try

        End Sub

        Private Function GetCardDescriptor(ByRef process As ProcessInfo, ByVal CardID As String) As CommonSecurityDescriptor
            Dim oSecureCard As DocsVision.Platform.SecurityManager.ISecureObject = m_oSession.AccessManager.GetSecureCard(CardID)
            Dim oDescBytes As Byte() = DirectCast(oSecureCard.GetSecurity(SecurityInformationEnum.siDacl), Byte())

            ' Получаем объект типа CommonSecurityDescriptor из массива byte() для карточки 
            Dim oSecurityDesc As CommonSecurityDescriptor = New CommonSecurityDescriptor(True, False, oDescBytes, 0)

            m_oLastBytes = oDescBytes
            Return oSecurityDesc

        End Function

        Private Function GetAccountsFromDescriptor(ByVal oSecurityDesc As CommonSecurityDescriptor) As ArrayList
            Dim oAccounts As New ArrayList

            Dim oACL As DiscretionaryAcl = oSecurityDesc.DiscretionaryAcl
            For Each oACE As CommonAce In oACL
                oAccounts.Add(oACE)
            Next
            Return oAccounts
        End Function

        Private Function GetLogMessage(ByVal CardID As String, ByVal oAccounts As ArrayList) As String
            Dim sResult As String = "Карточка документа:" + CardID + vbCrLf
            sResult += "SecurityDescriptor: " + Convert.ToBase64String(m_oLastBytes) + vbCrLf
            For Each oAce As CommonAce In oAccounts
                Dim oAccountName As NTAccount = DirectCast(oAce.SecurityIdentifier.Translate(GetType(NTAccount)), NTAccount)
                sResult += "Пользователь: " + oAccountName.Value.ToString + " (" + oAce.SecurityIdentifier.ToString + ")" + vbCrLf
                sResult += vbTab + "AccessMask:" + vbTab + oAce.AccessMask.ToString + "(" + Decompose(oAce.AccessMask) + ")" + vbCrLf
                sResult += vbTab + "AceFlags:" + vbTab + oAce.AceFlags.ToString + vbCrLf
                sResult += vbTab + "InheritanceFlags:" + vbTab + oAce.InheritanceFlags.ToString + vbCrLf
                sResult += vbTab + "IsInherited:" + vbTab + oAce.IsInherited.ToString + vbCrLf
                sResult += vbTab + "PropagationFlags:" + vbTab + oAce.PropagationFlags.ToString + vbCrLf
            Next

            Return sResult
        End Function

        Private Function Decompose(ByVal iAccessMask As Integer) As String
            Dim sResult As String = vbNullString


            If (iAccessMask And DVRights.ACCESS_SYSTEM_SECURITY) <> 0 Then
                sResult += "+ACCESS_SYSTEM_SECURITY"
            End If



            If (iAccessMask And DVRights.COPY) <> 0 Then
                sResult += "+COPY"
            End If



            If (iAccessMask And DVRights.CREATE_CONTENT) <> 0 Then
                sResult += "+CREATE_CONTENT"
            End If

            If (iAccessMask And DVRights.DELETE) <> 0 Then
                sResult += "+DELETE"
            End If

            If (iAccessMask And DVRights.DELETE_CONTENT) <> 0 Then
                sResult += "+DELETE_CONTENT"
            End If

            If (iAccessMask And DVRights.GENERIC_ALL) <> 0 Then
                sResult += "+GENERIC_ALL"
            End If

            If (iAccessMask And DVRights.GENERIC_EXECUTE) <> 0 Then
                sResult += "+GENERIC_EXECUTE"
            End If

            If (iAccessMask And DVRights.GENERIC_READ) <> 0 Then
                sResult += "+GENERIC_READ"
            End If

            If (iAccessMask And DVRights.GENERIC_WRITE) <> 0 Then
                sResult += "+GENERIC_WRITE"
            End If

            If (iAccessMask And DVRights.READ) <> 0 Then
                sResult += "+READ"
            End If

            If (iAccessMask And DVRights.READ_CONTROL) <> 0 Then
                sResult += "+READ_CONTROL"
            End If

            If (iAccessMask And DVRights.SYNCHRONIZE) <> 0 Then
                sResult += "+SYNCHRONIZE"
            End If

            If (iAccessMask And DVRights.WRITE) <> 0 Then
                sResult += "+WRITE"
            End If

            If (iAccessMask And DVRights.WRITE_DAC) <> 0 Then
                sResult += "+WRITE_DAC"
            End If

            If (iAccessMask And DVRights.WRITE_OWNER) <> 0 Then
                sResult += "+WRITE_OWNER"
            End If

            If sResult <> vbNullString Then sResult = Right(sResult, Len(sResult) - 1)
            Return sResult
        End Function
    End Class

End Namespace


UPD. Убрал лишнее

2 комментария:

  1. А для 4.0 что изменить придется?

    ОтветитьУдалить
  2. в 4.0 нужно изменить строки
    Dim oSecureCard As DocsVision.Platform.SecurityManager.ISecureObject = m_oSession.AccessManager.GetSecureCard(CardID)
    Dim oDescBytes As Byte() = DirectCast(oSecureCard.GetSecurity(SecurityInformationEnum.siDacl), Byte())

    на

    Dim oSecureCard As DocsVision.Platform.ObjectManager.ISecurable = m_oSession.AccessManager.GetSecureCard(CardID)
    Dim oDescBytes As Byte() = DirectCast(oSecureCard.SecurityDescriptor, Byte())

    ОтветитьУдалить