img3

© 2014 - 2024 esia.pro

Библиотека авторизации через ЕСИА (Java)

1 Общее описание

Библиотека содержит набор функций реализованных на языке программирования Java позволяющих организовать взаимодействие с сервисами Единой системы идентификации и аутентификации (ЕСИА) по протоколу OAuth 2.0. Подробную информацию о данном протоколе и принципах взаимодействия с ЕСИА можно получить в методических рекомендациях по использованию ЕСИА

2 Перечень поставляемых файлов

В состав файлов, поставляемых с библиотекой, входят следующие:

  • oauth2 - директория, в которой содержатся основные файлы библиотеки;
    • scope - директория моделей;
      • org/OrgDetails.java - модель для представления детализованных данных организации;
      • usr/PersonAddress.java - модель для представления данных по адресам пользователя;
      • usr/PersonContact.java - модель для представления контактных данных пользователя;
      • usr/PersonDocument.java - модель для представления данных по документам пользователя;
      • usr/PersonInfo.java - модель для представления базового набора данных о пользователе (ФИО, СНИЛС, ИНН и т.п.);
      • usr/PersonKid.java - модель для представления данных по детям пользователя;
      • usr/PersonOrg.java - модель для представления базового набора данных по организациям пользователя;
      • usr/PersonVehicle.java - модель для представления данных по транспортным средствам пользователя;
    • AccessTokenRefresher.java - интерфейс сервиса обновления маркера доступа;
    • AccessTokenRefresherV1.java - сервис обновления маркера доступа, использующий API V1;
    • AccessTokenRequester.java - интерфейс сервиса запроса маркера доступа;
    • AccessTokenRequesterV1.java - сервис запроса маркера доступа, использующий API V1;
    • AccessTokenRequesterV3.java - сервис запроса маркера доступа, использующий API V3;
    • AccessTokenResponse.java - внутренний класс. Ответ от ЕСИА с результатами аутентификации;
    • AccessTokenVerifier.java - интерфейс сервиса проверки маркера доступа на валидность;
    • AccessType.java - тип доступа к ресурсам (online, offline);
    • AuthService.java - интерфейс сервиса, отвечающий за авторизацию, получение маркера доступа, его обновление и выход;
    • AuthState.java - текущее состояние авторизации, содержит в себе маркер доступа, маркер обновления и информацию о времени истечения маркера доступа:
    • AuthStateStorage.java - интерфейс хранилища авторизационных данных. Обычно для этих целей используется БД (Redis, PostgreSQL …).
    • AuthorizedHttpClient.java - HTTP клиент с поддержкой авторизации. Является обёрткой над простым HTTP клиентом. Его основная задача добавлять заголовок авторизации с маркером доступа и обновлять маркер доступа при необходимости;
    • Configuration.java - конфигурация сервисов библиотеки;
    • DateProvider.java - интерфейс поставщика времени;
    • EsiaAuthService.java - реализация сервиса авторизации для ЕСИА;
    • EsiaDomain.java - основные домены ЕСИА;
    • EsiaException.java - ошибки ЕСИА;
    • EsiaTokenVerifier.java - проверка маркера доступа ЕСИА на валидность. Используемые алгоритмы ГОСТ 3410-2012-256, RSA 256;
    • LoginRequest.java - информация для выполнения запроса авторизации;
    • LoginUrlBuilder.java - интерфейс сервиса формирования URL для запроса авторизационного кода;
    • LoginUrlBuilderV1.java - сервиса формирования URL для запроса авторизационного кода, использующий API V1;
    • LoginUrlBuilderV2.java - сервиса формирования URL для запроса авторизационного кода, использующий API V2;
    • Parameters.java - набор различных констант параметров для авторизации в ЕСИА;
    • PersonInfoService.java - сервис получения пользовательских данных;
    • RealtimeDateProvider.java - поставщик реального времени;
    • StateGenerator.java - интерфейс генератора идентификаторов state;
    • Utils.java - различные вспомогательные функции;
    • UuidStateGenerator.java - state генератор, основанный на UUID;
    • ParametrizedScope.java - разрешение на получения набора данных с поддержкой параметров;
    • BaseScope.java - интерфейс разрешения на получение набора данных;
    • Scope.java - разрешения на предоставляемые наборы данных;
  • crypto - различные классы, связанные с криптографией;
    • CertWithKey.java - структура, содержащая в себе сертификат и приватный ключ;
    • CryptoAlgorithm.java - используемые крипто-алгоритмы;
    • CryptoService.java - интерфейс крипто-сервиса;
    • CryptoServiceJwtAlgorithm.java - внутренний класс. Алгоритм проверки подписи JWT, использующий крипто-сервис для проверки подписи;
    • FileCertLoader.java - загрузка сертификатов и приватных ключей из файлов;
    • HashAlgorithm.java - поддерживаемые алгоритмы хеширования;
    • KeyStoreCertLoader.java - загрузка сертификатов и ключей из keystore в формате PKCS#12 (.pfx, .p12);
    • PemUtils.java - утилиты для работы с PEM форматом;
    • SignAlgorithm.java - поддерживаемые алгоритмы подписания;
    • VerifyAlgorithm.java - поддерживаемые алгоритмы верификации подписи;
    • pem - работа с PEM форматом;
      • PemObject.java - объект из файла формата PEM;
      • PemReader.java - парсер PEM файла;
  • http - классы, связанные с оберткой HTTP клиента;
    • ApacheHttpClient.java - реализация HTTP клиента (Apache);
    • Constants.java - различные константы, используемые с протоколом HTTP;
    • FormUrlCoder.java - формирование URL-encoded строки запроса;
    • HttpClient.java - интерфейс HTTP клиента;
    • HttpClientLogWrapper.java - прокси, который логирует HTTP запросы, проходящие через HTTP клиент;
    • HttpMethod.java - HTTP методы;
    • HttpRequest.java - HTTP запрос;
    • HttpResponse.java - HTTP ответ;
    • Pair.java - пара “ключ-значение”;
    • Params.java - список параметров “ключ-значение”;
  • logging - классы для логирования;
    • LoggerDelegate.java - делегат логирования;
    • Logger.java - внутренний класс. Логгер, который использует предоставленный делегат для вывода сообщений;
    • LogLevel.java - уровни логирования;
  • utils - вспомогательные классы;
    • ArrayUtils.java - вспомогательные функции для массивов;
    • AuthorizationRequiredException.java - исключение, сообщающее о необходимости авторизоваться;
    • BaseException.java - базовый класс исключений библиотеки;
    • DateTimeGsonDeserializer.java - десериализатор даты и времени, приходящих от ЕСИА;
    • ParameterRequiredException.java - исключение о требуемом параметре;
    • Request.java - Адаптер к объекту запроса платформы приложения. Приложение использует некий фреймворк или библиотеку для обработки входящих HTTP запросов. Данный адаптер позволяет из HTTP запроса платформы получить некоторую информацию;
  • bouncycastle
    • BCCryptoProvider.java - провайдер, обеспечивающий создание крипто-сервиса на базе крипто-библиотеки BouncyCastle. Также предоставляет вспомогательные механизмы для загрузки ключей и сертификатов;
    • BCCryptoService.java - реализация крипто-сервиса на базе крипто-библиотеки BouncyCastle;

