Разработка скрипта ЕСИА - Avanpost FAM/MFA+

Общие сведения

Avanpost FAM предоставляет возможность выполнить интеграцию с ЕСИА в качестве источника информации о пользователях.

Помимо стандартного механизма загрузки информации о ФЛ (физическом лице согласно «Методическим рекомендациям по использованию Единой системы идентификации и аутентификации») Avanpost FAM предоставляет возможность реализации сценария чтения и обработки данных из ЕСИА. Этот сценарий расширяет возможности применения интеграции с ЕСИА такими сценариями, как:

  • загрузка и обработка контактных, адресных и других сведений ФЛ ЕСИА;
  • загрузка и обработка информации о документах ФЛ ЕСИА;
  • загрузка и обработка информации об организациях ФЛ ЕСИА;
  • загрузка и обновление данных о членстве УЗ в группах на основе членства в группах ЕСИА.

Текущая инструкция описывает методику разработки сценария загрузки данных из ЕСИА.

Сценарий (скрипт) загрузки информации об аккаунтах разрабатывается на языке ECMAScript 5.1. На языке базируется язык JavaScript, поэтому опыт разработки на языке JavaScript является предпочтительным для решения задачи разработки скрипта чтения данных. 

Предполагается, что разработчик сценария загрузки информации из ЕСИА обладает следующими компетенциями:

  • владение языком программирования ECMAScript 5.1 или JavaScript;
  • понимание механики взаимодействия с ЕСИА и знание «Методических рекомендаций по использованию Единой системы идентификации и аутентификации».

Процесс выполнения скрипта

Сценарий выполняется после получения необходимых токенов (ID Token, Access Token) и является заменой стандартного запроса на Userinfo Endpoint ЕСИА в терминологии OAuth 2.0. При этом сценарий может быть разработан как для однократного выполнения, так и для конвейерной загрузки данных сотрудника (например, при необходимости динамического изменения scopes в составе ряда запросов к Authorization Endpoint ЕСИА).

Схема аутентификации при реализации скрипта загрузки информации из ЕСИА выглядит следующим образом:

  1. Пользователь инициирует аутентификацию в целевое веб-приложение. Пользователь выбирает аутентификацию через ЕСИА.
  2. Avanpost FAM перенаправляет пользователя на Authorization Endpoint ЕСИА с использованием scopes, заданных в соответствующем параметре в настройках провайдера аутентификации ЕСИА.
  3. Пользователь выполняет аутентификацию на стороне ЕСИА, после чего ЕСИА перенаправляет пользователя на Callback Endpoint Avanpost FAM с передачей Code.
  4. Avanpost FAM получает Code и выполняет обмен Code на токены (ID Token, Access Token).

Выполнится сценарий загрузки информации из ЕСИА, настроенный для провайдера. По результатам выполнения сценария анализируется структура, заполненная через вызовы к SetAccounts. Если имеется одна УЗ, связанная с текущим ФЛ ЕСИА, то Avanpost FAM выполняет аутентификацию в эту УЗ. Если УЗ несколько – Avanpost FAM предложит пользователю выбрать одну из имеющихся УЗ. После выбора УЗ пользователь считается аутентифицированным посредством ЕСИА.

Методика разработки скрипта

Для разработки скрипта необходимо, чтобы была выполнена корректная настройка всех параметров на вкладке «Подключение» и были выполнены обязательные настройки на стороне ЕСИА.

Скрипт должен содержать в себе как минимум вызовы функции context.SetAccounts() с целью установки информации о создаваемом или обновляемом аккаунте. Если context.SetAccounts() не установил ни одной УЗ, то пользователь получит сообщение об ошибке аутентификации. Если в context.SetAccounts() установлена одна или несколько УЗ, то будет выполнена их идентификация на основе ключевого атрибута username.  Остальные атрибуты описаны в Приложении 2 текущей инструкции.

Остальные вызовы, которые могут быть реализованы из скрипта, могут содержать в себе вызовы стандартных функций из ECMAScript 5.1 и дополнительных функций, описанных в Приложении 1. Импорт сторонних ES/JS-скриптов из сетевых источников или файлов в рамках сценария недоступен.

После ввода сценария в поле «Скрипт управления пользовательскими данными и разрешениями» осуществляется его отладка. Отладка выполняется посредством выполнения процесса аутентификации через ЕСИА, оценки получаемого с точки зрения пользователя результата и просмотра отладочного журнала. Журнал выполнения аутентификации посредством сценария ЕСИА выводится в стандартный журнал системы, доступный через программу journalctl на сервере системы (например, с помощью bash-команды journalctl -ru idp). При необходимости вывода дополнительных сведений или содержимого переменных можно использовать функцию console.log(), результат выполнения которой будет выведен в системный журнал.

