Рекомендации по подключению приложений по протоколу OAuth 2.0 / OIDC 1.0

В этом разделе рассмотрено взаимодействие приложения с Blitz Identity Provider в рамках следующих моделей авторизации, предусмотренных OAuth 2.0:

  • Authorization Code Grant – приложение авторизуется с явного разрешения пользователя, по этой же схеме реализована аутентификация на основе OpenID Connect 1.0.

  • Resource Owner Password Credentials Grant – приложение авторизуется посредством предъявления логина и пароля пользователя (данные которого предоставляются).

Более подробно о взаимодействии приложений с поставщиком идентификации по протоколам OAuth 2.0 и OpenID Connect 1.0 можно ознакомиться в спецификациях:

Авторизация приложения с явного разрешения пользователя

Общая схема

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

  • приложение запрашивает Blitz Identity Provider доступ к ресурсу;
  • приложение получает разрешение на доступ (authorization grant) в виде авторизационного кода (Blitz Identity Provider предварительно запрашивает это разрешение у пользователя);
  • приложение запрашивает маркер доступа, предъявив авторизационный код Blitz Identity Provider;
  • Blitz Identity Provider аутентифицирует приложение, проверяет авторизационный код и выдает маркер доступа и маркер обновления;
  • приложение запрашивает у Blitz Identity Provider защищенный ресурс, предъявляя маркер доступа;
  • Blitz Identity Provider проверяет маркер доступа, если он валиден, то разрешает доступ к защищенному ресурсу;

Далее возможны следующие шаги:

  • приложение через некоторое время запрашивает с помощью выданного ранее маркера доступ к защищенному ресурсу;
  • Blitz Identity Provider проверяет маркер, обнаруживает, что срок его действия истек, возвращает сообщение об ошибке;
  • приложение обращается к Blitz Identity Provider за получением нового маркера доступа, предъявляя маркер обновления;
  • Blitz Identity Provider проверяет валидность маркера обновления и возвращает два новых маркера: доступа и обновления.

Схема взаимодействия представлена на рисунке ниже. После того, как приложение получило маркер доступа, оно может неоднократно обращаться за получением соответствующего защищенного ресурса, пока не истечет срок действия этого маркера. Когда это произойдет, системе-клиенту потребуется получить новый маркер доступа.

Общая схема взаимодействия при получении маркера доступа с помощью авторизационного кода

Схема аутентификации на основе OpenID Connect 1.0

Аутентификация на основе OpenID Connect 1.0 включает в себя те же основные шаги, что и авторизация на основе OAuth 2.0:

  • приложение отправляет запрос на аутентификацию в адрес Blitz Identity Provider;
  • Blitz Identity Provider аутентифицирует пользователя;
  • Blitz Identity Provider получает согласие пользователя на проведение аутентификации и на передачу идентифицирующей информации о нем в приложение;
  • Blitz Identity Provider перенаправляет пользователя обратно в приложение и передает авторизационный код;
  • приложение формирует запрос с использованием авторизационного кода на получения маркера идентификации;
  • приложение получает ответ, содержащий необходимый маркер идентификации;
  • приложение проводит валидацию маркера идентификации и извлекает из маркера идентификатор пользователя.

Следует учесть, что в ответ на запрос на получение авторизационного кода Blitz Identity Provider всегда возвращает маркер доступа и маркер обновления, выданные на запрошенное разрешение (scope). Иными словами, если в запросе указано единственное разрешение openid, то в ответ Blitz Identity Provider вернет маркер идентификации, а также маркер доступа и маркер обновления. Маркер доступа можно использовать для получения тех данных о пользователе, которые явно прописаны в консоли управления.

Примеры запросов

Для проведения авторизации и/или аутентификации приложение должно направить пользователя на страницу предоставления прав доступа (URL указан в консоли управления), передав в качестве параметров:

  • scope – запрашиваемые разрешения (scope), для проведения аутентификации должно быть передано разрешение openid;
  • response_type – тип ответа (принимает значение “code”);
  • redirect_uri – ссылка для возврата пользователя;
  • state – набор случайных символов, имеющий вид 128-битного идентификатора запроса (используется для защиты от перехвата), это же значение будет возвращено в ответе – опциональный параметр;
  • nonce – набор случайных символов (используется для защиты от перехвата), это же значение будет возвращено в маркере идентификации – опциональный параметр (только для аутентификации по OpenID Connect);
  • client_id – идентификатор клиента;
  • prompt – параметр, определяющий способ ответа при проведении аутентификации (только для OpenID Connect), может принимать значения:

    • none – в этом случае будет проведена фоновая проверка аутентификации пользователя без перенаправления его на страницу входа: если пользователь имеет активную сессию в Blitz Identity Provider (и пользователь ранее давал доступ приложению), то будет возвращен авторизационный код; если он такой сессии не имеет, то будет возвращено сообщение об ошибке;
    • login – в этом случае будет проведена принудительная проверка аутентификации пользователя с перенаправлением его на страницу входа (даже если он имеет активную сессию).