3 Основные функции

Основными функциями библиотеки авторизации являются:

  • получение авторизационного кода ЕСИА;
  • обмен авторизационного кода на маркер доступа;
  • обмен маркера обновления на маркер доступа (без запроса авторизации пользователя на стороне ЕСИА);
  • получение дополнительных разрешений в процессе работы и переавторизация в ЕСИА при необходимости;
  • получение данных пользователя из ЕСИА (в приложении Б перечислены скоупы, которые может получать базовая и расширенная версии библиотеки);
  • выход (логаут) на стороне ЕСИА;
  • подписание запросов к ЕСИА на основе криптографических средств, установленных на удалённом сервере.

4 Интеграция библиотеки

4.1 Подготовка

Перед началом интеграции необходимо:

  1. настроить для вашей системы HTTPS (это обязательное требование, поскольку данные между вашей системой и ЕСИА передаются в открытом виде);
  2. выполнить экспорт ключевой пары (сформированной по ГОСТ2012) из криптоконтейнера (экспорт можно сделать с помощью нашей утилиты);
  3. настроить систему на технологическом портале тестовой/промышленной ЕСИА. На технологическом портале в окне редактирования параметров системы (см. рисунок 1) указать URL возврата после авторизации и логаута, а также установить алгоритм подписания запросов GOST3410_2012_256.

img1

img2

Рисунок 1 - Поля в окне редактирования параметров системы

  1. В подходящую директорию положить ключ и сертификат в PEM формате (для извлечения ключа и сертификата из криптоконтейнера можно воспользоваться нашей утилитой), сформированные по ГОСТ2012 с длиной ключа 256 бит, и удостовериться, что тот же сертификат загружен на технологическом портале тестовой/промышленной ЕСИА.
  2. В подходящую директорию положить файл сертификата ЕСИА в PEM формате с именем esia-test.crt или esia-prod.crt в зависимости от окружения (тестовое/промышленное), в котором запускается код.
  3. ВАЖНО!!! Настроить доступ к директориям для размещения файлов сертификата, ключа и логов библиотеки таким образом, чтобы их файлы нельзя было получить извне.

4.2 Подключение библиотеки к проекту

Поскольку библиотека поставляется в виде модулей с открытым исходным кодом она может быть интегрирована в кодовую базу любого проекта на Java (при соблюдении требований к зависимостям, которые описаны в разделе 5).

Возможны следующие варианты подключения библиотеки к целевому проекту:

  1. Сборка библиотеки и деплой в репозиторий Maven, подключение к целевому проекту на базе Maven или Gradle в виде зависимости;
  2. Сборка библиотеки в jar и подключение к целевому проекту;
  3. Копирование необходимых файлов исходников и добавление их в целевой проект; ### 4.2.1. Сборка библиотеки и деплой в репозиторий Maven Данный вариант подходит для любых проектов, основанных на Maven либо Gradle.

