Проблемы утверждений, запросы утверждений и возможности клиента

Требование утверждений — это ответ из API, указывающий, что у маркера доступа, отправленного клиентским приложением, недостаточно утверждений. Это может быть связано с тем, что маркер не удовлетворяет политикам условного доступа, установленным для этого API, или маркер доступа был отозван.

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

Приложения, использующие расширенные функции безопасности, такие как Непрерывная оценка доступа (CAE) и контекст проверки подлинности условного доступа, должны быть готовы обрабатывать требования утверждений.

Приложение получает вызовы утверждений от популярных служб, таких как Microsoft Graph , только если он объявляет свои клиентские возможности в своих вызовах к службе.

Формат заголовка требования утверждений

Требование утверждений — это директива в виде заголовка www-authenticate, возвращаемая API-интерфейсом, когда предоставленный ему маркер доступа не является авторизованным, а вместо него требуется новый маркер доступа с необходимыми возможностями. Требование утверждений состоит из нескольких элементов: код состояния HTTP ответа и заголовок www-authenticate, который сам состоит из нескольких элементов и должен содержать директиву утверждений.

Приведем пример:

HTTP 401; Unauthorized

www-authenticate =Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", error="insufficient_claims", claims="eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlIjoiY3AxIn19fQ=="

Код состояния HTTP: должен быть 401 Unauthorized.

Заголовок ответа www-authenticate, содержащий указанные ниже элементы.

Параметр Обязательный/необязательный Description
Тип аутентификации Обязательное поле Должен иметь значение Bearer.
Область Необязательно Идентификатор или доменное имя арендатора (например, microsoft.com), к которому осуществляется доступ. ДОЛЖЕН БЫТЬ пустой строкой в случае, когда проверка подлинности осуществляется через общую конечную точку.
authorization_uri Обязательное поле Универсальный код ресурса (URI) конечной authorize точки, где при необходимости можно выполнить интерактивную проверку подлинности. Если этот параметр указан в параметре realm, то в authorization_uri ДОЛЖНЫ БЫТЬ добавлены сведения о клиенте. Если realm является пустой строкой, параметр authorization_uri ДОЛЖЕН БЫТЬ связан с общей конечной точкой.
error Обязательное поле Если требуется создать требование утверждений, это должно быть значение "insufficient_claims".
claims Требуется при ошибке "insufficient_claims". Строка в кавычках, содержащая базовый запрос утвержденийв кодировке Base64. Запрос утверждений должен запрашивать утверждения для "access_token" на верхнем уровне объекта JSON. Значение (запрашиваемые утверждения) будет зависеть от контекста и описано далее в этом документе. Из соображений размера приложения проверяющей стороны ДОЛЖНЫ минифицировать код JSON перед применением кодировки Base64. Необработанный КОД JSON приведенного выше примера.{"access_token":{"acrs":{"essential":true,"value":"cp1"}}}

Ответ 401 может содержать более одного заголовка www-authenticate. Все поля в предыдущей таблице должны содержаться в одном заголовке www-authenticate. Заголовок www-authenticate, который содержит требование утверждений, может содержать другие поля. Поля в заголовке не упорядочены. Согласно стандарту RFC 7235, имя каждого параметра должно встречаться только один раз в каждом требовании схемы проверки подлинности.

Запрос утверждений

Если приложение получает требование утверждений, это означает, что прежний маркер доступа больше не считается допустимым. В этом сценарии приложение должно удалить маркер из локального кэша или сеанса пользователя. Затем он должен перенаправить вошедшего пользователя обратно в идентификатор Microsoft Entra, чтобы получить новый маркер с помощью потока кода авторизации OAuth 2.0 с параметром утверждений , который будет соответствовать другим требованиям, которые не были выполнены.

Приведем пример:

GET https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/authorize
?client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
&claims=%7B%22access_token%22%3A%7B%22acrs%22%3A%7B%22essential%22%3Atrue%2C%22value%22%3A%22c1%22%7D%7D%7D

Вызов утверждений должен быть передан как часть всех вызовов конечной точки Microsoft Entra /authorize , пока маркер не будет успешно получен. После получения маркера он больше не нужен.

Для заполнения параметра claims разработчик должен:

  1. Декодировать полученную ранее строку Base64.
  2. Закодировать строку в URL-адрес и снова добавить ее в параметр claims.

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

Возможности клиента

Возможности клиента помогают поставщику ресурсов, например веб-API, определить, распознает ли вызывающее клиентское приложение требования утверждений и может ли оно соответствующим образом скорректировать свой ответ. Эта возможность может пригодиться, если не все клиенты API способны обрабатывать требования утверждений, а некоторые более ранние версии ожидают другого ответа.

