Skip to content

Commit 533f39d

Browse files
aad authz updates
1 parent 94bb49b commit 533f39d

3 files changed

+130
-10
lines changed

articles/app-service/configure-authentication-provider-aad.md

+21-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Use this option unless you need to create an app registration separately. It mak
3131
1. Select **Authentication** in the menu on the left. Click **Add identity provider**.
3232
1. Select **Microsoft** in the identity provider dropdown. The option to create a new registration is selected by default. You can change the name of the registration or the supported account types.
3333

34-
A client secret will be created and stored as a slot-sticky [application setting](./configure-common.md#configure-app-settings) named `MICROSOFT_PROVIDER_AUTHENTICATION_SECRET`. You can update that setting later to use [Key Vault references](./app-service-key-vault-references.md) if you wish to manage the secret in Azure Key Vault.
34+
A client secret will be created and stored as a slot-sticky [application setting] named `MICROSOFT_PROVIDER_AUTHENTICATION_SECRET`. You can update that setting later to use [Key Vault references](./app-service-key-vault-references.md) if you wish to manage the secret in Azure Key Vault.
3535

3636
1. If this is the first identity provider configured for the application, you will also be prompted with an **App Service authentication settings** section. Otherwise, you may move on to the next step.
3737

@@ -103,7 +103,7 @@ To register the app, perform the following steps:
103103
|Issuer Url| Use `<authentication-endpoint>/<tenant-id>/v2.0`, and replace *\<authentication-endpoint>* with the [authentication endpoint for your cloud environment](../active-directory/develop/authentication-national-cloud.md#azure-ad-authentication-endpoints) (e.g., "https://login.microsoftonline.com" for global Azure), also replacing *\<tenant-id>* with the **Directory (tenant) ID** in which the app registration was created. This value is used to redirect users to the correct Azure AD tenant, as well as to download the appropriate metadata to determine the appropriate token signing keys and token issuer claim value for example. For applications that use Azure AD v1, omit `/v2.0` in the URL.|
104104
|Allowed Token Audiences| The configured **Application (client) ID** is *always* implicitly considered to be an allowed audience. If this is a cloud or server app and you want to accept authentication tokens from a client App Service app (the authentication token can be retrieved in the [X-MS-TOKEN-AAD-ID-TOKEN](configure-authentication-oauth-tokens.md#retrieve-tokens-in-app-code)) header, add the **Application (client) ID** of the client app here. |
105105

106-
The client secret will be stored as a slot-sticky [application setting](./configure-common.md#configure-app-settings) named `MICROSOFT_PROVIDER_AUTHENTICATION_SECRET`. You can update that setting later to use [Key Vault references](./app-service-key-vault-references.md) if you wish to manage the secret in Azure Key Vault.
106+
The client secret will be stored as a slot-sticky [application setting] named `MICROSOFT_PROVIDER_AUTHENTICATION_SECRET`. You can update that setting later to use [Key Vault references](./app-service-key-vault-references.md) if you wish to manage the secret in Azure Key Vault.
107107

108108
1. If this is the first identity provider configured for the application, you will also be prompted with an **App Service authentication settings** section. Otherwise, you may move on to the next step.
109109

@@ -113,7 +113,22 @@ To register the app, perform the following steps:
113113

114114
You're now ready to use the Microsoft identity platform for authentication in your app. The provider will be listed on the **Authentication** screen. From there, you can edit or delete this provider configuration.
115115

116-
## Add customized authorization policy
116+
## Authorize requests
117+
118+
By default, App Service Authentication only handles authentication, determining if the caller is who they say they are. Authorization, determining if that caller should have access to some resource, is an additional step beyond authentication. You can learn more about these concepts from [Microsoft identity platform authorization basics](../active-directory/develop/authorization-basics.md).
119+
120+
Your app can [make authorization decisions in code](#perform-validations-from-application-code). App Service Authentication does provide some [built-in checks](#use-a-built-in-authorization-policy) which can help, but they may not alone be sufficient to cover the authorization needs of your app.
121+
122+
> [!TIP]
123+
> Multi-tenant applications should interrogate the issuer and tenant ID of the request as part of this process to make sure the values are allowed. When App Service Authentication is configured for a multi-tenant scenario, it does not itself reason about which tenant the request comes from. An app may need to be limited to specific tenants, based on if the organization has signed up for the service, for example. See the [Microsoft identity platform multi-tenant guidance](../active-directory/develop/howto-convert-app-to-be-multi-tenant.md#update-your-code-to-handle-multiple-issuer-values).
124+
125+
### Perform validations from application code
126+
127+
When you perform authorization checks in your app code, you can leverage the [claims information that App Service Authentication makes available](./configure-authentication-user-identities.md#access-user-claims-in-app-code). The injected `x-ms-client-principal` header contains a Base64-encoded JSON object with the claims asserted about the caller. By default, these claims go through a claims mapping, so the claim names may not always match what you would see in the token. For example, the `tid` claim is mapped to `http://schemas.microsoft.com/identity/claims/tenantid` instead.
128+
129+
You can also work directly with the underlying access token from the injected `x-ms-token-aad-access-token` header.
130+
131+
### Use a built-in authorization policy
117132

118133
The created app registration authenticates incoming requests for your Azure AD tenant. By default, it also lets anyone within the tenant to access the application, which is fine for many applications. However, some applications need to restrict access further by making authorization decisions. Your application code is often the best place to handle custom authorization logic. However, for common scenarios, the Microsoft identity platform provides built-in checks that you can use to limit access.
119134

@@ -141,6 +156,8 @@ Within the API object, the Azure Active Directory identity provider configuratio
141156
| `allowedPrincipals` | A grouping of checks that determine if the principal represented by the incoming request may access the app. Satisfaction of `allowedPrincipals` is based on a logical `OR` over its configured properties. |
142157
| `identities` (under `allowedPrincipals`) | An allowlist of string **object IDs** representing users or applications that have access. When this property is configured as a nonempty array, the `allowedPrincipals` requirement can be satisfied if the user or application represented by the request is specified in the list.<br/><br/>This policy evaluates the `oid` claim of the incoming token. See the [Microsoft Identity Platform claims reference]. |
143158

159+
Additionally, some checks can be configured through an [application setting], regardless of the API version being used. The `WEBSITE_AUTH_AAD_ALLOWED_TENANTS` application setting can be configured with a comma-separated list of up to 10 tenant IDs (e.g., "559a2f9c-c6f2-4d31-b8d6-5ad1a13f8330,5693f64a-3ad5-4be7-b846-e9d1141bcebc") to require that the incoming token be from one of the specified tenants, as specified by the `tid` claim. The `WEBSITE_AUTH_AAD_REQUIRE_CLIENT_SERVICE_PRINCIPAL` application setting can be configured to "true" or "1" to require the incoming token to include an `oid` claim. This setting is ignored and treated as true if `allowedPrincipals.identities` has been configured.
160+
144161
Requests that fail these built-in checks are given an HTTP `403 Forbidden` response.
145162

146163
[Microsoft Identity Platform claims reference]: ../active-directory/develop/access-tokens.md#payload-claims
@@ -212,3 +229,4 @@ Regardless of the configuration you use to set up authentication, the following
212229
<!-- URLs. -->
213230

214231
[Azure portal]: https://portal.azure.com/
232+
[application setting]: ./configure-common.md#configure-app-settings

articles/app-service/configure-authentication-user-identities.md

+102-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,113 @@ This article shows you how to work with user identities when using the the built
1313

1414
For all language frameworks, App Service makes the claims in the incoming token (whether from an authenticated end user or a client application) available to your code by injecting them into the request headers. External requests aren't allowed to set these headers, so they are present only if set by App Service. Some example headers include:
1515

16-
* X-MS-CLIENT-PRINCIPAL-NAME
17-
* X-MS-CLIENT-PRINCIPAL-ID
16+
| Header | Description |
17+
|------------------------------|-----------------------------------------------------------------------|
18+
| `X-MS-CLIENT-PRINCIPAL` | A Base64 encoded JSON representation of available claims. See [Decoding the client principal header](#decoding-the-client-principal-header) for more information. |
19+
| `X-MS-CLIENT-PRINCIPAL-ID` | An identifier for the caller set by the identity provider. |
20+
| `X-MS-CLIENT-PRINCIPAL-NAME` | A human-readable name for the caller set by the identity provider. |
21+
| `X-MS-CLIENT-PRINCIPAL-IDP` | The name of the identity provider used by App Service Authentication. |
1822

19-
Code that is written in any language or framework can get the information that it needs from these headers.
23+
Provider tokens are also exposed through similar headers. For example, the Microsoft Identity Provider also sets `X-MS-TOKEN-AAD-ACCESS-TOKEN` and `X-MS-TOKEN-AAD-ID-TOKEN` as appropriate.
2024

2125
> [!NOTE]
2226
> Different language frameworks may present these headers to the app code in different formats, such as lowercase or title case.
2327
28+
Code that is written in any language or framework can get the information that it needs from these headers. [Decoding the client principal header](#decoding-the-client-principal-header) covers this process. For some frameworks, the platform also provides additional options which may be more convenient
29+
30+
### Decoding the client principal header
31+
32+
`X-MS-CLIENT-PRINCIPAL` contains the full set of available claims as Base64 encoded JSON. These claims go through a default claims-mapping process, so some may have different names than you would see if processing the token directly. The decoded payload is structured as follows:
33+
34+
```json
35+
{
36+
"auth_typ": "",
37+
"claims": [
38+
{
39+
"typ": "",
40+
"val": ""
41+
}
42+
],
43+
"name_typ": "",
44+
"role_typ": ""
45+
}
46+
```
47+
48+
| Property | Type | Description |
49+
|------------|------------------|---------------------------------------|
50+
| `auth_typ` | string | The name of the identity provider used by App Service Authentication. |
51+
| `claims` | array of objects | An array of objects representing the available claims. Each object contains `typ` and `val` properties. |
52+
| `typ` | string | The name of the claim. This may have been subject to default claims mapping and could be different from the corresponding claim contained in a token. |
53+
| `val` | string | The value of the claim. |
54+
| `name_typ` | string | The name claim type, which is typically a URI providing scheme information about the `name` claim if one is defined. |
55+
| `role_typ` | string | The role claim type, which is typically a URI providing scheme information about the `role` claim if one is defined. |
56+
57+
To process this header, your app will need to decode the payload and iterate through the `claims` array to find the claims of interest. It may be convenient to convert these into a representation used by the app's language framework. Here is an example of this process in C# that constructs a [ClaimsPrincipal](/dotnet/api/system.security.claims.claimsprincipal) type for the app to use:
58+
59+
```csharp
60+
using System;
61+
using System.Collections.Generic;
62+
using System.Linq;
63+
using System.Security.Claims;
64+
using System.Text;
65+
using System.Text.Json;
66+
using System.Text.Json.Serialization;
67+
using Microsoft.AspNetCore.Http;
68+
69+
public static class ClaimsPrincipalParser
70+
{
71+
private class ClientPrincipalClaim
72+
{
73+
[JsonPropertyName("typ")]
74+
public string Type { get; set; }
75+
[JsonPropertyName("val")]
76+
public string Value { get; set; }
77+
}
78+
79+
private class ClientPrincipal
80+
{
81+
[JsonPropertyName("auth_typ")]
82+
public string IdentityProvider { get; set; }
83+
[JsonPropertyName("name_typ")]
84+
public string NameClaimType { get; set; }
85+
[JsonPropertyName("role_typ")]
86+
public string RoleClaimType { get; set; }
87+
[JsonPropertyName("claims")]
88+
public IEnumerable<ClientPrincipalClaim> Claims { get; set; }
89+
}
90+
91+
public static ClaimsPrincipal Parse(HttpRequest req)
92+
{
93+
var principal = new ClientPrincipal();
94+
95+
if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
96+
{
97+
var data = header[0];
98+
var decoded = Convert.FromBase64String(data);
99+
var json = Encoding.UTF8.GetString(decoded);
100+
principal = JsonSerializer.Deserialize<ClientPrincipal>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
101+
}
102+
103+
/**
104+
* At this point, the code can iterate through `principal.Claims` to
105+
* check claims as part of validation. Alternatively, we can convert
106+
* it into a standard object with which to perform those checks later
107+
* in the request pipeline. That object can also be leveraged for
108+
* associating user data, etc. The rest of this function performs such
109+
* a conversion to create a `ClaimsPrincipal` as might be used in
110+
* other .NET code.
111+
*/
112+
113+
var identity = new ClaimsIdentity(principal.IdentityProvider);
114+
identity.AddClaims(principal.Claims.Select(c => new Claim(c.Type, c.Value)));
115+
116+
return new ClaimsPrincipal(identity);
117+
}
118+
}
119+
```
120+
121+
### Framework-specific alternatives
122+
24123
For ASP.NET 4.6 apps, App Service populates [ClaimsPrincipal.Current](/dotnet/api/system.security.claims.claimsprincipal.current) with the authenticated user's claims, so you can follow the standard .NET code pattern, including the `[Authorize]` attribute. Similarly, for PHP apps, App Service populates the `_SERVER['REMOTE_USER']` variable. For Java apps, the claims are [accessible from the Tomcat servlet](configure-language-java.md#authenticate-users-easy-auth).
25124

26125
For [Azure Functions](../azure-functions/functions-overview.md), `ClaimsPrincipal.Current` is not populated for .NET code, but you can still find the user claims in the request headers, or get the `ClaimsPrincipal` object from the request context or even through a binding parameter. See [working with client identities in Azure Functions](../azure-functions/functions-bindings-http-webhook-trigger.md#working-with-client-identities) for more information.

0 commit comments

Comments
 (0)