Необходимые шаги по подключению:

  1. Сборка и публикация:
    1. Публикация в локальный репозиторий разработчика:
./gradlew publishToMavenLocal
  1. Публикация в приватный репозиторий
./gradlew publish -Ppublish.username=”username” -Ppublish.password=”password” -Ppublish.url=”https://maven.example.com/repo”
  1. Добавить в проект зависимость в секцию dependencies:
    1. Для Maven (pom.xml):
<dependency>
  <groupId>ru.rnds.esia</groupId>
  <artifactId>esia-oauth2-core</artifactId>
  <version>2.0</version>
</dependency>
<dependency>
  <groupId>ru.rnds.esia</groupId>
  <artifactId>esia-oauth2-bouncycastle</artifactId>
  <version>2.0</version>
</dependency>
  1. Для Gradle Groovy (build.gradle):
implementation ‘ru.rnds.esia:esia-oauth2-core:2.0’
implementation ‘ru.rnds.esia:esia-oauth2-bouncycastle:2.0’
  1. Для Gradle Kotlin (build.gradle.kts):
implementation(“ru.rnds.esia:esia-oauth2-core:2.0”)
implementation(“ru.rnds.esia:esia-oauth2-bouncycastle:2.0”)

4.2.2 Сборка библиотеки в jar и подключение к целевому проекту;

  1. В корне целевого проекта необходимо создать папку libs
  2. Сборка и публикация библиотек в локальный репозиторий maven в папке libs:
cd esia-oauth2-java
./gradlew -Dmaven.repo.local=/home/user/project/libs publishToMavenLocal
  1. Подключение к проекту:
    1. Maven (pom.xml):
<repositories>
   <repository>
       <id>local</id>
       <url>file://${project.basedir}/libs</url>
   </repository>
</repositories>
<dependencies>
   <dependency>
       <groupId>ru.rnds.esia</groupId>
       <artifactId>esia-oauth2-core</artifactId>
       <version>2.0</version>
   </dependency>
   <dependency>
       <groupId>ru.rnds.esia</groupId>
       <artifactId>esia-oauth2-bouncycastle</artifactId>
       <version>2.0</version>
   </dependency>
</dependencies>
  1. Gradle Groovy (build.gradle):
repositories {
   mavenLocal {
       url "file://${rootProject.rootDir}/libs"
   }
   mavenCentral()
}

dependencies {
   implementation 'ru.rnds.esia:esia-oauth2-core:2.0'
   implementation 'ru.rnds.esia:esia-oauth2-bouncycastle:2.0'
}
  1. Gradle Kotlin (build.gradle.kts):
repositories {
   mavenLocal {
       setUrl("file://${rootProject.rootDir}/libs")
   }
   mavenCentral()
}

dependencies {
   implementation("ru.rnds.esia:esia-oauth2-core:2.0")
   implementation("ru.rnds.esia:esia-oauth2-bouncycastle:2.0")
}

4.2.3 Добавление файлов исходников в целевой проект

В данном варианте подключения предусматривается простое копирование всех необходимых исходников библиотеки в целевой проект в любую папку в src/main/java на усмотрение разработчика.

4.3. Реализация необходимых интеграционных классов

Необходимо реализовать следующие интерфейсы:

  • AuthStateStorage - интерфейс хранилища авторизационных данных
  • Request - адаптер к объекту запроса платформы / фреймворка приложения
  • LoggerDelegate - делегат логирования (не обязательно)
  • HttpClient - HTTP клиент (не обязательно)

AuthStateStorage

При выполнении каждого запроса необходимо получить авторизационные данные, такие как маркер доступа, маркер обновления маркера доступа. Также в процессе запроса маркеры могут быть обновлены и их необходимо сохранить для выполнения последующих запросов. Для этих целей предназначен этот интерфейс. Реализация может хранить данные в сессии пользователя, либо в любом другом хранилище (БД). Важно реализовать механизм блокировки хранилища, так как запросы могут выполняться параллельно и может возникнуть ситуация когда два параллельных запроса начнут одновременно обновлять маркер доступа. Без блокировки последний запрос получит ошибку AuthorizationRequiredException.

Пример реализации данного интерфейса при работе с механизмом сервлетов находится в демонстрационном приложении по пути: sample-app/src/main/java/ru/rndsoft/esia/oauth2/sampleapp/utils/ServletAuthStateStorage.java.

Request

При обработке запроса от ЕСИА об успешной авторизации (handleLoginRedirect) необходимо получение определённых параметров из запроса. Данный интерфейс адаптирует запрос платформы (ServletRequest) для библиотеки.

Пример реализации данного интерфейса при работе с механизмом сервлетов находится в демонстрационном приложении по пути: sample-app/src/main/java/ru/rndsoft/esia/oauth2/sampleapp/utils/ServletRequest.java.