Сценарии использования

Рассмотрен ряд сценариев использования механизма загрузки данных на основе скрипта:

  1. Загрузка информации о ФЛ ЕСИА и формирование одной УЗ.
  2. Загрузка информации об организациях, в которых состоит ФЛ ЕСИА, и формирование нескольких УЗ в системе.

  3. Загрузка информации об организациях, в которых состоит ФЛ ЕСИА, включая ИНН и КПП, и формирование нескольких УЗ в системе.

Загрузка информации о ФЛ ЕСИА и формирование одной УЗ

В сценарии решается задача по базовой загрузке значений некоторых атрибутов ФЛ ЕСИА, в числе которых должны содержаться:

  • ФИО;
  • E-mail адрес;
  • СНИЛС.

В редакторе атрибутов системы создан дополнительный атрибут snils.

Для этого на вкладке «Подключение» провайдера ЕСИА настроены параметры:

  • Scopes – openid fullname email snils.

Разработан и настроен в параметрах интеграции ЕСИА следующий скрипт:

// Загружаем токены
var tokens = context.GetTokens();
var accessToken = tokens.AccessToken;
var sub = tokens.Sub;

// Загружаем профиль ФЛ ЕСИА
var profileUrl = "https://esia-portal1.test.gosuslugi.ru/rs/prns/" + sub;
var profileResponse = context.Send(
    {
        url: profileUrl,
        method: 'GET',
        headers: {
            Accept: ['*/*'],
            Authorization: ['Bearer ' + accessToken]
        }
    });
var profile = JSON.parse(profileResponse.body);

// Загружаем контактные сведения ФЛ ЕСИА (для примера использован URL тестовой ЕСИА)
var contactsUrl = "https://esia-portal1.test.gosuslugi.ru/rs/prns/" + sub + '/ctts' + '?embed=(elements)';
var contactsResponse = context.Send(
    {
        url: contactsUrl,
        method: 'GET',
        headers: {
            Accept: ['*/*'],
            Authorization: ['Bearer ' + accessToken]
        }
    });
var contacts = JSON.parse(contactsResponse.body);

// Обрабатываем контактные сведения ФЛ ЕСИА
for (var contact in contacts.elements) {
    var contactType = contacts['elements'][contact]['type'];
    if (contactType == 'EML') {
        var contactPersonMail = contacts['elements'][contact]['value'];
    }
}

// Создаём или обновляем УЗ в системе, сформированную на основе данных ЕСИА
context.SetAccounts([{
    username: profile.snils, // Формируем логин, используя СНИЛС ФЛ
    firstname: profile.firstName, // Имя
    lastname: profile.lastName, // Фамилия
    middlename: profile.middleName, // Отчество
    email: contactPersonMail, // E-mail
    attributes: {
        "СНИЛС": profile.snils, // СНИЛС
    }
}]);

Загрузка информации об организациях, в которых состоит ФЛ ЕСИА, и формирование нескольких УЗ в системе

В сценарии решается задача загрузки информации об организациях, в которых состоит ФЛ, и получение открытых данных этих организаций, которые не требуют запроса дополнительных scope и согласования пользователем ЕСИА.

В редакторе атрибутов системы создан дополнительный атрибут orgFullName.

Для этого на вкладке «Подключение», провайдера ЕСИА настроены параметры:

  • Scopes – openid fullname snils usr_org.

Разработан и настроен в параметрах интеграции ЕСИА следующий скрипт:

// Заполняем переменные значениями полученных токенов
var tokens = context.GetTokens();
var accessToken = tokens.AccessToken;
var sub = tokens.Sub;

// Загружаем профиль ФЛ ЕСИА
var profileUrl = "https://esia-portal1.test.gosuslugi.ru/rs/prns/" + sub;
var profileResponse = context.Send(
    {
        url: profileUrl,
        method: 'GET',
        headers: {
            Accept: ['*/*'],
            Authorization: ['Bearer ' + accessToken]
        }
    });
var profile = JSON.parse(profileResponse.body);

// Загружаем список организаций, в которых состоит ФЛ ЕСИА
var orgUrl = "https://esia-portal1.test.gosuslugi.ru/rs/prns/" + sub + '/roles';
var orgResponse = context.Send(
    {
        url: orgUrl,
        method: 'GET',
        headers: {
            Accept: ['*/*'],
            Authorization: ['Bearer ' + accessToken]
        }
    });
var org = JSON.parse(orgResponse.body);