Некоторые популярные приложения, такие как Microsoft Graph, отправляют требования утверждений только в том случае, если вызывающее клиентское приложение объявляет с помощью возможностей клиента, что способно обрабатывать их.

Чтобы избежать дополнительного трафика или влияния на взаимодействие с пользователем, идентификатор Microsoft Entra не предполагает, что ваше приложение может обрабатывать утверждения, оспариваемые, если вы явно не согласитесь. Приложение не получит вызовы утверждений (и не сможет использовать связанные функции, такие как маркеры CAE), если только он не объявляет, что он готов обрабатывать их с помощью функции cp1.

Взаимодействие возможностей клиента с идентификатором Microsoft Entra

В следующем примере параметра утверждений показано, как клиентское приложение взаимодействует с его возможностями с идентификатором Microsoft Entra в потоке кода авторизации OAuth 2.0.

Claims: {"access_token":{"xms_cc":{"values":["cp1"]}}}

Используйте следующий код, если используется библиотека MSAL:

_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
 .WithDefaultRedirectUri()
 .WithAuthority(authority)
 .WithClientCapabilities(new [] {"cp1"})
 .Build();

При использовании Microsoft.Identity.Web можно добавить в файл конфигурации следующий код:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": 'Enter_the_Application_Id_Here' 
    "ClientCapabilities": [ "cp1" ],
    // remaining settings...
},

См. следующий фрагмент кода, чтобы просмотреть пример запроса к идентификатору Microsoft Entra:

GET https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/authorize
?client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
&claims=%7B%22access_token%22%3A%7B%22xms_cc%22%3A%7B%22values%22%3A%5B%22cp1%22%5D%7D%7D%7D

Если у вас уже есть полезные данные для параметра claims, вы можете добавить ее в существующий набор.

Например, если у вас уже есть следующий ответ из контекста проверки подлинности доступа к условию;

{"access_token":{"acrs":{"essential":true,"value":"c25"}}}

Вы можете добавить возможность клиента в качестве префикса к существующим полезным данным claims.

{"access_token":{"xms_cc":{"values":["cp1"]},"acrs":{"essential":true,"value":"c25"}}}

Получение утверждения xms_cc в маркере доступа

Чтобы понять, может ли клиентское приложение обрабатывать требования утверждений, реализация API должна запросить необязательное утверждение xms_cc в манифесте приложения.

Утверждение xms_cc со значением "cp1" в маркере доступа — полномочный способ понять, что клиентское приложение способно обрабатывать требования утверждений. xms_cc является необязательным утверждением, которое не всегда будет выдано в маркере доступа, даже если клиент отправляет запрос утверждений с "xms_cc". Чтобы в маркер доступа включалось утверждение xms_cc, приложение-ресурс (т. е. реализация API) должно запрашивать xms_cc как необязательное утверждение в манифесте приложения. При запросе в качестве необязательного утверждения xms_cc добавляется в маркер доступа, только если клиентское приложение отправляет xms_cc в запросе утверждений. Значение запроса xms_cc утверждения включается в качестве значения утверждения xms_cc в маркере доступа, если это известное значение. Единственным известным значением является cp1.

Значения не учитывает регистр и не упорядочены. Если в запросе утверждений xms_cc указано более одного значения, эти значения будут многозначными коллекциями в качестве значения утверждения xms_cc.

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

{ "access_token": { "xms_cc":{"values":["cp1","foo", "bar"] } }}

Это приводит к утверждению следующего фрагмента в маркере доступа, если cp1, foo и bar являются известными возможностями.

"xms_cc": ["cp1", "foo", "bar"]

После запроса xms_ccнеобязательного утверждения манифест приложения изменится следующим образом:

"optionalClaims":
{
    "accessToken": [
    {
        "additionalProperties": [],
        "essential": false,
        "name": "xms_cc",
        "source": null
    }],
    "idToken": [],
    "saml2Token": []
}

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

Claim ccClaim = context.User.FindAll(clientCapabilitiesClaim).FirstOrDefault(x => x.Type == "xms_cc");
if (ccClaim != null && ccClaim.Value == "cp1")
{
    // Return formatted claims challenge as this client understands this
}
else
{
    // Throw generic exception
    throw new UnauthorizedAccessException("The caller does not meet the authentication bar to carry our this operation. The service cannot allow this operation");
}

Примеры кода

Следующие шаги