LoggerDelegate

Позволяет реализовать и сконфигурировать извне необходимый механизм логирования сообщений библиотеки.

Пример реализации данного интерфейса при работе с SLF4J находится в демонстрационном приложении по пути: sample-app/src/main/java/ru/rndsoft/esia/oauth2/sampleapp/utils/Slf4JLoggerDelegate.java.

HttpClient

Библиотека использует встроенный Apache HTTP клиент, но при необходимости возможно добавить реализацию основанную на любом другом HTTP клиенте, на том например, который используется в целевом проекте.

Интерфейс HTTP клиента библиотеки находится в core/src/main/java/ru/rndsoft/esia/http/HttpClient.java.

Реализация Apache HTTP клиента находится в core/src/main/java/ru/rndsoft/esia/http/ApacheHttpClient.java.

4.4 Инициализация библиотеки

Способ инициализации зависимостей зависит от используемого фреймворка или платформы целевого приложения. Рассмотрим инициализацию на примере сервлетов.

В результате инициализации будут получены настроенные классы EsiaAuthService и PersonInfoService при помощи которых в дальнейшем будут производиться действия по авторизации и получению персональных данных.

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

Формирование запроса авторизации производится классами LoginUrlBuilderV1 (API v1) и LoginUrlBuilderV2 (API v2), которые реализуют интерфейс LoginUrlBuilder. На данный момент актуальным является API v2. API v1 считается устаревшим и не рекомендуется к использованию.

Получение маркера доступа производится классами AccessTokenRequesterV1 (API v1) и AccessTokenRequesterV3 (API v3), которые реализуют интерфейс AccessTokenRequester. На данный момент актуальным является API v3. API v1 считается устаревшим и не рекомендуется к использованию.

Обновление маркера доступа производится классом AccessTokenRefresherV1 (API v1), который реализуют интерфейс AccessTokenRequester.

Инициализация производится в классе StartStopListener в методе contextInitialized (sample-app/src/main/java/ru/rndsoft/esia/oauth2/sampleapp/StartStopListener.java):

// создаем SLF4J адаптер логов
Slf4JLoggerDelegate loggerDelegate = new Slf4JLoggerDelegate();

String baseUrl = getEnv("BASE_URL", "http://localhost:8080");

// создаем крипто-провайдер BouncyCastle
BCCryptoProvider provider = new BCCryptoProvider();
FileCertLoader fileCertLoader = provider.createFileCertLoader();

// загружаем сертификат ЕСИА для валидации маркера доступа
X509Certificate esiaCert = loadEsiaCert(fileCertLoader);

// Загружаем сертификат и ключ клиента
CertWithKey clientCertWithKey = fileCertLoader.loadCertWithKey(
       requireEnv("CERT_FILE"),
       requireEnv("KEY_FILE")
);

// Создаем крипто-сервис
CryptoService cryptoService = provider.createService(clientCertWithKey, esiaCert);

// Создаем валидатор маркера доступа
AccessTokenVerifier accessTokenVerifier = null;
if (esiaCert != null) {
   accessTokenVerifier = new EsiaTokenVerifier(cryptoService);
}

// Создаем объект конфигурации
configuration = Configuration.builder()
       // используем тестовый домен ЕСИА
       .domain(EsiaDomain.TEST)
       // задаём путь нашего обработчика редиректа из ЕСИА при авторизации
       .loginRedirectUri(String.format("%s/oauth2/login_response", baseUrl))
       // задаём путь нашего обработчика редиректа из ЕСИА при выходе
       .logoutRedirectUri(String.format("%s/oauth2/logout_success", baseUrl))
       // задаём нашу мнемонику в ЕСИА
       .clientId(requireEnv("CLIENT_ID"))
       // задаём необходимые scope для доступа к данным
       .scopes(Scope.FULLNAME, Scope.ID_DOC, Scope.INN, Scope.SNILS, Scope.ADDRESSES,
               Scope.VEHICLES, Scope.USR_ORG, Scope.EMAIL, Scope.MOBILE,
               Scope.KID_FULLNAME, Scope.KID_BIRTHDATE, Scope.KID_INN, Scope.KID_SNILS,
               Scope.KID_GENDER, Scope.KID_BIRTH_CERT_DOC, Scope.KID_MEDICAL_DOC)
       // задаём тип доступа к данным
       .accessType(AccessType.ONLINE)
       // используем созданный крипто-сервис
       .cryptoService(cryptoService)
       // используем созданный верификатор кода доступа
       .accessTokenVerifier(accessTokenVerifier)
       // используем созданный логгер для логирования вывода библиотеки
       .loggerDelegate(loggerDelegate)
       .build();

// создаём сервис авторизации с указанием реализаций формирования запроса авторизации, получения
// авторизационных данных по коду и обновление маркера доступа
AuthService authService = new EsiaAuthService(configuration, new LoginUrlBuilderV2(),
       new AccessTokenRequesterV3(), new AccessTokenRefresherV1());

