简体   繁体   中英

Azure AD Multi-tenant Applications - How to implement Token Validation?

I have a multi tenant Web app / API registered in Azure ad and that connected to an API App. The API App has Active Directory Authentication setup. At the moment only one other tenant needs access to api. I made sure only they can get access by putting https://sts.windows.net/<third party tenant>/ in the Issuer URL . My question is: How would I go about giving a second (or more) tenants access to the api? I can't add anymore tenant ids in the Issuer URL so I'm kinda at a loss

Thanks

The approach you are using currently will work only in a single tenant scenario, ie Automatic validation of tenant by setting IssuerURL works only in a single tenant scenario.

In case of multi-tenant applications, the application is responsible for storing and validating all possible issuers. This is by design and exact guidance on this topic from Microsoft is available here:

Work with claims-based identities in Azure AD: Issuer Validation

For a single-tenant application, you can just check that the issuer is your own tenant. In fact, the OIDC middleware does this automatically by default. In a multi-tenant app, you need to allow for multiple issuers, corresponding to the different tenants. Here is a general approach to use:

  • In the OIDC middleware options, set ValidateIssuer to false. This turns off the automatic check.
  • When a tenant signs up, store the tenant and the issuer in your user DB.
  • Whenever a user signs in, look up the issuer in the database.If the issuer isn't found, it means that tenant hasn't signed up. You can redirect them to a sign up page.
  • You could also blacklist certain tenants; for example, for customers that didn't pay their subscription.

So, in case of a .NET based web application the code in your startup class would change to something like this.. notice the new TokenValidationParameters { ValidateIssuer = false }

Authenticate using Azure AD and OpenID Connect

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions {
    ClientId = configOptions.AzureAd.ClientId,
    ClientSecret = configOptions.AzureAd.ClientSecret, // for code flow
    Authority = Constants.AuthEndpointPrefix,
    ResponseType = OpenIdConnectResponseType.CodeIdToken,
    PostLogoutRedirectUri = configOptions.AzureAd.PostLogoutRedirectUri,
    SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
    TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false },
    Events = new SurveyAuthenticationEvents(configOptions.AzureAd, loggerFactory),
});

Once you have disabled the Validate issuer, you will need to handle the validation yourself. Here is a sample with some guidance around how to do this validation yourself

Update your code to handle multiple issuer values

You will at least need to check the "tid" claim which captures the Azure AD Tenant Id against your own list of valid tenant IDs, before you let the call go through.

When a single tenant application validates a token, it checks the signature of the token against the signing keys from the metadata document, and makes sure the issuer value in the token matches the one that was found in the metadata document.

Since the /common endpoint doesn't correspond to a tenant and isn't an issuer, when you examine the issuer value in the metadata for /common it has a templated URL instead of an actual value:

https://sts.windows.net/ {tenantid}/

Therefore, a multi-tenant application can't validate tokens just by matching the issuer value in the metadata with the issuer value in the token. A multi-tenant application needs logic to decide which issuer values are valid and which are not, based on the tenant ID portion of the issuer value.

For example, if a multi-tenant application only allows sign in from specific tenants who have signed up for their service, then it must check either the issuer value or the tid claim value in the token to make sure that tenant is in their list of subscribers. If a multi-tenant application only deals with individuals and doesn't make any access decisions based on tenants, then it can ignore the issuer value altogether.

(EDIT) More information on Validating Tokens I'm trying to answer your questions from comments here.

  1. Here is sample code which does the task of manually validating JWT tokens. Manually validating a JWT access token in a web API

在此处输入图片说明

A useful excerpt..

Validating the claims When an application receives an access token upon user sign-in, it should also perform a few checks against the claims in the access token. These verifications include but are not limited to:

audience claim, to verify that the ID token was intended to be given to your application not before and "expiration time" claims, to verify that the ID token has not expired issuer claim, to verify that the token was issued to your app by the v2.0 endpoint nonce, as a token replay attack mitigation You are advised to use standard library methods like JwtSecurityTokenHandler.ValidateToken Method (JwtSecurityToken) to do most of the aforementioned heavy lifting. You can further extend the validation process by making decisions based on claims received in the token. For example, multi-tenant applications can extend the standard validation by inspecting value of the tid claim (Tenant ID) against a set of pre-selected tenants to ensure they only honor token from tenants of their choice.

  1. Sample Access Token, just for understanding: Access Token and Id_token are both simple base64 encoded JSON Web Tokens (JWT). You can decode these to find the claims and then validate them. I'm sharing a sample which has code to do just that. Before that here is a sample access token from one of Microsoft Docs. I just took one for example from here

Actual Value: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N... (a long encoded string continues) Decoded Value (you can check this easily using a website like https://jwt.io ):

{
  "aud": "https://service.contoso.com/",
  "iss": "https://sts.windows.net/7fe81447-da57-4385-becb-6de57f21477e/",
  "iat": 1388440863,
  "nbf": 1388440863,
  "exp": 1388444763,
  "ver": "1.0",
  "tid": "7fe81447-da57-4385-becb-6de57f21477e",
  "oid": "68389ae2-62fa-4b18-91fe-53dd109d74f5",
  "upn": "frankm@contoso.com",
  "unique_name": "frankm@contoso.com",
  "sub": "deNqIj9IOE9PWJWbHsftXt2EabPVl0Cj8QAmefRLV98",
  "family_name": "Miller",
  "given_name": "Frank",
  "appid": "2d4d11a2-f814-46a7-890a-274a72a7309e",
  "appidacr": "0",
  "scp": "user_impersonation",
  "acr": "1"
}

As you can see the decoded value has many claims including "tid" which you're about to validate.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM