![]() | ![]() | ![]() |
Предварительная редакция от 29 Июля 2022г.
API мониторинга является расширением ИСО Тополь API интеграции и предназначено для трансляции данных во внешние сервисы.
В отличии от API интеграции, которое нацелено на запросы клиента к серверу, API мониторинга позволяет серверу самостоятельно передавать данные без инициации обмена внешним сервисом
API мониторинга полностью совместимо с API интеграции, используется аналогичный формат передачи данных и структуры их представления, однако API мониторинга обеспечивает не весь функционал API интеграции.
API мониторинга и API интеграции могут использоваться одновременно на одном сервере для параллельной работы с различными подключенными устройствами и сервисами.
Для обмена информацией (без использования шифрования) с внешним сервисом используется протокол HTTP/1.1 в соответствии с RFC 2616 “Hypertext Transfer Protocol -- HTTP/1.1”
https://tools.ietf.org/html/rfc2616
Для обмена информацией с внешним сервисом с использованием шифрования канала передачи данных используется протокол HTTPS в соответствии с RFC 2818 “HTTP Over TLS” https://datatracker.ietf.org/doc/html/rfc2818
Данные между сервером ИСО Тополь и внешним сервисом передаются в одностороннем порядке по инициативе сервера с помощью POST запроса.
Набор передаваемых данных представляет из себя JSON в соответствии с rfc 8259 «The JavaScript Object Notation (JSON) Data Interchange Format»
https://tools.ietf.org/html/rfc8259
Данные поля типа дата (например дата события) передаются в формате POSIX time (Unix epoch) + три регистра для миллисекунд
т.е. например дата 1519220475466 = 1519220475 POSIX (21 Февраля 2018 13:41:15 GMT) + 466 миллисекунд = 21.02.2018 13:41:15:466 GMT
Данные типа UUID представляют из себя уникальный идентификатор, сформированный в соответствии с RFC 4122 «A Universally Unique IDentifier (UUID) URN Namespace» https://tools.ietf.org/html/rfc4122
Передаются UUID в строковом виде в формате, описанном в пункте 3.Namespace Registration Template, «The formal definition of the UUID string representation»
Для авторизации сервера на стороннем сервиса и передачи идентификатора сервера, используются заголовки: - bosid - идентификатор сервера, указанный в переменной SET_SSOI_ID
файла конфигурации - password - пароль сервера, указанный в переменной SET_SSOI_PASSWORD
файла конфигурации
SET_SSOI_ID
может содержать любое текстовое значение в зависимости от требований стороннего сервиса. Рекомендуется использовать текстовое представление UUID в соответствии с пунктом 1.5.2 Формат передачи идентификаторов для обеспечения совместимости между сторонними сервисами и облачной инфраструктурой ИСО
SET_SSOI_PASSWORD
может содержать как сам пароль так и его хэш в зависимости от требований внешнего сервиса.
ВАЖНО! Пароль или хэш пароля хранятся в файле конфигурации в открытом виде, в случае установки сервера ИСО Тополь на оборудование заказчика необходимо предпринять меры по защите файла от несанкционированного доступа
Для повышения уровня безопасности авторизации на внешнем сервисе, возможно использование динамического ключа в поле password. Для этого необходимо установить значение переменной SET_SSOI_PASSWORD_SALT
в значение true в файле конфигурации.
При этом в поле password будет передаваться не значение переменной SET_SSOI_PASSWORD
а SHA-512 хэш с солью, в качестве которой выступает текущее значение системного времени сервера в формате POSIX time (Unix epoch) с нулевым значением текущих секунд. При использование динамического ключа значение SET_SSOI_PASSWORD
передаётся в кодировке Base64
Таким образом ключ изменяется изменяется раз в минуту вместе с солью.
При расшифровке данных внешний сервис должен сравнить известный ему пароль (или хэш пароля, если в переменной SET_SSOI_PASSWORD
указан хэш) с полученным хэшем используя в качестве соли своё системное время, аналогично представленное в формате POSIX time (Unix epoch) с нулевым значением текущих секунд
Пример реализации функции хэширования на языке Java:
private static String getHashSHA(String password, Long timestamp) throws NoSuchAlgorithmException {
if (timestamp == null) { // Метка времени которая используется в качестве соли для пароля сервера Тополь.
// Сторонний сервис должен обеспечивать возможность проверки данных с несколькими метками для корректной
// работы в случае рассинхронизации часов между сервером Тополь и сервером стороннего сервиса
timestamp = Instant.now().getEpochSecond(); // Метка времени обрезается до секунд
}
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); // Подготовка массива байт соли
buffer.putLong(timestamp);
byte[] salt = buffer.array(); // Соль
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); // Дайджест для SHA-512
messageDigest.update(salt); // Заполнение динамическими (солью) данными
byte[] hash = messageDigest.digest(password.getBytes(StandardCharsets.UTF_8)); // Заполнение статическими (паролем) данными
return Base64.getEncoder().encodeToString(hash); // Кодирование в Base64
}
ВАЖНО! Для обеспечения возможности работы динамического ключа, необходимо чтобы внешний сервис позволял рассинхронизацию своего времени со временем сервера как минимум на 1 минуту т.к. посылка данных может быть сформирована в конце минуты и с учётом сетевых задержек быть принятой внешним сервисом в следующую минуту.
Адреса запросов формируются из адреса стороннего сервиса и адреса точки доступа приёмника данных для конкретного типа данных
Сервер позволяет указать адреса трёх разных сторонних сервисов, на которые будет вестись трансляция данных в переменных файла конфигурации SET_SSOI_URL1
, SET_SSOI_URL2
и SET_SSOI_URL3
.
В переменной указывается полный путь с указанием протокола (http или https), ip адреса или доменного имени сервиса и порта для приёма данных, например:
SET_SSOI_URL1=https://cloud.ssoi.ru:30000
SET_SSOI_URL2=https://cloud.npfpol.ru:40000
SET_SSOI_URL3=http://10.42.0.3:33000
По умолчанию данные будут транслироваться на сервис, адрес которого указан в переменной SET_SSOI_URL1
а в случае его недоступности данные будут переданы на сервис SET_SSOI_URL2
. Если сервис SET_SSOI_URL2
так-же окажется недоступен, данные будут переданы на сервис SET_SSOI_URL3
.
Это позволяет организовать отказоустойчивую связь между сервером и внешним сервисом с возможностью резервирования каналов связи и оборудования внешнего сервиса без использования дополнительного оборудования и программного обеспечения.
Попытка обращения к SET_SSOI_URL1
будет осуществляться при каждом новом обмене данными.
В случае если переменная SET_SSOI_URL3
не заполнена, обмен данными будет выполняться только с SET_SSOI_URL1
и SET_SSOI_URL2
, если не заполнена переменная SET_SSOI_URL2
то обмен данными будет выполняться только с SET_SSOI_URL1
.
ВАЖНО! Сервер ИСО Тополь не контролирует когерентность данных на серверах
SET_SSOI_URL1
,SET_SSOI_URL2
иSET_SSOI_URL3
внешнего сервиса, синхронизация данных между ними должна осуществляться на стороне внешнего сервиса
При запуске сервера, ИСО тополь передаёт своё полное состояние отправляя пакет данных в формате идентичном ответу на запрос списка приборов (см. пункт 4. Получение списка приборов в ИСО Тополь API интеграции) в точку доступа JSON_SET_STATE
JSON_SET_STATE = "/json/setstate";
Например, если SET_SSOI_URL1=https://cloud.ssoi.ru:30000
то итоговый POST запрос будет нацелен на https://cloud.ssoi.ru:30000/json/setstate
Аналогично с командой “Получение списка приборов” в “ИСО Тополь API интеграции” передаваемый при статус является актуальной опорной точкой для дальнейшего мониторинга с помощью новых событий, однако существует возможность принудительной синхронизации в двух вариантах, которые могут работать одновременно: - при помощи регулярной отправки пакета статуса - если в файле конфигурации значение переменной SET_SSOI_SEND_STATE_INTERVAL
выставлено больше 0, то полное состояние сервера будет транслироваться с указанным интервалом (в секундах) - при помощи отправки пакета статуса при каждом изменении состоянии системы если переменная SET_SSOI_SEND_STATE_ON_CHANGE
выставлена в значение true в файле конфигурации
ВАЖНО! Стоит учитывать что частая передача пакета статуса приведёт к значительному потреблению трафика. Обратите внимание на пункт 4.2 где описан альтернативный вариант принудительной синхронизации с более легковесным пакетом данных
При запуске сервера, ИСО тополь передаёт полное состояние охраняемых зон в формате идентичном ответу на запрос списка зон (см. пункт 8.1 Получение списка зон в ИСО Тополь API интеграции) в точку доступа JSON_SET_ZONES
JSON_SET_ZONES = "/json/setzones";
Аналогично передаче полного статуса, существует возможность принудительной синхронизации состояния зон в двух вариантах, которые могут работать одновременно: - при помощи регулярной отправки пакета статуса зон - если в файле конфигурации значение переменной SET_SSOI_SEND_ZONES_INTERVAL
выставлено больше 0, то полный статус зон будет транслироваться с указанным интервалом (в секундах) - при помощи отправки пакета статуса зон при каждом изменении их состоянии если переменная SET_SSOI_SEND_ZONES_ON_CHANGE
выставлена в значение true в файле конфигурации
При формировании нового события в системе, оно оценивается по уровню важности (поле level) и если его уровень выше чем указанный в переменной SET_SSOI_LEVEL
то оно попадает в буфер событий для отправки внешнему сервису.
Это позволяет указывать начиная с каких событий вести трансляцию данных и не отсылать события низкой важности. Список уровней приведён в “ИСО Тополь API интеграции”
Размер локального буфера может быть отрегулирован в переменной SET_SSOI_MAX_CACHE
. При удачной передаче события внешнему сервису оно удаляется из буфера. При переполнении буфера формируется событие отсутствия связи с внешним сервисом и новые события перестают приниматься буфером до его частичной очистки при успешном сеансе связи со сторонним сервисом.
Раз в секунду сервер оценивает наличие событий в буфере, и при их наличии инициирует передачу внешнему сервису, обращается к точке
JSON_ADD_EVENT = "/json/addevent";
События передаются в формате JSON аналогично ответу на запрос “4. Получение оперативного списка событий” но сервер самостоятельно следит за индексом последнего переданного события.
Если в конфигурационном файле значение переменной SET_SSOI_EVENTS_ACCEPTS_ARRAY
выставлено в false, то сервер будет передавать по одному событию (от старых к новым) за сеанс, если значение выставлено в true то будут переданы все доступные события в виде массива объектов
Настройка SET_SSOI_SALT в файле конфигурации позволяет включить шифрование всех передаваемых данных в теле запроса независимо от применяемого протокола передачи данных.
Для шифрования данных используется AES в режиме CBC с дополнением PKCS#5
Пример реализации функции расшифровки данных на языке Java:
public static String decrypt(String data, Long timestamp, String password) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
if (timestamp == null) { // Метка времени которая используется в качестве соли для пароля сервера Тополь.
// Сторонний сервис должен обеспечивать возможность проверки данных с несколькими метками для корректной
// работы в случае рассинхронизации часов между сервером Тополь и сервером стороннего сервиса
timestamp = Instant.now().getEpochSecond(); // Метка времени обрезается до секунд
}
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); // Подготовка массива байт соли
buffer.putLong(timestamp);
byte[] salt = buffer.array(); // Соль
byte[] vectorBuffer = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Буфер вектора инициализации
IvParameterSpec vector = new IvParameterSpec(vectorBuffer); // Вектор инициализации
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // PBKDF2-HMAC-SHA256
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); // Длина ключа 256
SecretKey key = keyFactory.generateSecret(keySpec);
SecretKeySpec secretKey = new SecretKeySpec(key.getEncoded(), "AES"); // Ключ
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // Шифр AES в режиме CBC с дополнением PKCS#5
cipher.init(Cipher.DECRYPT_MODE, secretKey, vector);
return new String(cipher.doFinal(Base64.getDecoder().decode(data))); // Преобразование из Base64 и расшифровка
}
Приборы | Фото |
---|---|
Руководство пользователя | ![]() |
Открытое API | ![]() |
API трансляции данных | ![]() |