Если параметр prompt не задан, то страница аутентификации появляется только тогда, когда пользователь не имеет активной сессии.

Пример запроса на получение авторизационного кода (запрошен маркер доступа с разрешением test):

https://<hostname>/blitz/oauth/ae?scope=test&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fsuccess&state=342a2c0c-d9ef-4cd6-b328-b67d9baf6a7f&client_id=localhost%2Fdemo2

Пример запроса на получение авторизационного кода (запрошена аутентификация, а также маркер доступа с разрешением test) с параметром nonce:

https://<hostname>/blitz/oauth/ae?scope=test+openid&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fsuccess&state=342a2c0c-4cd6-4cd6-b328-b67d9baf6a7f&client_id=localhost%2Fdemo2&nonce=987654321

Пример запроса на получение авторизационного кода (запрошена аутентификация) с параметрами nonce и prompt:

https://<hostname>/blitz/oauth/ae?scope=openid&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fsuccess&state=342a2c0c-b328-b328-b328-b67d9baf6a7f&client_id=localhost%2Fdemo2&nonce=987654321&prompt=login

Пример ответа со значением авторизационного кода (code) и параметром state:

http://localhost/success?code=f954nEzQ08DXju4wxGbSSfCX7TkZ1GvXUR7TzVus8fGnu4AUl-YIosgax-BLXMeQQAlasD6CN2qG_-0KXK5NIjARoKykhuR9IpbuzqeFxS0&state=342a2c0c-d9ef-4cd6-b328-b67d9baf6a7f

Пример ответа для случая с параметром prompt=none, когда пользователь не аутентифицирован:

http://localhost/success?error=login_required&error_description=The%2BAuthorization%2BServer%2Brequires%2BEnd-User%2Bauthentication.%2BThis%2Berror%2BMAY%2Bbe%2Breturned%2Bwhen%2Bthe%2Bprompt%2Bparameter%2Bvalue%2Bin%2Bthe%2BAuthentication%2BRequest%2Bis%2Bnone%252C%2Bbut%2Bthe%2BAuthentication%2BRequest%2Bcannot%2Bbe%2Bcompleted%2Bwithout%2Bdisplaying%2Ba%2Buser%2Binterface%2Bfor%2BEnd-User%2Bauthentication.&state=342a2c0c-d9ef-4cd6-b328-b67d9baf6a7f

После получения авторизационного кода приложение должно обменять его на маркер доступа / маркер идентификации. Для этого оно должно сформировать запрос методом POST на URL для получения и обновления маркера. Запрос должен содержать заголовок Authorization со значением Basic {secret}, где secret – это entity_id:secret (например, localhost/demo2:1234567890) в формате base64. Пример заголовка:

Authorization: Basic bG9jYWxob3N0L2RlbW8yOjEyMzQ1Njc4OTA=

Тело запроса должно содержать следующие параметры:

  • code – значение авторизационного кода, который был ранее получен;
  • grant_type – принимает значение “authorization_code”, если авторизационный код обменивается на маркер доступа;
  • redirect_uri – ссылка, по которой должен быть направлен пользователь после того, как даст разрешение на доступ (то же самое значение, которое было указано в запросе на получение авторизационного кода).

Пример запроса:

POST /blitz/oauth/te HTTP/1.1
Host: <hostname>
Authorization: Basic bG9jYWxob3N0L2RlbW8yOjEyMzQ1Njc4OTA=
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

grant_type=authorization_code&code=FLZHSMMqXTxU8EFW3bse7qOIYqarfbdbxGaDbVflffFENxBltpREKs7dEkN33dFvNyUggDb2XpP4nyTlUIZUMf4xBDreSmKrOkrVV7qK8GU&redirect_uri=http%3A%2F%2Flocalhost%2Fsuccess

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

