При работе с Администрацией одного из районов Астраханской области столкнулись с такой проблемой, а точнее задачей. Глава администрации района работает на iPad и хотел бы подписывать документы ЭЦП через веб-доступ Directum. Но функция подписи документов при работе через iPad оказалась не доступна.
Натолкнувшись на статью «Автоподписание в типовых маршрутах» (http://club.directum.ru/post/Avtopodpisanie-v-tipovykh-marshrutakh.aspx) возникло решение настроить автоподписание документов на сервере.
Для решения задачи в типовом маршруте «Согласование официальных документов», который используется администрацией для отправки документов на подпись Главе, были внесены следующие изменения:
// Инициализация
Параметры = Work.WorkflowParams
ДокументИнф = Параметры.ValueByName("ПисьмоИсходящее").Value
Руководитель = Work.Info.Performer
// Если результат выполнения блока - "Подписано", то проверить наличие ЭЦП
// руководителя
Результат = Work.ExecutionResult.Code
если Результат == Sender.Results.ValueByName('Подписано').Code
// Найти последнюю действующую версию документа
Документ = ДокументИнф.Document
НомерДействВерсии = GetNumVersionEDoc(Документ; EDOC_VERSION_ACTIVE_STAGE_CODE)
если НомерДействВерсии >= 0
// Если нашли подходящую версию, то проверяем подписи
Подписано = CheckUserSignOnEDoc(Документ; Руководитель.Name; НомерДействВерсии)
иначе
Сообщение = 'Должна быть хотя бы одна действующая версия документа!'
Raise(СоздатьИсключение('EDIRNoActiveVersion'; Сообщение; ecWarning))
конецесли
если не Подписано
//проверяем, осуществляется ли доступ через веб и является ли исполнителем задания - Глава
если IsWebRuntimeContext() and Руководитель.ID == 12345 // для идентификации пользователя используется его ИД
Document=Документ
VersionNumber = НомерДействВерсии - 1
SignType = stApproving
//Подписать документ
//Инициализация переменных
CertificateFound = False
CertificateForSignInfo = nil
//Получить список сертификатов
CertificateList = ServiceFactory.GetUserECertificateList(CurrentPerformerUser)
//Получить первый сертификат
CertificateList.Reset
// Пока не достигнут конец списка сертификатов или сертификат не найден
while not (CertificateList.EOF or CertificateFound)
//Получить информацию о сертификате
CertificateForSignInfo = CertificateList.Value
//Проверить тип электронного сертификата: сертификат, предназначенный
//для подписания ЭЦП (ctSignature), или сертификат, предназначенный для подписания
//ЭЦП и для шифрования (ctSignatureEncode), и, что данный сертификат используется по умолчанию
CertificateFound = ((CertificateForSignInfo.CertificateType = ctSignature) or
(CertificateForSignInfo.CertificateType = ctSignatureEncode)) and
CertificateForSignInfo.IsDefault
//Если сертификат не удовлетворяет условиям выше, присвоить переменной CertificateForSignInfo пустой указатель
if not CertificateFound
CertificateForSignInfo = nil
endif
//Перейти к следующему элементу списка сертификатов
CertificateList.Next
endwhile
//Проверить на пустой указатель: если информация о сертификате не найдена, выдать сообщение пользователю
Assert(not VarIsClear(CertificateForSignInfo); Format('У пользователя"%s" отсутствует сертификат для подписания'; CurrentPerformerUser.Name))
//Получить сертификат из БД из компоненты "Пользователи" (открытый ключ)
Certificate = CertificateForSignInfo.ECertificate
//Получить права доступа пользователей к документу
AccessRights = Document.AccessRights
//Проверить права текущего пользователя на подписание ЭД
AccessRights.CheckSign()
// Получить версию для подписания
Version = Document.Versions.Values(VersionNumber)
//Получить список ЭЦП для ЭД. Если ЭД не подписан, список пуст
ListECP=Version.Signatures
//Получить первую подпись ЭД
ListECP.Reset
//Проверить, может соответствующая версия уже подписана соответствующим пользователем соответствующим типом подписи
AlreadySign = FALSE
foreach ECP in ListECP
if ECP.Author.ID = CurrentPerformerUser.ID and ECP.SignatureType = SignType
AlreadySign = TRUE
endif
endforeach
if Not AlreadySign
//Загрузить сертификат из личного хранилища
Certificate.Thumbprint = Certificate.Thumbprint
//Подписать версию ЭД за себя
Version.Sign(Certificate; SignType)
endif
иначе // если доступ осуществляется не через веб или пользователь с ИД не равным 12345, то подписать надо документ вручную
Сообщение = 'Необходимо подписать последнюю действующую версию документа!'
Raise(СоздатьИсключение('EDIRLastVersionNoSigned'; Сообщение; ecWarning))
конецесли
конецесли
конецесли
Таким образом, из статьи «Автоподписание в типовых маршрутах» (http://club.directum.ru/post/Avtopodpisanie-v-tipovykh-marshrutakh.aspx) был заимствован код, из которого были убраны некоторые строки, в т.ч. функции, открывающие диалоговые окна (в режиме веб-доступа интерактивные окна не функционируют). Также добавлена проверка, ведется ли работа через веб-доступ и от имени конкретного пользователя (Главы администрации в нашем случае), чтобы для всех остальных пользователей блок работал в обычном режиме (когда необходимо самим ставить ЭЦП на документы).
Теперь для Главы администрации, когда он работает через iPad, приходит задание о подписании документа ЭЦП, и когда он нажимает на кнопку «Выполнить» - «Подписано», документ автоматически подписывается на сервере от его имени.
Все хорошо кажется, но есть вопрос безопасности - а где на сервере храниться закрытый ключ: на отчуждаемых носителях (etoken, rutoken, дискета) или просто в реестре?
Если просто в реестре, то тут есть дыра в безопасности. Тем более, когда идет речь о подписи министра.
в дальнейшем планируется использовать Rutoken, пока в режиме тестирования функционала хранение ключа в происходит реестре
А можно ли Автоподписать документ в событии завершения блока или в Блоке Сценарий?
Для этого, закрытый сертификат должен быть установлен на сервере WorkFlow.
Но, в этом случае он уязвим, так как в теории воспользоваться им может не только хозяин ключа...
Авторизуйтесь, чтобы написать комментарий