// создаём сервис получения персональной информации пользователя
PersonInfoService personInfoService = new PersonInfoService(configuration, authService);

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

configuration.close();

4.5 Процесс авторизации в ЕСИА

Получение URL для прохождения авторизации производится вызовом метода createLoginRequest интерфейса AuthService. В результате (LoginRequest) помимо uri также возвращается state (ID состояния запроса), который следует сохранить в сессии пользователя для дальнейшей проверки запроса на возможные атаки CSRF. Если такая проверка не нужна, полученный state можно проигнорировать.

Пример реализации на сервлетах находится в классе LoginServlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
   AuthService service = ServiceLocators.authService.get(getServletContext());
   LoginRequest loginRequest = service.createLoginRequest();
   HttpSession session = request.getSession(true);
   session.setAttribute("state", loginRequest.state);
   response.sendRedirect(loginRequest.uri);
}

После завершения авторизации ЕСИА производит перенаправление на сконфигурированный путь возврата (loginRedirectUri) в котором передает дополнительными параметрами необходимые данные для завершения процесса авторизации на стороне приложения. Обработка данных завершения производится вызовом метода handleLoginRedirect интерфейса AuthService.

Дополнительно, если используется проверка на CSRF, необходимо восстановить идентификатор состояния запроса (state), ранее сохраненный в сессии пользователя, и передать его в вызов метода handleLoginRedirect. Если проверка на CSRF не требуется, в state передается null.

Пример реализации на сервлетах находится в классе OnLoginResponseServlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
   AuthService service = ServiceLocators.authService.get(getServletContext());
   HttpSession session = request.getSession();
   String stateFromSession = (String) session.getAttribute("state");
   try {
       service.handleLoginRedirect(new ServletRequest(request), new ServletAuthStateStorage(session), stateFromSession);
   } catch (EsiaException e) {
       throw new RuntimeException(e);
   }
   if (AdditionalScopeRequester.handleRedirectAfterLogin(request, response))
       return;
   response.sendRedirect("/person_info");
}

4.6 Выход из ЕСИА

Получение URL для выхода (логаута) пользователя производится методом createLogoutUrl интерфейса AuthService. Для выхода следует перенаправить пользователя на полученный URL, также стоит зачистить объект сессии пользователя.

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

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
   AuthService service = ServiceLocators.authService.get(getServletContext());
   HttpSession session = request.getSession();
   if (session != null)
       session.invalidate();
   String logoutUrl = service.createLogoutUrl();
   response.sendRedirect(logoutUrl);
}

После завершения процесса выхода ЕСИА производит перенаправление на сконфигурированный путь возврата (logoutRedirectUri). Обработка завершения производится вызовом метода handleLogoutRedirect интерфейса AuthService.

Пример реализации на сервлетах находится в классе OnLogoutSuccessServlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   AuthService service = ServiceLocators.authService.get(getServletContext());
   service.handleLogoutRedirect(new ServletAuthStateStorage(request.getSession()));
   request.getRequestDispatcher("/logout_success.jsp").forward(request, response);
}

4.7 Обновление маркера доступа

Маркер доступа обновляется автоматически при любых запросах маркера доступа методами getAccessToken или requireAccessToken интерфейса AuthService. Для принудительного обновления маркера доступа используется метод refreshAccessToken. Стоит отметить, что в продуктовой эксплуатации явный вызов этого метода не требуется, он предназначен исключительно для тестирования.

Пример реализации обновления маркера доступа находится в классе OnRefreshTokenServlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
   AuthService service = ServiceLocators.authService.get(getServletContext());
   HttpSession session = request.getSession();
   try {
       service.refreshAccessToken(new ServletAuthStateStorage(session));
   } catch (AuthorizationRequiredException e) {
       throw new RuntimeException(e);
   }
   response.sendRedirect("/person_info");
}

4.8 Получение дополнительных разрешений

Для получения некоторых наборов данных необходимо получение дополнительных разрешений с указанием идентификаторов полученных в процессе запросов (например при запросе детальной информации об организации). Для этих целей служит метод requestScopes в интерфейсе AuthService.

При запросе доп. разрешений в случае, если у пользователя ещё этих разрешений нет, формируется URL на прохождении авторизации. Приложению следует перенаправить пользователя на этот URL. Далее процесс проходит аналогично с обычной авторизацией.

Пример реализации запроса дополнительных разрешений находится в классе AdditionalScopeRequester:

public static boolean request(AuthService authService,
                             AuthStateStorage storage,
                             HttpServletRequest request,
                             HttpServletResponse response,
                             String... scopes) throws AuthorizationRequiredException, IOException {
   @Nullable LoginRequest loginRequest = authService.requestScopes(storage, scopes);
   if (loginRequest == null) return false;
   HttpSession session = request.getSession();
   String uri = request.getRequestURI();
   String query = request.getQueryString();
   if (query != null && !query.isEmpty()) {
       uri = uri + "?" + query;
   }
   session.setAttribute(REDIRECT_AFTER_LOGIN_ATTR, uri);
   session.setAttribute("state", loginRequest.state);
   response.sendRedirect(loginRequest.uri);
   return true;
}