{
    "access_token": "DsefHaGZ_n0Cw98-Uyhrhuhj_Ihxr1WOO1rqtX7_8aVdHQtrV5CHMpqLykrfEmqft351E-QKk_pxTduH6jAxmZlplwaeCpYaTxK7_5lAM5E",
    "expires_in": 3600,
    "scope": "test2",
    "refresh_token": "RBBM7i_eM88jeXS0R2SI0sIV7cFG8eIOr7vcxEFDBza91qdwbFIO-1AxbdxqgdGEZKJRgT5jNcSTOcwubRo6rCzOkMLbjEFTILKVrIx4eVg",
    "token_type": "bearer"
}

Если запрошена аутентификация (scope – openid), то будет также возвращен маркер идентификации:

{
    "id_token": "eyJhbGciOiJSUzI1NiJ9.eyJub25jZSI6Ijk4NzY1NDMyMSIsImV4cCI6MTQ0NTAwNDc3NywiaWF0IjoxNDQ0OTk0MjEyLCJzdWIiOiJzemF5dHNldkBkZXYtYmxpdHotaWRwLmxvYyIsImF1ZCI6WyJsb2NhbGhvc3QvZGVtbzIiXSwiaXNzIjoiaHR0cHM6Ly9kZXYtYmxpdHoucmVheG9mdC5sb2MifQ.Ckt_dr9J4k514MIuQEDY88A026NWzdCcIIIDxOXaZxue52eQlNVxaDXIQ8F0IyG2T-2KmeSeVG7UK4RoYWhYWT7Skn5NfF-gFJIfXB4NfUGwt5iic5UGQkp-xGqKzTxCKduuWrp-oVb69Bd8fFCeFYTVhB-iWR_V1yZhYTipQt6rLVKaqEFPvRv6iN_cGGIr7k0EJtEvF6Y71ktf6ERnhCXsLn78mPeJv0H0jk6dWWl9JJxpZC6RvUEqv4Q8q92xXh7RjoMQUErNk03J74QLIdn3xYke0ch20fOauMPLYXOc0-cPwo5kjF5zK6-c1chrwfk2FFMCi1bGYpgcICEssQ",
    "access_token": "dO-xymwduYR8uFqvYYK1ghpk-tqantG5PstfomddlO5d2-BVzVVaNdHuJYdWxpL__c8MsLWB8IwmiUIEep53tnZR2mflAnYiguE0UyUZNBE",
    "expires_in": 3600,
    "scope": "test openid",
    "refresh_token": "1lEWX7IE7SESIXRJNJeN66oPdzoFSfOGDLB3foAgXUDfuzYf1aXS1FuJX5JM50mmDqHuX75t-DrtvM0ISa82vs_t0NI9O1AcAilduRzZ8Iw",
    "token_type": "bearer"
}

Для обновления маркера доступа приложение должно сформировать запрос методом POST на URL для получения и обновления маркера. Запрос должен содержать аналогичный заголовок Authorization, а также следующие параметры в теле запроса:

  • refresh_token – значение маркера обновления;
  • grant_type – принимает значение refresh_token, если маркер обновления обменивается на маркер доступа.

Пример запроса:

POST /blitz/oauth/te HTTP/1.1
Host: <hostname>
Authorization: Basic bG9jYWxob3N0L2RlbW8yOjEyMzQ1Njc4OTA=
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

grant_type=refresh_token&refresh_token=jj2DAYsPi-aXMeSrQ7WiucRQKtz4_swxXdJDqVpC9laxIgQ_LhPmxiA8tPI7TocUkkgktXFqp28P0nC6af6STHP46TvvO1gBTx1-aW9rPbQ

Авторизация приложения посредством предъявления логина и пароля

Общая схема

Эта модель контроля доступа предполагает, что приложение получает разрешение на доступ к ресурсу (например, данными пользователя) в результате предъявления логина и пароля пользователя. Эту модель авторизации рекомендуется применять только в случае, если между приложением и Blitz Identity Provider установлены отношения доверия.

В общем виде схема взаимодействия выглядит следующим образом:

  • приложение запрашивает Blitz Identity Provider доступ к ресурсу, предъявляя логин и пароль пользователя;
  • Blitz Identity Provider аутентифицирует приложение, проверяет логин и пароль пользователя и выдает маркер доступа и маркер обновления;
  • приложение запрашивает у Blitz Identity Provider защищенный ресурс, предъявляя маркер доступа.