// Проходимся по коллекции организаций, в которых числится ФЛ ЕСИА
for (var element in org.elements) {
	var orgFullName = org['elements][element]['fullName']

    // Создаём или обновляем аккаунт сотрудника оргнизации (для каждой организации - отдельный аккаунт)
    context.SetAccounts([{
        username: profile.snils,
        firstname: profile.firstName,
        lastname: profile.lastName,
        middlename: profile.middleName,
        attributes: {
            "orgFullName": orgFullName
        }
    }]);
}

Приложение 1. Спецификация дополнительных функций

ФункцияНазначениеРезультат вызоваПример вызова

context.GetTokens()

Получение коллекции токенов.Возврат именованной структуры, содержащей ключи: 

IdToken, AccessToken, Sub. Эти значения могут потребоваться для выполнения других вызовов.

Пример установки соответствующих значений в переменные:

var tokens = context.GetTokens();
var idToken = tokens.IdToken;
var accessToken = tokens.AccessToken;
var sub = tokens.Sub;

context.SignString('message')

Подпись сертификатом, указанным в значении параметра «Контейнер сертификата (hash)».Возврат значения подписанной строки.

Пример подписи строки и помещения подписанного значения в переменную:

var signedMessage = context.SignString(message)

context.VerifyString('message')

Возврат логического значения, сообщающего о том, удалось ли выполнить проверку сообщения 'message' посредством сертификата ЕСИА, указанного в значении параметра «Файл сертификата ЕСИА».Возврат результата проверки подписи сертификатом ЕСИА.

Пример проверки, что строка действительно подписана сертификатом ЕСИА:

var idVerified = context.VerifyString(message)

context.SetAccounts({...})

Формирование коллекции УЗ, которые должны быть созданы или обновлены после выполнения скрипта.

В результате установлен набор УЗ, которые должны быть созданы или обновлены после выполнения скрипта.

При многократном вызове функции все УЗ накапливаются, в результате чего будет сформировано или обновлено несколько УЗ в соответствии с числом вызовов функции.

Пример установки информации об УЗ в системе:

context.SetAccounts([{
    username: "userLogin",
	firstname: "FirstName",
	lastname: "LastName",
	middlename: "MiddleName",
	email: "userlogin@mail.it",
	mobile: "8999232"
	attributes: {
		"name1":"value1",
		"name2":"value2"
	},
	groups:["group1","group2"],
	roles: ["role1", "role2"]
}]);

context.Send({...})

Отправка HTTP-запроса.Отправка HTTP-запроса и возврат результата выполнения.

Пример загрузки данных из ЕСИА:

var tokens = context.GetTokens()
var accessToken = tokens.AccessToken
var profileResponse = context.Send({
    url: "https://esia-portal1.test.gosuslugi.ru/rs/prns/" + tokens.Sub,
    method: 'GET',
    headers: {
        Accept: ['*/*'],
        Authorization: ['Bearer ' + accessToken]
    }
});
var profile = JSON.parse(profileResponse.body);

context.SetError('message')

Установка сообщения об ошибке для пользователя.Установка сообщения об ошибке, которое будет выведено пользователю.

Пример установки сообщения об ошибке:

context.SetError("script error message");

Приложение 2. Сопоставление атрибутов учётной записи с атрибутами в скрипте

Атрибут профиля пользователяКлюч атрибута в скриптеОсобенности заполнения значения атрибута
Логинusername

Строка, соответствующая требованиям к формированию логина в системе.

Должен быть уникален среди пользователей. В случае наличия значения атрибута username у другой УЗ – существующая УЗ будет обновлена атрибутами, переданными в context.SetAccounts().  

ИмяfirstnameПроизвольная строка.
ФамилияlastnameПроизвольная строка.
ОтчествоmiddlenameПроизвольная строка.
E-mailemail

Стандартный формат E-mail, например "login@domain.ru".

Должен быть уникален среди пользователей системы. В случае наличия значения E-mail у другой УЗ – УЗ создана или обновлена не будет. Идентификация пользователя, формируемого через ЕСИА, по атрибуту email не осуществляется.

ТелефонmobileСтрока в формате номера телефона, например: "89995557744", "8(999)5557744", "8(999)555-77-44", "+79995557744".
Дополнительные атрибутыattributesКоллекция пар ключ-значение с передачей ключей атрибутов и их значений, например, {"attribute1": "value1", "attribute2": "value2"}. Атрибуты профиля пользователя с соответствующими ключами должны быть предварительно созданы в системе.
Группыgroups

Коллекция строк с наименованиями групп, которые должны быть указаны у пользователя, например, ["group1", "group2"]. Группы с соответствующими наименованиями должны быть предварительно созданы в системе. 

Необходимо учитывать, что при передаче этого атрибута все остальные группы, которые были ранее назначены этому пользователю, за исключением явно переданных в параметре groups, будут отозваны.

Обсуждение