Пример использования AdditionalScopeRequester находится в классе OrgDetailsServlet:

if (AdditionalScopeRequester.request(authService, storage, request, response,
       Stream.of(Scope.ORG_FULLNAME, Scope.ORG_SHORTNAME, Scope.ORG_ADDRS, Scope.ORG_TYPE,
               Scope.ORG_OGRN, Scope.ORG_INN, Scope.ORG_KPP, Scope.ORG_LEG, Scope.ORG_AGENCYTYPE,
               Scope.ORG_EMPS, Scope.ORG_BRHS
       ).map(s -> s.addParam("org_oid", orgId)).collect(Collectors.toList())
)) return;

4.9 Получение персональных данных

За получение персональных данных отвечает класс PersonInfoService. Данный сервис предоставляет следующие методы для получения данных:

  • getPersonId - получение идентификатора пользователя;
  • getPersonInfo - получение персональной информации (ФИО, СНИЛС, гражданство, пол, дату, место рождения и т.д.);
  • getPersonDocuments - документы пользователя (паспорт, водительские права и т.д.);
  • getPersonContacts - контактные данные пользователя (телефон, email);
  • getPersonOrgs - сводные данные об организациях, сотрудником которых является пользователь;
  • getPersonAddesses - список адресов пользователя;
  • getPersonKids - перечень записей о детях физ. лица;
  • getPersonKidDocuments - список документов ребенка;
  • getPersonVehicles - список зарегистрированных транспортных средств пользователя;
  • getOrgDetails - получение детальной информации об организации пользователя. Необходимо получение дополнительного разрешения.

Пример получения информации находится в классах PersonInfoServlet:

AuthService authService = ServiceLocators.authService.get(request.getServletContext());
ServletAuthStateStorage storage = new ServletAuthStateStorage(request.getSession());
PersonInfoService personInfoService = ServiceLocators.personInfoService.get(request.getServletContext());
PersonInfoService.Requester requester = personInfoService.getRequester(storage);
String personId = requester.getPersonId();
PersonInfo personInfo = requester.getPersonInfo(personId);
PersonDocument[] documents = requester.getPersonDocuments(personId);
PersonContact[] contacts = requester.getPersonContacts(personId);
PersonAddress[] addresses = requester.getPersonAddresses(personId);
PersonKid[] kids = requester.getPersonKids(personId);
Map<String, PersonDocument[]> kidsDocuments = Arrays.stream(kids).collect(Collectors.toMap(PersonKid::getId, k -> {
   try {
       return requester.getPersonKidDocuments(personId, k.getId());
   } catch (IOException | AuthorizationRequiredException | EsiaException e) {
       throw new RuntimeException(e);
   }
}));

PersonVehicle[] vehicles = requester.getPersonVehicles(personId);
PersonOrg[] orgs = requester.getPersonOrgs(personId);
request.setAttribute("personInfo", personInfo);
request.setAttribute("contacts", contacts);
request.setAttribute("documents", documents);
request.setAttribute("addresses", addresses);
request.setAttribute("kids", kids);
request.setAttribute("kidsDocuments", kidsDocuments);
request.setAttribute("vehicles", vehicles);
request.setAttribute("personOrgs", orgs);
request.setAttribute("authState", gson.toJson(storage.getState(), AuthState.class));
request.setAttribute("scopes", authService.getScopes(storage));

request.getRequestDispatcher("/person_info.jsp").forward(request, response);

И OrgDetailsServlet:

PersonInfoService personInfoService = ServiceLocators.personInfoService.get(request.getServletContext());
PersonInfoService.Requester requester = personInfoService.getRequester(storage);
OrgDetails orgDetails = requester.getOrgDetails(orgId);

request.setAttribute("orgDetails", orgDetails);

request.getRequestDispatcher("/org_details.jsp").forward(request, response);

5 Зависимости

Библиотека авторизации предъявляет следующие языковые требования

Java >= 8

Также в случае интеграции с копированием исходников в проект (п. 4.2.3) для работы библиотеки авторизации должны быть прописаны следующие зависимости:

  • org.jetbrains:annotations:16.0.2
  • org.apache.httpcomponents:httpclient:4.5.13
  • com.auth0:java-jwt:4.0.0
  • com.google.code.gson:gson:2.9.1
  • org.bouncycastle:bcprov-jdk18on:1.72
  • org.bouncycastle:bcpkix-jdk18on:1.72

ПРИЛОЖЕНИЕ А.
Описание конфигурационных параметров

Библиотека авторизации принимает на вход набор параметров (класс Configuration), описанных в таблице А.1.

Таблица А.1. - Описание параметров