Дальнейшее взаимодействие осуществляется по стандартной схеме. Схема взаимодействия представлена на рисунке ниже.

Общая схема взаимодействия при получении маркера доступа посредством предъявления логина и пароля

Примеры запросов

Для получения маркера приложение должно отправить POST на URL для получения и обновления маркера. Запрос должен содержать описанный ранее заголовок Authorization, а в теле – следующие параметры:

  • scope – запрашиваемые scope;
  • grant_type – принимает значение password, если для получения маркера доступа предъявляется логин и пароль пользователя;
  • username – имя пользователя;
  • password – пароль пользователя.
POST /blitz/oauth/te HTTP/1.1
Host: <hostname>
Authorization: Basic bG9jYWxob3N0L2RlbW8yOjEyMzQ1Njc4OTA=
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

grant_type=password&username=tester&password=QWErty1234&scope=test

Пример ответа:

{
    "access_token": "C1NpcWTI_vgKBQPC7Mpf7uKPUQK1-1tczb79We5FQmAWFTikDAh6SyUgnAFHrLaZoVIiqSWRg3_fNYnKZQr0P2dRxtSFrUCkVsY3oLB-pi4",
    "expires_in": 3600,
    "scope": "test",
    "refresh_token": "FgCbFwuUh7DUTK-_-iChKgW8WZAUr_KOJTZqVKGtoPm62UO8klg1btm2bENnhy9FXsseUM87udPqFdCA_d-7E5a4UMmkZCaIXhDQ3yeib0E",
    "token_type": "bearer"
}

Получение данных и идентификационной информации

Данные пользователя

Для запроса данных о пользователе необходимо выполнить запрос методом GET по адресу получения данных пользователя. В запрос должен быть добавлен следующий заголовок:

Authorization: Bearer <access token>

В заголовке access token – это маркер доступа, предварительно полученный от Blitz Identity Provider.

Пример запроса:

GET /blitz/oauth/me HTTP/1.1
Host: <hostname>
Authorization: Bearer NINxnizbgYYQg94vEd6MjkTPxR3r2SZ3GO0HY0yEKLRXIDKsQ_0fZ-s9IAHBO92AszgTIqItY-_jsuIXqM_8i_6k8ohZcZ6acqpax-g6e8o
Cache-Control: no-cache

В ответе будут отображены только те данные, которые определены в scope, на который получен маркер доступа. Пример ответа:

{
    "name": "Тестов Тест",
    "sn": "Тестов"
}

Данные о маркере доступа

Для запроса данных об имеющемся маркере доступа необходимо выполнить запрос методом POST по адресу сервиса интроспекции маркера доступа (Создан в соответствие с RFC 7662). В запрос для аутентификации системы-клиента должен быть добавлен описанный ранее заголовок Authorization: Basic. Также должен быть добавлен заголовок Content-Type, принимающий значение application/x-www-form-urlencoded.

Сервис интроспекции может быть вызван любой системой, зарегистрированной в Blitz Identity Provider, для проверки любого маркера доступа (система может проверить маркер, выданный другой системе).

В теле запроса могут быть указаны параметры:

  • token – маркер доступа, данные о котором требуется просмотреть (обязательный параметр);
  • token_type_hint – тип маркера доступа (например, access_token), предназначен для ускорения поиска (опциональный параметр).

Пример запроса:

POST /blitz/oauth/introspect HTTP/1.1
Host: <hostname>
Authorization: Basic bG9jYWxob3N0L2RlbW8zOjA5ODc2NTQzMjE
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

token=MkvRff63ASFvC0-w6D3fiDxQgaYqmkrnzeDDcz374NDIbux6DA8ByDdB9-oMfaIklyoaNfrk87a4Ep3XzSxbF9m0wA2Z7LIUOaCGuSaKDNo

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

  • active – признак действительности маркера доступа, принимает значения true/false. Маркер действителен, если он выдан сервисом авторизации Blitz Identity Provider, не был отозван и срок его действия не истек;
  • scope – область доступа, на которую выдан маркер доступа. Передается в виде перечня разрешений (scope);
  • client_id – идентификатор системы-клиента, которая получила данный маркер доступа;
  • username – идентификатор пользователя (владельца ресурса, предоставившего доступ к своим данным), определенный как базовый идентификатор в Blitz Identity Provider. Значение параметра возвращается только в том случае, если он может быть передан в рамках scope по предъявленному маркеру доступа;
  • jti – идентификатор маркера доступа (в виде строки);
  • token_type – тип предъявленного маркера доступа;

