python

Библиотека Python 3 для подключения к ЕСИА — esia-connector

  • воскресенье, 29 ноября 2015 г. в 02:10:39
http://habrahabr.ru/post/271827/

Все началось с того, что Минкомсвязи разрешило использовать портал госуслуг для идентификации и аутентификации пользователей на негосударственных веб-узлах. Это реализуется с помощью службы ЕСИА (Единая Система Идентификации и Аутентификации — esia.gosuslugi.ru). Заказчик нашего проекта входил в число первых 5 участников, которые подали заявки на интеграцию с ЕСИА, что выразилось для нас задачей эту интеграцию поддержать.

В свободном доступе мы не нашли открытого бесплатного решения подходящего для своего стека технологий, поэтому после разработки, с благословления заказчика, решили поделиться собственным (BSD license).

Итак, представляем вам проект esia-connector, написан на Python 3, использует утилиту openssl, проверялся в работе только в Debian-based системах.

Пакет: pypi.python.org/pypi/esia-connector
Проект: github.com/saprun/esia-connector


Что такое ЕСИА, какие она возможности предоставляет рассказывать не стану, только о возможностях текущей реализации нашей библиотеки.
esia-connector позволяет:
  • аутентифицироваться в ЕСИА, получить в ответ токен (который затем можно использовать для идентификации пользователя), проверить его;
  • получить личные данные пользователя: ФИО, данные удостоверяющих личность документов (паспорта, водительские права), контактные данные (номера телефонов, адрес электронной почты), ИНН, СНИЛС, адреса (проживания и регистрации).


Использование


Для того, чтобы подключиться к ЕСИА с помощью библиотеки вам нужно иметь на руках:
  1. Сертификат, выданный, либо самоподписанный в формате описанном в методических рекомендациях, загруженный на тестовый и боевой сервер ЕСИА.
    Выдержка из методических рекомендаций
    Выпустить ключевой контейнер и сертификат ключа квалифицированной электронной подписи для подключаемой информационной системы (должен содержать ОГРН ЮЛ, являющегося оператором информационной системы). Дополнительно поддерживается работа с ключевым контейнером и сертификатом ключа неквалифицированной электронной подписи в формате X.509 версии 3. В этом случае является допустимым самостоятельно сгенерировать (например, с помощью утилиты keytool из состава Java Development Kit) для своей системы ключевой контейнер и самоподписанный сертификат. Сертификат требуется для идентификации ИС при взаимодействии с ЕСИА. ЕСИА поддерживает алгоритмы формирования электронной подписи RSA с длиной ключа 2048 бит и алгоритмом криптографического хэширования SHA-256, а также алгоритм электронной подписи ГОСТ Р 34.10-2001 и алгоритм криптографического хэширования ГОСТ Р 34.11-94.
  2. Выданную службой поддержки ЕСИА учетную запись компании на боевом и тестовом серверах. Она, затем, должна быть указана при создании объекта EsiaSettings вместо строки “YOUR_SYSTEM_ID”.
  3. Учетные записи пользователей на тестовом и боевом серверах ЕСИА для отладки и тестирования.
  4. Публичные ключи ЕСИА (тестовый и боевой) для верификации полученного токена. В открытом доступе этих ключей нет, техподдержка высылает их электронной почтой по требованию.


Чтобы запустить тестовый пример (минимальное веб-приложение на Flask доступно в репозитории библиотеки) нужно
предварительно загруженный на сервер ЕСИА сертификат разместить в файле “esia-connector/examples/res/test.crt”. В этом же каталоге следует разместить ваш приватный ключ под именем “test.key”, а упомянутый выше публичный ключ разместить под именем “esia_pub.key”.
Затем запустить приложение Flask, из каталога examples выполнить:
python flask_app.py


На главной странице мы увидим правильно сформированную ссылку для обращения к ЕСИА, при переходе по ней сервер ЕСИА обработает данные в GET-запросе, запросит у пользователя логин и пароль к ЕСИА, затем после удачного введения запросит разрешение на доступ нашего приложения к ЕСИА и, в случае выдачи разрешения, редиректит на заданную в тестовом примере страницу, где мы с уже полученным токеном сделаем еще пару запросов на получение персональных данных пользователя от лица которого производим запрос, и отобразим эти данные на этой же странице.

Пример использования esia-connector
import os

from flask import Flask, request

from esia_connector.client import EsiaSettings, EsiaAuth


def get_test_file(name):
    return os.path.join(os.path.dirname(__file__), 'res', name)


TEST_SETTINGS = EsiaSettings(esia_client_id='YOUR SYSTEM ID',
                             redirect_uri='http://localhost:5000/info',
                             certificate_file=get_test_file('test.crt'),
                             private_key_file=get_test_file('test.key'),
                             esia_token_check_key=get_test_file('esia_pub.key'),
                             esia_service_url='https://esia-portal1.test.gosuslugi.ru',
                             esia_scope='openid http://esia.gosuslugi.ru/usr_inf')

assert TEST_SETTINGS.esia_client_id != 'YOUR SYSTEM ID', "Please specify real system id!"

assert os.path.exists(TEST_SETTINGS.certificate_file), "Please place your certificate in res/test.crt !"
assert os.path.exists(TEST_SETTINGS.private_key_file), "Please place your private key in res/test.key!"
assert os.path.exists(TEST_SETTINGS.esia_token_check_key), "Please place ESIA public key in res/esia_pub.key !"


app = Flask(__name__)

esia_auth = EsiaAuth(TEST_SETTINGS)


@app.route("/")
def hello():
    url = esia_auth.get_auth_url()
    return 'Start here: <a href="{0}">{0}</a>'.format(url)


@app.route("/info")
def process():
    code = request.args.get('code')
    state = request.args.get('state')
    esia_connector = esia_auth.complete_authorization(code, state)
    inf = esia_connector.get_person_main_info()
    return "%s" % inf


if __name__ == "__main__":
    app.run()



Реализация


Устройство библиотеки тривиальное, комментариев не требует, после написания стало понятно, что можно было бы спроектировать и лучше, чтобы пользователю библиотеки требовалось выполнять меньше действий с ее интерфейсом.
Стоит отметить, что используется утилита openssl для подписи, в связи с этим есть лишняя операция создания временного файла.
Нас устраивает текущая реализация, но лучше было бы использовать pyopenssl.

У нас нет планов развития библиотеки, пока не будет требований в проекте, а их в ближайшей перспективе нет.
Если используете esia-connector в ваших проектах и попутно что-то добавите/исправите — PR-те, будем рады включить.

Что можно было бы сделать:
  1. Реорганизовать интерфейс библиотеки для упрощения использования.
  2. Заменить использование openssl на pyopenssl.
  3. Разработать функционал по получению других данных из ЕСИА.
  4. Поддержать альтернативный протокол обмена данных реализованный в ЕСИА (SAML).
  5. Реализовать обертки для популярных фреймворков, например: Django, Flask, возможно в рамках отдельных проектов.


Ссылки


  1. Методические рекомендации по использованию ЕСИА: minsvyaz.ru/ru/documents/4243
  2. Регламент информационного взаимодействия: www.minsvyaz.ru/ru/documents/4244
  3. Новость о возможности интеграции с ЕСИА: www.kommersant.ru/doc/2832483
  4. Открытая реализация на PHP: github.com/fr05t1k/esia