Наименование параметра Обязательный Описание параметра
1 domain да URL системы - поставщика услуг (ЕСИА)
2 clientId да Мнемоника, полученная при регистрации ИС в минкомсвязи
3 loginRedirectUri да Определяет адрес возврата в ИС после авторизации пользователя в ЕСИА
4 logoutRedirectUri нет Определяет адрес возврата в ИС после логаута пользователя в ЕСИА
5 scopes, customScopes нет Перечень областей данных, к которым предоставляется доступ для ИС после авторизации
6 accessType да Определяет тип доступа к защищенному хранилищу ЕСИА предоставляемому для ИС
7 accessTokenVerifier нет Определяет реализацию проверки маркера доступа
8 loggerDelegate нет Определяет реализацию логирования
9 dateProvider нет Определяет реализацию поставщика текущего времени
10 stateGenerator нет Определяет реализацию генератора идентификаторов для state
11 httpClient нет Определяет реализацию HttpClient
12 cryptoService да Определяет крипто-сервис

Пример формирования конфигурационного объекта, задающего необходимый набор параметров для библиотеки, приведен ниже.

Для тестовой среды ЕСИА:

// Создаем объект конфигурации
configuration = Configuration.builder()
       // используем тестовый домен ЕСИА
       .domain(EsiaDomain.TEST)
       // задаём путь нашего обработчика редиректа из ЕСИА при авторизации
       .loginRedirectUri(String.format("%s/oauth2/login_response", baseUrl))
       // задаём путь нашего обработчика редиректа из ЕСИА при выходе
       .logoutRedirectUri(String.format("%s/oauth2/logout_success", baseUrl))
       // задаём нашу мнемонику в ЕСИА
       .clientId(requireEnv("CLIENT_ID"))
       // задаём необходимые scope для доступа к данным
       .scopes(Scope.FULLNAME, Scope.ID_DOC, Scope.INN, Scope.SNILS, Scope.ADDRESSES,
               Scope.VEHICLES, Scope.USR_ORG, Scope.EMAIL, Scope.MOBILE,
               Scope.KID_FULLNAME, Scope.KID_BIRTHDATE, Scope.KID_INN, Scope.KID_SNILS,
               Scope.KID_GENDER, Scope.KID_BIRTH_CERT_DOC, Scope.KID_MEDICAL_DOC)
       // задаём тип доступа к данным
       .accessType(AccessType.ONLINE)
       // используем созданный крипто-сервис
       .cryptoService(cryptoService)
       // используем созданный верификатор кода доступа
       .accessTokenVerifier(accessTokenVerifier)
       // используем созданный логгер для логирования вывода библиотеки
       .loggerDelegate(loggerDelegate)
       .build();

Для промышленной среды ЕСИА:

// Создаем объект конфигурации
configuration = Configuration.builder()
       // используем продуктовый домен ЕСИА
       .domain(EsiaDomain.PROD)
       // задаём путь нашего обработчика редиректа из ЕСИА при авторизации
       .loginRedirectUri(String.format("%s/oauth2/login_response", baseUrl))
       // задаём путь нашего обработчика редиректа из ЕСИА при выходе
       .logoutRedirectUri(String.format("%s/oauth2/logout_success", baseUrl))
       // задаём нашу мнемонику в ЕСИА
       .clientId(requireEnv("CLIENT_ID"))
       // задаём необходимые scope для доступа к данным
       .scopes(Scope.FULLNAME, Scope.ID_DOC, Scope.INN, Scope.SNILS, Scope.ADDRESSES,
               Scope.VEHICLES, Scope.USR_ORG, Scope.EMAIL, Scope.MOBILE,
               Scope.KID_FULLNAME, Scope.KID_BIRTHDATE, Scope.KID_INN, Scope.KID_SNILS,
               Scope.KID_GENDER, Scope.KID_BIRTH_CERT_DOC, Scope.KID_MEDICAL_DOC)
       // задаём тип доступа к данным
       .accessType(AccessType.ONLINE)
       // используем созданный крипто-сервис
       .cryptoService(cryptoService)
       // используем созданный верификатор кода доступа
       .accessTokenVerifier(accessTokenVerifier)
       // используем созданный логгер для логирования вывода библиотеки
       .loggerDelegate(loggerDelegate)
       .build();

ПРИЛОЖЕНИЕ Б.
Перечень запрашиваемых областей доступа

Перечень областей данных (scope) библиотеки приведен в таблице Б.1.

Таблица Б.1. - Перечень запрашиваемых областей доступа