Пример ответа:

{
    "username": "testuser",
    "scope": "test",
    "jti": "10jdlNohfHzuv3xoFurvWSPheEJEC7KHdHr-dcaVyYYvV3h0l2sh6OVVE4z3ChnRNVbddpjn3KH4Z76nQsO3q5ca8LbG9KWrKo1xWJKSbM0",
    "token_type": "Bearer",
    "client_id": "localhost/demo2",
    "active": true
}

Идентификационная информация

Для получения данных об идентификации и аутентификации приложению необходимо самостоятельно анализировать содержание маркера идентификации. Маркер состоит из трех частей:

  • заголовок (header), в котором содержится общая информация о типе маркера, в том числе об использованных в ходе его формирования криптографических операциях.
  • набор утверждений (payload / claim set) с содержательными сведениями о маркере.
  • подпись (signature), которая удостоверяет, что маркер «выдан» Blitz Identity Provider и не был изменен при передаче.

Части маркера разделены точкой, так что он имеет вид:

HEADER.PAYLOAD.SIGNATURE

Маркер передается в виде строки в формате Base64url.

Заголовок (header) содержит описание алгоритма шифрования (параметр alg; в настоящее время в Blitz Identity Provider поддерживается алгоритм электронной подписи RSA SHA-256, рекомендуемый спецификацией (соответствует значению RS256).

Набор утверждений включает следующие атрибуты:

  • идентификатор маркера (nonce), передается в неизменном виде из соответствующего запроса на проведение аутентификации;
  • время прекращения действия (exp), указывается в секундах с 1 января 1970 г. 00:00:00 GMT;
  • время выдачи (iat), указывается в секундах с 1 января 1970 г. 00:00:00 GMT;
  • идентификатор субъекта (sub), в качестве значения указывается значение идентификатора, определенного в консоли управления, для данного пользователя;
  • адресат маркера (aud), указывается client_id приложения, направившего запрос на аутентификацию;
  • организация, выпустившая маркер (iss), указывается URL Blitz Identity Provider.

Пример набора утверждений:

{
  "nonce": "987654321",
  "exp": 1445004777,
  "iat": 1444994212,
  "sub": "test@dev-blitz-idp.loc",
  "aud": [
    "localhost/demo2"
  ],
  "iss": "https://<hostname>"
}

Подпись (signature) маркера осуществляется по алгоритму, который указывается в параметре alg маркера. Подпись вычисляется от двух предыдущих частей маркера (HEADER.PAYLOAD).

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

  1. Проверка идентификатора Blitz Identity Provider, содержащегося в маркере идентификации.

  2. Сверка nonce исходного запроса на проведение аутентификации и nonce в маркере идентификации.

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

  4. Проверка подписи маркера идентификации (с использованием указанного в маркере алгоритма).

  5. Текущее время должно быть не позднее, чем время прекращения срока действия маркера идентификации.

После валидации маркера идентификации приложение считает пользователя аутентифицированным. Для получения дополнительных данных о пользователе следует использовать маркер доступа.

Для анализа содержания маркера идентификации, а также для упрощения разработки модулей по его проверке можно воспользоваться доступными онлайн-декодерами и библиотеками .

Обеспечение логаута при использовании OAuth 2.0

Если приложение предоставляет пользователю возможность инициировать выход из приложения (логаут), то приложению для обеспечения выхода недостаточно завершить локальную сессию. Необходимо также вызвать в Blitz Identity Provider операцию логаута. Если этого не сделать, то может возникнуть ситуация, что пользователь в приложении нажал кнопку Выход, после чего сразу попробовал нажать кнопку Вход, и вместо ожидаемого запроса идентификации и аутентификации сработал Single Sign On, и пользователь сразу автоматически оказался авторизованным.

Для инициирования в Blitz Identity Provider приложение после закрытия своей локальной сессии должно осуществить HTTP Redirect на следующий URL в Blitz Identity Provider, передав в качестве query-параметра адрес возврата в приложение: http(s)://<hostname>:<port>/blitz/login/logout?redirect=http(s)://redirect_url. Если Blitz Identity Provider успешно завершит логаут, то он перенаправит пользователя по переданному URL обратно в приложение.