• Ru

Электронная подпись вложений (Attachment Signature)

Обзор

В UniBPM реализован серверный механизм электронной подписи документов (вложений типа Attachment), обеспечивающий:

  • контроль целостности документа
  • фиксацию данных подписанта
  • фиксацию контекста аутентификации
  • неизменяемость подписи
  • возможность последующей проверки

❗️Механизм предназначен для внутреннего корпоративного документооборота и не является квалифицированной электронной подписью (КЭП).


Архитектура подписи

1. Контроль целостности документа

docHash = SHA-256(байты PDF)

Позволяет определить, был ли изменён документ после подписания.


2. Контекст аутентификации (Auth Context)

Формируется JSON-снимок контекста пользователя без сохранения Bearer token.

Вычисляется:

authContextHash = SHA-256(authContextJson)

3. Payload подписи

Формируется канонический JSON:

{
  "signatureId": "...",
  "docId": "...",
  "docHash": "...",
  "signerUserId": "...",
  "signerFullName": "...",
  "signerPosition": "...",
  "signerEmployeeId": "...",
  "signerBusinessUnit": "...",
  "signerLegalEntity": "...",
  "signerRole": "...",
  "signedAt": "...",
  "authContextHash": "...",
  "systemVersion": "1.0.0",
  "signatureAlgorithm": "SHA-256"
}

Вычисляется:

signaturePayloadHash = SHA-256(signaturePayloadJson)

Хранение данных

JSON сохраняется в БД в формате TEXT для обеспечения стабильности хеша.


API

Использование в UI (Filepicker)

Для включения механизма подписи в форме используется компонент filepicker.

Custom Properties

{
  "signature": "true",
  "signerRole": "EMPLOYEE",
  "signatureReadonly": "true"
}
  • signature = true — включает механизм подписи для вложения
  • signerRole — роль подписанта (передаётся на backend при подписании)
  • signatureReadonly = true — режим только просмотра подписи (подписание недоступно)

Поведение компонента

Компонент отображает строку вида:

Не подписано • Подписать • Протокол подписания • Скачать с штампом

Статусы подписи:

  • Не подписано
  • Подписано вами
  • Подписано другим сотрудником
  • Подпись не действительна

Логика:

  • Подписать — доступно, если документ не подписан или подписан другим пользователем и не установлен signatureReadonly = true
  • Протокол подписания — доступно, если есть подписи
  • Скачать с штампом — доступно, если есть подписи

При клике на имя файла выполняется скачивание оригинального документа.

Подписать документ

POST /api/attachment/{id}/sign

Получить список подписей

GET /api/attachment/{id}/signatures

Проверить подписи

GET /api/attachment/{id}/verify


Получить протокол подписи

GET /api/attachment/{id}/signature-protocol

Возвращает PDF-документ с протоколом подписания вложения.

Протокол содержит:

  • сведения о документе (идентификатор, имя файла, размер, тип)
  • сводную таблицу подписей
  • детальную информацию по каждой подписи
  • хэш документа (SHA-256)
  • хэш контекста аутентификации (authContextHash)
  • хэш payload подписи (signaturePayloadHash)
  • JSON контекста аутентификации
  • JSON payload подписи

Документ предназначен для:

  • аудита подписания
  • передачи в архив
  • последующей проверки корректности подписей

Формат ответа: application/pdf


Получить документ со штампом подписей

GET /api/attachment/{id}/signature-stamped

Возвращает исходный PDF-документ с наложенным штампом подписей на последней странице.

Штамп содержит:

  • надпись «Документ подписан электронной подписью (UniBPM)»
  • таблицу подписантов:
    • Подписант
    • Должность
    • Организация
    • Дата и время подписания
  • общее количество подписей
  • хэш документа (SHA-256)

Особенности:

  • штамп накладывается поверх документа без изменения исходного содержимого
  • используется компактное представление, оптимизированное для печати
  • применяется единый акцентный стиль UniBPM
  • поддерживается корректное отображение кириллицы

Формат ответа: application/pdf

Назначение:

  • предоставление пользователю финальной версии документа с подписями
  • визуальное подтверждение подписания
  • передача документа внешним системам и контрагентам

Получить оригинальный документ

GET /api/attachment/read/{id}

Возвращает исходный файл вложения без изменений.

Особенности:

  • используется для скачивания оригинального документа
  • возвращает бинарные данные (blob)
  • применяется в UI при клике на имя файла

Формат ответа: соответствует типу файла (например, application/pdf)


Предварительная настройка Keycloak

Требуемые claims

{
  "signerEmployeeId": "0000-00006",
  "signerLegalEntity": "ООО \"Ромашка\"",
  "signerBusinessUnit": "Административный департамент",
  "signerFullName": "Иванов Иван Иванович",
  "signerPosition": "Генеральный директор"
}

Создание атрибутов

Admin Console → Realm → Realm Settings → User Profile

Создать атрибуты:

  • signerFullName
  • signerPosition
  • signerBusinessUnit
  • signerEmployeeId
  • signerLegalEntity

❗️После создания атрибутов необходимо обеспечить их заполнение и поддержание в актуальном состоянии.


Настройка client scope

Создать client scope и добавить мапперы типа User Attribute → Claim.

Пример для signerFullName:

  • Mapper Type: User Attribute
  • User Attribute: signerFullName
  • Token Claim Name: signerFullName
  • Claim JSON Type: String
  • Add to access token: true
  • Add to ID token: true
  • Add to userinfo: true
  • Multivalued: false

Повторить для остальных атрибутов.


Настройка properties UniBPM

application:
  signature:
    claims:
      mapping:
        full-name: signerFullName
        position: signerPosition
        business-unit: signerBusinessUnit
        employee-id: signerEmployeeId
        legal-entity: signerLegalEntity
    missing-claim-policy: FAIL

Политики:

  • FAIL — подписание запрещено
  • EMPTY — сохраняется пустое значение
  • FALLBACK — используется альтернативное значение

Рекомендуется FAIL.


Гарантии механизма

  • контроль неизменности документа
  • фиксация версии системы
  • фиксация алгоритма подписи
  • проверяемость подписи в будущем

Ограничения

  • Не является квалифицированной ЭП
  • Использует SHA-256
  • Подпись формируется на сервере