Название scope Состав набора данных Запрашивается(+)/Не запрашивается(-)
1. fullname Просмотр фамилии, имени и отчества:
• фамилия;
• имя;
• отчество.
+
2. birthdate дата рождения, указанная в учетной записи +
3. gender пол, указанный в учетной записи +
4. snils СНИЛС, указанный в учетной записи +
5. inn ИНН, указанный в учетной записи +
6. id_doc Просмотр данных о документе, удостоверяющем личность:
• серия и номер документа, удостоверяющего личность;
• дата выдачи;
• кем выдан;
• код подразделения;
• гражданство.
+
7. birthplace место рождения. +
8. medical_doc Просмотр данных полиса ОМС:
• номер полиса ОМС;
• срок действия.
+
9. military_doc Просмотр данных военного билета:
• серия и номер военного билета;
• дата выдачи;
• орган, выдавший документ.
+
10. foreign_passport_doc Просмотр данных заграничного паспорта:
• фамилия, имя, отчество буквами латинского алфавита;
• серия и номер заграничного паспорта;
• дата выдачи;
• срок действия;
• орган, выдавший документ;
• гражданство.
+
11. drivers_licence_doc Просмотр данных водительского удостоверения:
• серия и номер водительского удостоверения;
• дата выдачи;
• срок действия.
+
12. birth_cert_doc Просмотр данных свидетельства о рождении:
• серия и номер свидетельства;
• дата выдачи;
• место государственной регистрации.
+
13. residence_doc Просмотр данных вида на жительство:
• серия и номер вида на жительство;
• дата выдачи.
+
14. temporary_residence_doc Просмотр данных разрешения на временное проживание:
• серия и номер разрешения на временное проживание;
• дата выдачи.
+
15. vehicles Просмотр данных транспортных средств:
• государственный регистрационный знак;
• серия и номер свидетельства о регистрации.
+
16. email адрес электронной почты, указанный в учетной записи +
17. mobile номер мобильного телефона +
18. contacts Просмотр данных о контактах и адресах:
• номер домашнего телефона;
• номер мобильного телефона;
• адрес электронной почты;
• адрес регистрации;
• адрес места проживания.
+
19. usr_org список организаций пользователя. +
20. usr_avt Просмотр изображения (аватара) пользователя:
• получения изображения (аватара);
• создание и обновление изображения (аватара);
• получение исходного изображения (аватара)
-
21. self_employed Просмотр данных о самозанятых
• признак самозанятого;
• категория (вид деятельности).
-
22. kid_fullname Просмотр фамилии, имени и отчества:
• фамилия;
• имя;
• отчество.
+
23. kid_birthdate дата рождения ребенка +
24.. kid_gender Пол ребенка +
25. kid_snils СНИЛС ребенка +
26. kid_inn ИНН ребенка +
27. kid_birth_cert_doc Просмотр данных свидетельства о рождении:
• серия свидетельства;
• номер свидетельства;
• дата выдачи свидетельства;
• кем выдано свидетельство.
-
28. kid_medical_doc Просмотр данных полиса ОМС:
• номер полиса ОМС;
• действителен до ОМС.
-
1. org_shortname Сокращенное наименованиеорганизации +
2. org_fullname Полное наименованиеорганизации +
3. org_type Тип организации +
4. org_ogrn ОГРН организации +
5. org_inn ИНН организации +
6. org_leg ОПФ организации +
7. org_kpp КПП организации +
8. org_agencyterrange Территориальнаяпринадлежность ОГВ +
9. org_agencytype Тип ОГВ +
10. org_oktmo ОКТМО организации +
11. org_ctts Контакты организации: номер телефона, номер факса, адрес электронной почты +
12. org_addrs Адреса организации (почтовый адрес, юридический адрес): индекс, идентификатор страны, адрес в виде строки (не включая дом, строение, корпус, номер квартиры), строение, корпус, дом, квартира, код ФИАС, регион,город, внутригородской район, район, поселение, доп. территория, улица на доп. территории, улица +
13. org_vhls Транспортные средства организации: название, государственный регистрационный знак, серия и номер свидетельства орегистрации -
14. org_grps Группы, владельцемкоторых является организация -
15. org_emps Данные о сотрудникахорганизации -
16. org_brhs Данные о филиалах организации (название, КПП, ОПФ, контакты,адреса) -
17. org_brhs_ctts Контакты филиаловорганизации -
18. org_brhs_addrs Адреса филиаловорганизации -
19. org_rcs Центры регистрацииорганизации -
20. org_stms Системы, владельцемкоторых является организация -
21. org_invts Приглашения, направленныеорганизацией -
22. categories Данные присвоенных организации видовдеятельности -
  • Библиотека авторизации через ЕСИА (Java)
  • 1 Общее описание
  • 2 Перечень поставляемых файлов
  • 3 Основные функции
  • 4 Интеграция библиотеки
  • 4.1 Подготовка
  • 4.2 Подключение библиотеки к проекту
  • 4.2.2 Сборка библиотеки в jar и подключение к целевому проекту;
  • 4.2.3 Добавление файлов исходников в целевой проект
  • 4.3. Реализация необходимых интеграционных классов
  • AuthStateStorage
  • Request
  • LoggerDelegate
  • HttpClient
  • 4.4 Инициализация библиотеки
  • 4.5 Процесс авторизации в ЕСИА
  • 4.6 Выход из ЕСИА
  • 4.7 Обновление маркера доступа
  • 4.8 Получение дополнительных разрешений
  • 4.9 Получение персональных данных
  • 5 Зависимости
  • ПРИЛОЖЕНИЕ А. Описание конфигурационных параметров
  • ПРИЛОЖЕНИЕ Б. Перечень запрашиваемых областей доступа