Skip to content

Conversation

@jmprieur
Copy link
Contributor

Adding flexibility for the authority and audience (to enable the Azur…e AD v2.0 endpoint)

Summary of the changes (Less than 80 chars)

  • Improving the XML comments for AzureADOptions (to help for Azure AD v2.0 and sovereign cloud support)
  • Adding the notion of Authority which is now computed from the Instance and ClientId, so that AzureAD v2.0 can be supported (Authority would therefore be https://{Instance}/{TenantId}/v2.0)
  • Adding the notion of Audience for Web APIs so that it can be set (for instance to api://{tenantId} in v2.0)

Addresses requests for supporting Azure AD v2.0 (Microsoft identity platform for developers)

This is similar to aspnet/AADIntegration#49, but without breaking changes. This will enable supporting Azure AD v2.0 naturally (from the templates)

@jmprieur jmprieur changed the title Adding flexibility for the authority and audience Adding flexibility for the authority and audience to support Azure AD v2.0 Feb 25, 2019
@jmprieur
Copy link
Contributor Author

looking at the test failures

/// <summary>
/// Azure Active Directory Authority
/// </summary>
public string Authority { get; set; } = "{Instance}{TenantId}";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem to be more like string templates and not default values. It should then be the responsability of *Configuratgion.cs to create default values if the user hasn't set any.

i.e. Just tell the user that the default value will be {Instance}{TenantId} if he does not set anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well this is {Instance}{TenantId}/v2.0 in the case of v2.0.
See also the templates.

@Tratcher Tratcher self-assigned this Feb 25, 2019
Copy link

@henrik-me henrik-me left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@Tratcher Tratcher added this to the 3.0.0-preview4 milestone Feb 25, 2019
@Eilon Eilon added the area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer label Feb 25, 2019
Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: after fixing the tests.

//#endif
// },
//#endif
////#if (IndividualB2CAuth)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this just a whitespace change? If so revert.


/// <summary>
/// Gets or sets the Azure Active Directory instance.
/// Typical values are:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

////#elseif (OrganizationalAuth)
// "AzureAd": {
// "Instance": "https:////login.microsoftonline.com/",
// "Autority": "{Instance}{TenantId}/v2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the same order in both templates.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tratcher : the templates are in a different order already today (I was surprised too). I did not change the order.


options.Audience = azureADOptions.ClientId;
options.Authority = new Uri(new Uri(azureADOptions.Instance), azureADOptions.TenantId).ToString();
options.Audience = string.Format(azureADOptions.Audience?.Replace("{ClientId}", "{0}"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has several problems.

  • What happens if azureAdOptions.Audience is null? (It's not ok to show explicitly on the template config file).
  • We don't do replacements this way. azureADOptions.Audience?.Replace("{ClientId}", "{0}"
    • Normally we use a string interpolation.
  • Same for authority below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javiercn : how can we use string interpollation for a string which is not in the code, but in a config file? could you please show me an example on how to do it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmprieur how is azureADOptions populated?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javiercn is there a way to enforce some type of validation, For example, azureADOptions.Audience must be populated correctly from config?

// "Instance": "https:////login.microsoftonline.com/",
// "Autority": "{Instance}{TenantId}/v2.0",
//#if (MultiOrgAuth)
// "TenantId": "organizations",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this now? MultiOrg is kind of it's own beast and it used to point to https:////login.microsoftonline.com/common would this now point to https:////login.microsoftonline.com/organizations?

Asa general principle we don't introduce concepts in the template if we don't absolutely need to, so could this go back to the way it was before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in Azure AD v2.0, common means AAD+MSA whereas in Azure AD v1.0 it used to mean "AAD multi-org.
To say AAD multi-org in "Azure AD v2.0", one needs to use organizations. I proposed this one, in order to not change the behavior of the template (by using organizations with a v2.0 template, it behaves as common for a v1.0 template).

////#elseif (OrganizationalAuth)
// "AzureAd": {
// "Instance": "https:////login.microsoftonline.com/",
// "Autority": "{Instance}{TenantId}/v2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation too

@javiercn
Copy link
Member

Thanks for the contribution!
The overall changes look good, but there are a few things I think we need to consider (or I would like to understand better) before we move forward with this:

  • Adding the notion of Authority which is now computed from the Instance and ClientId, so that AzureAD v2.0 can be supported (Authority would therefore be https://{Instance}/{TenantId}/v2.0)
  • Adding the notion of Audience for Web APIs so that it can be set (for instance to api://{tenantId} in v2.0)
  • Are these just fixed ways of configuring the OIDC options to match what the endpoints for AzureAD V2 expect?
  • Is the format for the Azure AD V2 endpoints fixed but just different or do we truly need for you to be able to put anything on the Authority and Audience fields.
    • If we were to only support V2, could these be computed from the inputs that we already collect?
  • Are the V1 endpoints going to be working (which I presume for at least some time)?
  • Are the V2 endpoints GA?
  • Can users be switched from V1 to V2 endpoints without any visible changes to the responses produced by Azure AD (Response formats, claims, required parameters, etc)?

Based on what I can see from looking at the code I think we can do this without explicitly introducing Audience and Authority explicitly on the Options type and on the templates.
We can simply tag this information to each of the mappings in
https://github.com/aspnet/AspNetCore/blob/master/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADSchemeOptions.cs
Flow it from
https://github.com/aspnet/AspNetCore/blob/master/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADAuthenticationBuilderExtensions.cs#L99
and use it
https://github.com/aspnet/AspNetCore/blob/master/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADOpenIdConnectOptionsConfiguration.cs#L32
To configure the values appropriately.

Startup wise there are several ways we can do this, including not doing anything at all.

Implicit version on the method name.

services.AddAuthentication().AddAzureADV2

Explicit as a parameter

services.AddAuthentication().AddAzureADV2(
    AzureADEndpointVersion.2_0,
    options => Configuration.Bind(options));

As part of the options type

services.AddAuthentication().AddAzureAD(options => { Configuration.Bind(options); options.EndpointVersion = AzureADEndpointVersion.2_0 });

We migrate users forward (if endpoints are forward compatible)

services.AddAuthentication().AddAzureAD(options => Configuration.Bind(options));

With an additional extension method (if endpoints are forward compatible)

services
   .AddAuthentication()
   .AddAzureAD(options => Configuration.Bind(options))
   .(Enable/Use/Configure/Other/)AzureADEndpointVersion(AzureADEndpointVersion.Latest);

We just patch the OIDC and JwtBearer options respectively on the template:

services
   .AddAuthentication()
   .AddAzureAD(options => Configuration.Bind(options))
   .(Enable/Use/Configure/Other/)AzureADEndpointVersion(AzureADEndpointVersion.Latest);
services.Configure<OpenIdConnectOptions>(options => {
    options.Audience = $"api://{options.ClientId}",
    options.Authority = $"{options.Authority}/v2.0"
});

No matter what, this needs input from our PM team as it changes the templates and introduces new concepts in the users faces, either in config or in startup.

For the rest of the ASP.NET Team, we would need to explicitly test the templates for this change before merging.

@jmprieur
Copy link
Contributor Author

jmprieur commented Mar 4, 2019

@javiercn : thanks for your review and feedback. To answer your questions:

Are these just fixed ways of configuring the OIDC options to match what the endpoints for AzureAD V2 expect?
Is the format for the Azure AD V2 endpoints fixed but just different or do we truly need for you to be able to put anything on the Authority and Audience fields.

The Microsoft identity platform (fomerly AAD v2.0) supports the notion of authority in the following way. For the AzureAD.UI components, we don't need to bother here about B2C and ADFS, but giving the big picture.

image

If we were to only support V2, could these be computed from the inputs that we already collect?
I guess yet.

This might not be completely natural, but you provided good alternative ideas here. (See at the end of this comment)

Are the V1 endpoints going to be working (which I presume for at least some time)?
Yes the v1.0 endpoints still work and will be maintained.

Are the V2 endpoints GA?
It depends on the scenario, but for Web App (which are the target of the changes below), this has been availble since Connect (Nov) 2017, and has GAed in 2018.

Can users be switched from V1 to V2 endpoints without any visible changes to the responses produced by Azure AD (Response formats, claims, required parameters, etc)?

That's a good question which I had a bit overlooked: there are actually changes in the claims as, if going to the v1.0 authorize endpoint, Web apps will receive a v1.0 token, whereas when going to the v2.0 authorize endpoint, they will receive a v2.0 tokens. More about the tokens differences here: IDToken and AccessToken. In particular the name is, in v2.0 prefered_username

@javiercn : overall thanks for your feedback on the alternatives. Interestingly some are quite close to some of our implementation in the Web App tutorial. Could you please have a look at the following code and give your feedback (it's very small).

https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/78a07c913eced00c0a128fbbb11b2c1449ee404e/Microsoft.Identity.Web/StartupHelpers.cs#L28-L95

I'm starting to think that this might be what we to do, and not change the templates

@Tratcher Tratcher assigned javiercn and unassigned Tratcher Mar 4, 2019
@Eilon
Copy link
Contributor

Eilon commented Apr 18, 2019

@jmprieur / @javiercn - are we clear on the next steps for this? Are we waiting for feedback?

@mkArtakMSFT mkArtakMSFT removed this from the 3.0.0-preview4 milestone Apr 22, 2019
@javiercn
Copy link
Member

javiercn commented Apr 22, 2019

@Eilon I think if we are willing to take a breaking change here, we can update the implementation to point to the 2.0 endpoints, and 3.0 is a good timeframe to do so. We don't need to add new concepts, simply change the implementation.

We would have to take a look at the claim-set difference between 1.0 endpoints and 2.0 endpoints, but I don't expect it to be an issue.

From the sample @jmprieur provided seems that there might be smaller tweaks we can do to improve the E2E experience (like around account selection) so I think there's some value in moving to the 2.0 endpoints.

That said, we need a PM on our team to chime in. @danroth27 or @blowdart should be the ones to say something. I expect this to be an M sized workitem.

My opinion (in case it's not clear) is that we don't add additional methods or support both scenarios side -by-side (v1 and v2 endpoints) with the same package, but that we break and update.

In the end, you can always implement this by yourself, our package just makes it convenient.

@Eilon
Copy link
Contributor

Eilon commented Apr 22, 2019

Sounds good @javiercn . We'll review with @blowdart this week.

@blowdart
Copy link
Contributor

The token differences concern me, everything must map the same to the resulting identity, no matter what version of the endpoint is used. That needs to be guaranteed :)

@javiercn
Copy link
Member

@blowdart not necessarily. If AAD versioned the endpoints I imagine is because they wanted to do breaking changes.

We can take the 3.0 opportunity to update. I’m not concerned about the fundamental claims of the token changing.

But whatever you guys feel like.

@javiercn
Copy link
Member

Waiting here for a decision fro @blowdart on whether or not we should do anything here. @Eilon if the answer is we don't want to update, then I think we can close this PR, as you can still manually update the config to target 2.0 endpoints if you choose do to so.

@blowdart
Copy link
Contributor

The change of the email address claim to a very non-standard "preferred_username" would need addressing, otherwise it's never going to work for people upgrading and who are using email as their default key, rather than sub (because sub isn't obviously the right one to use).

The sample tokens also show "given name" / "family name" changing to "name".

So, I'd need to see token contents for exactly the same user before decided if we can afford the change in 3.0, given the possibility of extra work, because it doesn't look like it's just pointing to the new endpoint.

@javiercn
Copy link
Member

@blowdart You can get the email on the email claim by asking for the email scope (which we can ask for by default and is more standard compliant).

This is the V1 token

Claim Value
aud b14a7505-96e9-4927-91e8-0601d0fc9caa
iss https://sts.windows.net/fa15d692-e9c7-4460-a743-29f2956fd429/
iat Thu Sep 06 2018 16:05:24 GMT-0700 (Pacific Daylight Time)
nbf Thu Sep 06 2018 16:05:24 GMT-0700 (Pacific Daylight Time)
exp Thu Sep 06 2018 17:10:24 GMT-0700 (Pacific Daylight Time)
aio AXQAi/8IAAAAqxsuB+R4D2rFQqOETO4YdXbLD9kZ8xfXadeAM0Q2NkNT5izfg3uwbWSXhuSSj6UT5hy2D6WqApB5jKA6ZgZ9k/SU27uV9cetXfLOtpNttgk5DcBtk+LLstz/Jg+gYRmv9bUU4XlphTc6C86Jmj1FCw==
amr rsa
email abeli@microsoft.com
family_name Lincoln
given_name Abe
idp https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/
ipaddr 131.107.222.22
name abeli
nonce 123523
oid 05833b6b-aa1d-42d4-9ec0-1b2bb9194438
rh I
sub 5_J9rSss8-jvt_Icu6ueRNL8xXb8LF4Fsg_KooC2RJQ
tid fa15d692-e9c7-4460-a743-29f2956fd429
unique_name AbeLi@microsoft.com
uti Lxe_46GqTkOpGSfTln4EAA
ver 1.0

This is the V2 token

Claim Value
ver 2.0
iss https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
sub AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ
aud 6cb04018-a3f5-46a7-b995-940c78f5aef3
exp Fri Sep 07 2018 16:03:31 GMT-0700 (Pacific Daylight Time)
iat Thu Sep 06 2018 15:58:31 GMT-0700 (Pacific Daylight Time)
nbf Thu Sep 06 2018 15:58:31 GMT-0700 (Pacific Daylight Time)
name Abe Lincoln
preferred_username AbeLi@microsoft.com
oid 00000000-0000-0000-66f3-3332eca7ea81
tid 3338040d-6c67-4c5b-b112-36a304b66dad
nonce 123523
aio Df2UVXL1ix!lMCWMSOJBcFatzcGfvFGhjKv8q5g0x732dR5MB5BisvGQO7YWByjd8iQDLq!eGbIDakyp5mnOrcdqHeYSnltepQmRp6AIZ8jY

We can likely configure the V2 default set of claims to include the email and other claims based on open id. Overall I think it's worth pointing the size reduction of the token and the standarization.

@blowdart
Copy link
Contributor

As long as the claims that the eventual identity is constructed from will match from one version to the next, so there's no unexpected loss then I'm ok with it.

@javiercn
Copy link
Member

javiercn commented Apr 23, 2019

@jmprieur Do you think this can be achieved? Or is there any claim that is gone forever (that matters) that we can't bring back by requesting some other scopes by default.

@bgavrilMS
Copy link

@javiercn @blowdart - just to note that Jean-Marc is OOF until 30th, please expect delays in his answers.

You can have a look at the optional claims you can request for v1 and v2 endpoints here: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims

@brentschmaltz
Copy link
Contributor

@blowdart if the tokens contain different claims, the ClaimsIdentity will not be the same.

/// Gets or sets the audience for a Web API (This audience needs
/// to match the audience of the tokens sent to access this application)
/// </summary>
public string Audience { get; set; } = "{ClientId}";
Copy link
Contributor

@brentschmaltz brentschmaltz May 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow the setters to accept null or empty strings?
Similar for all these setters.

/// </list>
/// </summary>
public string Instance { get; set; }
public string Instance { get; set; } = "https://login.microsoftonline.com/";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there ever a time when these can be empty or null?

azureADOptions.Instance, azureADOptions.TenantId);
}

public void Configure(JwtBearerOptions options)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't seem to do anything.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It implements the interface https://github.com/aspnet/Extensions/blob/master/src/Options/Options/src/IConfigureOptions.cs#L11

Though I'm not sure if this is correct - should it be doing something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, as this class only targets named configuration instances.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A code comment might be useful, then.


options.Audience = azureADOptions.ClientId;
options.Authority = new Uri(new Uri(azureADOptions.Instance), azureADOptions.TenantId).ToString();
options.Audience = string.Format(azureADOptions.Audience?.Replace("{ClientId}", "{0}"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add some parameter checks for nulls.

@analogrelay
Copy link
Contributor

We're not going to be able to take this in 3.0. We can revisit in 3.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants