Интеграция поставщика удостоверений с FedCM
В этой статье подробно описаны все шаги, которые должен предпринять поставщик удостоверений (IdP), чтобы интегрироваться с API Federated Credential Management (FedCM).
Шаги интеграции IdP
Для интеграции с FedCM IdP необходимо выполнить следующие действия:
- Предоставить файл с общедоступной информацией для идентификации IdP.
- Предоставить конфигурационный файл и конечные точки для списков учетных записей и выдачи утверждений (и, необязательно, метаданных клиента).
- Обновить статус входа в систему с помощью API статуса входа.
Предоставление файла с общедоступной информацией
Возможна проблема с конфиденциальностью, в которой IdP может определить, посетил ли пользователь RP без явного согласия. Это влечет за собой последствия для отслеживания, поэтому IdP должен предоставить файл с общедоступной информацией для проверки своей идентичности и смягчения этой проблемы.
Файл с общедоступной информацией запрашивается с помощью неуполномоченного запроса GET, который не обрабатывает перенаправления. Это фактически предотвращает получение IdP информации о том, кто инициировал запрос и какой RP пытается подключиться.
Файл с общедоступной информацией должен быть размещен в зоне eTLD+1 IdP по адресу /.well-known/web-identity. Например, если конечные точки IdP обслуживаются по адресу https://accounts.idp.example/, они должны размещать файл с общедоступной информацией по адресу https://idp.example/.well-known/web-identity. Содержимое файла с общедоступной информацией должно иметь следующую структуру JSON:
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
Член provider_urls должен содержать массив URL-адресов, указывающих на допустимые конфигурационные файлы IdP, которые могут использоваться RP для взаимодействия с IdP. Длина массива в настоящее время ограничена одним элементом.
Заголовок HTTP Sec-Fetch-Dest
Все запросы, отправляемые браузером через FedCM, включают заголовок . Все конечные точки IdP, которые принимают запросы с учётными данными (т.е. Sec-Fetch-Dest: webidentityaccounts_endpoint и id_assertion_endpoint), должны подтвердить наличие этого заголовка, чтобы защититься от атак CSRF.
Предоставление конфигурационного файла и конечных точек
Конфигурационный файл IdP предоставляет список конечных точек, необходимых браузеру для обработки процесса федерации идентификации и управления входами в систему. Конечные точки должны быть одной области с конфигурацией.
Браузер отправляет неуполномоченный запрос на конфигурационный файл с помощью метода GET, который не обрабатывает перенаправления. Это эффективно предотвращает получение IdP информации о том, кто инициировал запрос и какой RP пытается подключиться.
Конфигурационный файл (размещенный по адресу https://accounts.idp.example/config.json в нашем примере) должен иметь следующую структуру JSON:
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"login_url": "/login",
"branding": {
"background_color": "green",
"color": "0xFFEEAA",
"icons": [
{
"url": "https://idp.example/icon.ico",
"size": 25
}
]
}
}
Свойства следующие:
accounts_endpoint-
URL конечной точки списка учетных записей, возвращающий список учетных записей, с которыми пользователь в данный момент авторизован на IdP. Браузер использует эти данные для создания списка вариантов входа для отображения пользователю в интерфейсе FedCM, предоставляемом браузером.
client_metadata_endpointНеобязательно-
URL конечной точки метаданных клиента, предоставляющий URL-адреса, указывающие на метаданные и страницы пользовательского соглашения RP, которые будут использоваться в интерфейсе FedCM.
id_assertion_endpoint-
URL конечной точки утверждения идентификации, которая, при отправке действительных учетных данных пользователя, должна ответить токеном валидации, который RP может использовать для проверки аутентификации.
login_url-
URL страницы входа для входа пользователя в IdP.
brandingНеобязательно-
Содержит информацию о брендинге, которая будет использоваться в интерфейсе FedCM, предоставляемом браузером, для настройки его внешнего вида по желанию IdP.
Следующая таблица обобщает различные запросы, выполняемые API FedCM:
| Конечная точка/ресурс | Метод | Авторизованный (с куки) | Включает Origin
|
|---|---|---|---|
well-known/config.json
| GET | Нет | Нет |
accounts_endpoint | GET | Да | Нет |
client_metadata_endpoint | GET | Нет | Да |
id_assertion_endpoint | POST | Да | Да |
Примечание: Подробное описание процесса FedCM, в котором выполняются эти запросы, см. в процессе входа FedCM.
Примечание: Ни один из запросов, выполняемых API FedCM к конечным точкам, описанным здесь, не позволяет обрабатывать перенаправления, в целях конфиденциальности.
Конечная точка списка учетных записей
Браузер отправляет авторизованные запросы (т.е. с cookie, идентифицирующей пользователя, авторизованного в системе) на эту конечную точку с помощью метода GET. В запросе отсутствует параметр client_id, заголовок Origin или заголовок Referer. Это эффективно предотвращает получение IdP информации о том, к какому RP пытается войти пользователь. Список возвращаемых учетных записей не зависит от RP.
Например:
GET /accounts.php HTTP/1.1 Host: idp.example Accept: application/json Cookie: 0x23223 Sec-Fetch-Dest: webidentity
Ответ на успешный запрос возвращает список всех учетных записей IdP, с которыми пользователь в настоящее время авторизован (не конкретные для любого RP), с структурой JSON, соответствующей следующей:
{
"accounts": [
{
"id": "john_doe",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["john_doe", "john_doe@idp.example"]
},
{
"id": "johnny",
"given_name": "Johnny",
"name": "Johnny",
"email": "johnny@idp.example",
"picture": "https://idp.example/profile/456",
"approved_clients": ["abc", "def", "ghi"],
"login_hints": ["johnny", "johnny@idp.example"]
}
]
}
Включает следующую информацию:
id-
Уникальный идентификатор пользователя.
name-
Фамилия пользователя.
email-
Электронный адрес пользователя.
given_nameНеобязательно-
Имя пользователя.
pictureНеобязательно-
URL-адрес изображения аватара пользователя.
approved_clientsНеобязательно-
Массив RP-клиентов, с которыми пользователь зарегистрирован.
login_hintsНеобязательно-
Массив строк, представляющих учётную запись. Эти строки используются для фильтрации списка вариантов учетных записей, которые браузер предлагает пользователю для входа. Это происходит, когда свойство
loginHintзадаётся внутриidentity.providersв связанном вызовеget(). Любая учётная запись со строкой в массивеlogin_hints, соответствующей предоставленномуloginHint, включается.
Примечание: Если пользователь не авторизован ни в одной учётной записи IdP, конечная точка должна ответить кодом HTTP 401 (Неавторизован).
Конечная точка метаданных клиента
Браузер отправляет неуполномоченные запросы на эту конечную точку с помощью метода GET, с clientId, переданным в вызов get() в качестве параметра.
Например:
GET /client_metadata.php?client_id=1234 HTTP/1.1 Host: idp.example Origin: https://rp.example/ Accept: application/json Sec-Fetch-Dest: webidentity
Ответ на успешный запрос включает URL-адреса, указывающие на метаданные и страницы пользовательского соглашения RP, которые будут использоваться в интерфейсе FedCM, предоставляемом браузером. Он должен соответствовать структуре JSON, приведенной ниже:
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html"
}
Конечная точка утверждения идентификации
Браузер отправляет запросы с учётными данными на этот конечный пункт с помощью метода POST, с типом контента application/x-www-form-urlencoded. В запросе также содержится полезная нагрузка, включающая подробности о попытке входа в систему и учетной записи, подлежащей валидации.
Он должен выглядеть примерно так:
POST /assertion.php HTTP/1.1 Host: idp.example Origin: https://rp.example/ Content-Type: application/x-www-form-urlencoded Cookie: 0x23223 Sec-Fetch-Dest: webidentity account_id=123&client_id=client1234&nonce=Ct60bD&disclosure_text_shown=true&is_auto_selected=true
Запрос на этот конечный пункт отправляется в результате выбора пользователем учетной записи для входа из соответствующего пользовательского интерфейса браузера. При отправке действительных учётных данных пользователя этот конечный пункт должен ответить маркером валидации, который RP может использовать для валидации пользователя на собственном сервере в соответствии с инструкциями по использованию, определёнными IdP, который используется для федерации идентификации. После валидации пользователя RP может войти в систему, зарегистрировать его в своём сервисе и т. д.
{
"token": "***********"
}
Полезная нагрузка запроса содержит следующие параметры:
client_id-
Идентификатор клиента RP (который соответствует
clientIdиз исходного запросаget()). account_id-
Уникальный идентификатор учётной записи пользователя, подлежащей входу в систему (который соответствует идентификатору пользователя
idиз ответа конечного пункта списка учётных записей). nonceНеобязательно-
Номера запроса, предоставленные RP.
disclosure_text_shown-
Строка
"true"или"false", указывающая, отображался ли текст раскрытия или нет. Текст раскрытия — это информация, отображаемая пользователю (включая ссылки на условия использования и политику конфиденциальности, если они предоставлены), если пользователь вошел в IdP, но не имеет учётной записи конкретно в текущем RP (в этом случае ему нужно выбрать «Продолжить как...» свою личность IdP и затем создать соответствующую учётную запись в RP). is_auto_selected-
Строка
"true"или"false", указывающая, был ли запрос на валидацию аутентификации инициирован в результате автоматической повторной аутентификации, т. е. без участия пользователя. Это может произойти, когда вызовget()выполняется с значением параметраmediationравным"optional"или"silent". Для IdP важно знать, произошла ли автоматическая повторная аутентификация для оценки производительности и в случае необходимости повышенной безопасности. Например, IdP может вернуть код ошибки, сообщая RP, что требуется явное участие пользователя (mediation="required").
Примечание: Если вызов get() успешно выполняется, значение is_auto_selected также передаётся RP через свойство IdentityCredential.isAutoSelected.
Ответы с ошибками подтверждения идентификации
Если IdP не может выдать маркер — например, если клиент не авторизован — конечный пункт подтверждения идентификации вернёт ответ с ошибкой, содержащий информацию о характере ошибки. Например:
{
"error": {
"code": "access_denied",
"url": "https://idp.example/error?type=access_denied"
}
}
Поля ответа с ошибкой следующие:
codeНеобязательно-
Строка. Это может быть известная ошибка из списка ошибок OAuth 2.0 или произвольная строка.
urlНеобязательно-
URL. Это должна быть веб-страница, содержащая информацию о возникшей ошибке в удобочитаемом виде для отображения пользователям, например, о способах исправления ошибки или контактах поддержки. URL-адрес должен находиться в одном домене с URL-адресом конфигурации IdP.
Эта информация может быть использована несколькими способами:
- Браузер может отобразить пользователю специальный интерфейс, информируя его о том, что пошло не так (см. документацию Chrome для примера). Имейте в виду, что если запрос не удалось выполнить из-за недоступности сервера IdP, он, очевидно, не может вернуть никакой информации. В таких случаях браузер сообщит об этом с помощью универсального сообщения.
- Соответствующий вызов RP
navigator.credentials.get(), используемый для попытки входа в систему, отклонит своё обещание сIdentityCredentialError, содержащим информацию об ошибке. RP может перехватить эту ошибку и дополнить пользовательский интерфейс браузера некоторой информацией, помогающей пользователю в будущих попытках входа в систему.
Обновление состояния входа в систему с помощью API состояния входа в систему
API состояния входа в систему позволяет IdP информировать браузер о своём состоянии входа в систему (входа) в этом конкретном браузере — другими словами, «есть ли какие-либо пользователи, авторизованные в IdP в текущем браузере или нет». Браузер сохраняет это состояние для каждого IdP; API FedCM затем использует его для сокращения количества запросов, отправляемых IdP (так как ему не нужно тратить время на запрос учётных записей, когда пользователи не авторизованы в IdP). Это также смягчает возможные атаки на основе временных данных.
Для каждого известного IdP (определяемого его URL-адресом конфигурации) браузер сохраняет переменную со тремя состояниями, представляющую состояние входа в систему с тремя возможными значениями:
-
"logged-in": IdP имеет по крайней мере одну учётную запись пользователя, авторизованную. Обратите внимание, что на данном этапе RP и браузер не знают, какой это пользователь. Информация о конкретных пользователях возвращается из конечного пунктаaccounts_endpointIdP на более позднем этапе процесса FedCM. -
"logged-out": Все учётные записи IdP в настоящее время выведены из системы. -
"unknown": Состояние входа в систему этого IdP неизвестно. Это значение по умолчанию.
Установка состояния входа в систему
IdP должен обновлять своё состояние входа в систему, когда пользователь входит в IdP или выходит из него. Это можно сделать двумя способами:
-
Заголовок ответа HTTP
Set-Loginможно установить в запросе навигации верхнего уровня или в запросе к ресурсу в том же домене:Set-Login: logged-in Set-Login: logged-out
-
Метод
Navigator.login.setStatus()можно вызвать из происхождения IdP:/* Set logged-in status */ navigator.login.setStatus("logged-in"); /* Set logged-out status */ navigator.login.setStatus("logged-out");
Как состояние входа в систему влияет на процесс федеративного входа в систему
Когда RP пытается выполнить федеративный вход в систему, проверяется состояние входа в систему:
- Если состояние входа в систему равно
"logged-in", осуществляется запрос к конечному пункту IdP списка учётных записей, и доступные учётные записи для входа в систему отображаются пользователю в диалоговом окне FedCM, предоставляемом браузером. - Если состояние входа в систему равно
"logged-out", обещание, возвращаемое запросом FedCMget(), отклоняется без отправки запроса к конечному пункту списка учётных записей. В таком случае разработчик должен обработать поток, например, предложив пользователю войти в подходящий IdP. - Если состояние входа в систему равно
"unknown", осуществляется запрос к конечному пункту IdP списка учётных записей, и состояние входа в систему обновляется в зависимости от ответа:- Если конечный пункт возвращает список доступных учётных записей для входа в систему, обновите статус на
"logged-in"и отобразите варианты входа в систему пользователю в диалоговом окне FedCM, предоставляемом браузером. - Если конечный пункт не возвращает учётных записей, обновите статус на
"logged-out"; обещание, возвращаемое запросом FedCMget(), затем отклоняется.
- Если конечный пункт возвращает список доступных учётных записей для входа в систему, обновите статус на
Что делать, если состояние входа в систему браузера и IdP становятся несинхронизированными?
Несмотря на то, что API состояния входа в систему информирует браузер о состоянии входа в систему IdP, браузер и IdP могут выйти из синхронизации. Например, сеансы IdP могут истекать, что означает, что все учётные записи пользователей выходят из системы, но состояние входа в систему всё ещё установлено на "logged-in" (приложение не смогло установить состояние входа в систему на "logged-out"). В таком случае при попытке федеративного входа в систему будет отправлен запрос к конечному пункту IdP списка учётных записей, но доступных учётных записей не будет возвращено, потому что сеанс больше недоступен.
В этом случае браузер может динамически позволить пользователю войти в IdP, открыв страницу входа IdP в диалоговом окне (URL-адрес входа находится в файле конфигурации IdP login_url). Точная структура этого потока зависит от браузера; например, Chrome обрабатывает это таким образом.
После входа пользователя в IdP IdP должен:
- Сообщить браузеру об авторизации пользователя, установив состояние входа в систему на
"logged-in". - Закрыть диалоговое окно входа, вызвав метод
IdentityProvider.close().
См. также
- Federated Credential Management API на developers.google.com (2023)
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API/IDP_integration