Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiple AAD authentication options using AddMicrosoftIdentityWebAppAuthentication not possible #971

Closed
1 of 8 tasks
wmmihaa opened this issue Feb 15, 2021 · 24 comments
Closed
1 of 8 tasks
Labels
duplicate This issue or pull request already exists enhancement New feature or request fixed multiple auth schemes supported in v.1.10
Milestone

Comments

@wmmihaa
Copy link

wmmihaa commented Feb 15, 2021

Which version of Microsoft Identity Web are you using?
Microsoft Identity Web 1.6.0

Where is the issue?

  • Web app
    • Sign-in users
    • Sign-in users and call web APIs
  • Web API
    • Protected web APIs (validating tokens)
    • Protected web APIs (validating scopes)
    • Protected web APIs call downstream web APIs
  • Token cache serialization
    • In-memory caches
    • Session caches
    • Distributed caches
  • Other (please describe)

I have an app which needs to support authentication using multiple AAD's, but if I try to call AddMicrosoftIdentityWebAppAuthentication multiple times it seams that only the last one takes affect, but I get a "Unable to unprotect the message.State" exception although I've set different CallbackPath.

Is there an other way to do this?

  "azuread1": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "azuread1.onmicrosoft.com",
    "TenantId": "xxxxx",
    "ClientId": "xxxxxx",
    "ClientSecret": "xxxxx",
    "CallbackPath": "/signin-oidc/azuread1",
    "SignedOutCallbackPath": "/signout-callback-oidc"
  },
 "azuread2": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "azuread2.onmicrosoft.com",
    "TenantId": "yyyyy",
    "ClientId": "yyyyy",
    "ClientSecret": "yyyyy",
    "CallbackPath": "/signin-oidc/azuread2",
    "SignedOutCallbackPath": "/signout-callback-oidc"
  },
services.AddMicrosoftIdentityWebAppAuthentication(configuration: Configuration,
                                                              configSectionName: "azuread1",
                                                              openIdConnectScheme: "azuread1",
                                                              cookieScheme: null);

 services.AddMicrosoftIdentityWebAppAuthentication(configuration: Configuration,
                                                              configSectionName: "azuread2",
                                                              openIdConnectScheme: "azuread2",
                                                              cookieScheme: null);

If I try to logging using azuread1 it will say the user dows not exist in azuread2.onmicrosoft.com, while if I log in using azuread2 I get an "Unable to unprotect the message.State" exception.

@jmprieur jmprieur added duplicate This issue or pull request already exists enhancement New feature or request labels Feb 17, 2021
@jmprieur
Copy link
Collaborator

@wmmihaa : this is duplicate of #955

@wmmihaa
Copy link
Author

wmmihaa commented Feb 17, 2021

@wmmihaa : this is duplicate of #955

Not sure it is as this relates to multiple auth schemes of the same type

@wmmihaa
Copy link
Author

wmmihaa commented Feb 22, 2021

Is there a plan to support integration with multiple AAD using AddMicrosoftIdentityWebAppAuthentication?

@jmprieur
Copy link
Collaborator

@wmmihaa : AddMicrosoftIdentityWebAppAuthentication is a shortcut for the simple case where you don't want to specify the scheme, whereas the multi AAD scenario is the very case where you want to control the scheme.
You'll want to do;

AddAuthentication(defaultScheme)
 .AddMicrosoftIdentityWebApp(configSection1, scheme1)

AddAuthentication()
 .AddMicrosoftIdentityWebApp(configSection2, scheme2)

We think we'll work on supporting this in 1.18.

@wmmihaa
Copy link
Author

wmmihaa commented Feb 23, 2021

I think the problem is in SignInManager.ConfigureExternalAuthenticationProperties which will always route to the same AAD independently of the provider...

public IActionResult OnPost(string provider, string returnUrl = null)
{
    // Request a redirect to the external login provider.
    var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
    var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
    return new ChallengeResult(provider, properties);
}

The line above will always route to the last added Authentication ...

StartUp.cs:

services.AddAuthentication(("azuread1)
    .AddMicrosoftIdentityWebApp(Configuration.GetSection("azuread1"), "azuread1", null);

services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(Configuration.GetSection("azuread2"), "azuread2", null);

Each of the line above work by it self, but not together

Let me know if you want med to demo this through a teams session

@wmmihaa
Copy link
Author

wmmihaa commented Feb 24, 2021

I've made short video to better explain the scenario and issue.
https://youtu.be/SSuciNOnt-0
hth

@wmmihaa
Copy link
Author

wmmihaa commented Feb 25, 2021

I've raised the issue in the aspnetcore repo: dotnet/aspnetcore#30472

@wmmihaa
Copy link
Author

wmmihaa commented Mar 3, 2021

Any news on this?
btw...I would not consider this an enhancement but a bug

dotnet/aspnetcore#30472 is closed so this is no longer duplicate.

@jmprieur
Copy link
Collaborator

jmprieur commented Mar 4, 2021

@wmmihaa : we are currently working on higher priority very requested features (performance and resilience of the token cache adapters, and rotation of certificates)
This would be next.

@wmmihaa
Copy link
Author

wmmihaa commented Mar 4, 2021

@jmprieur Thank you for the feedback. We will continue working on other things while we wait.

@jmprieur jmprieur added this to the 1.9.0 milestone Mar 4, 2021
@jennyf19 jennyf19 modified the milestones: 1.9.0, 1.10.0 Mar 31, 2021
@jennyf19
Copy link
Collaborator

jennyf19 commented May 5, 2021

@wmmihaa we have a preview package w/multiple auth scheme support. If you'd like to try it out, please send me an email: jeferrie@microsoft.com and I will send you the nuget package. we are still testing, so it's not on nuget yet.

@jennyf19 jennyf19 added fixed multiple auth schemes supported in v.1.10 labels May 5, 2021
@jennyf19 jennyf19 modified the milestones: 1.10.0, 1.11.0 May 14, 2021
@jennyf19
Copy link
Collaborator

Included in 1.11.0 release and documentation here.

@wmmihaa
Copy link
Author

wmmihaa commented May 24, 2021

Thank you @jennyf19

@sven5
Copy link

sven5 commented Jul 8, 2021

@wmmihaa Do you get it working with the new version?
I'm not successful. I already tried several combinations, still no luck.
Could you provide some demo code?

Thanks!

@wmmihaa
Copy link
Author

wmmihaa commented Jul 8, 2021

Hi Sven,
Yes it works for me. We're using v 1.14.0 (Microsoft.Identity.Web & Microsoft.Identity.Web.UI):

Startup.cs - ConfigureServices

foreach (var section in Configuration.GetSection("azureAd").GetChildren())
{
    services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(section, section.Key, null);
}

appsettings.json

  "azureAd": {
    "AAD1": {
      "Instance": "XXX",
      "Domain": "XXX",
      "TenantId": "XXX",
      "ClientId": "XXX",
      "CallbackPath": "/signin-oidc/aad1"
    },
    "AAD2": {
      "Instance": "https://login.microsoftonline.com/",
      "Domain": "XXX",
      "TenantId": "XXX",
      "ClientId": "XXX",
      "ClientSecret": "XXX",
      "CallbackPath": "/signin-oidc/aad2"
    }
  }

HTH

@sven5
Copy link

sven5 commented Jul 9, 2021

Ok my scenario is a little different. I'd like to use AAD and AAD B2C together in one web app.

services.AddAuthentication()
                    .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), Microsoft.Identity.Web.Constants.AzureAd, "cookiesAd");

services.AddAuthentication()
                   .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C"), Microsoft.Identity.Web.Constants.AzureAdB2C, "cookiesB2C");

My problem is that after logging in by using AAD the User is not authenticated in the app. Both authentication methods never work at the same time

@sven5
Copy link

sven5 commented Jul 9, 2021

Ok, now I've found my mistake. The important thing is passing the value of null to the cookieScheme parameter and setting Cookie Authentication as default.

@Faisal-developer
Copy link

@wmmihaa Is it working ? And how you differentiate that which user will be part of which tenant ?

How you modified this below code

public IActionResult OnPost(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}

@wmmihaa
Copy link
Author

wmmihaa commented Aug 15, 2022

Hi Faisal,
Yes I got it working.

And how you differentiate that which user will be part of which tenant ?

There are a couple of ways you can do this. Default, you'd allow the user to select which identity provider to use. In my case,I persist each AAD configuration in the database together with the email domain and as the user types their email address I redirect based on the domain.

How you modified this below code...

Your code looks good

@Faisal-developer
Copy link

Faisal-developer commented Aug 15, 2022

@wmmihaa Got it. You are using this for mobile app ? I meaning azure ad is integrated with mobile app or using web app ?

@wmmihaa
Copy link
Author

wmmihaa commented Aug 15, 2022

It's a web application

@Faisal-developer
Copy link

@wmmihaa Do you have any idea how it will work for flutter mob app ?

@wmmihaa
Copy link
Author

wmmihaa commented Aug 15, 2022

Sorry, I have not worked with flutter.

@rafaelcaviquioli
Copy link

I have the following configuration, AzureAdB2C is set as default, but when I open the application, I'm forwarded to AzureAdB2C signin page.

I would expect that when the user tries to open a not public page, it is forwarded to the auth provider configured in the default scheme.

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        configuration.Bind("AzureAdB2C", options);
        options.Events ??= new OpenIdConnectEvents();
        options.ResponseType = OpenIdConnectResponseType.Code;
        options.Scope.Add(options.ClientId);
    }, subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true, cookieScheme: null);

services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(options =>
    {
        configuration.Bind("AzureAdB2C", options);
        // Replace with invitation custom policy and callback urls 
        configuration.Bind("AzureAdB2CInvitation", options);

        options.ResponseType = OpenIdConnectResponseType.Code;
        options.Scope.Add(options.ClientId);
        options.Events ??= new OpenIdConnectEvents();
        
        options.Events.OnRedirectToIdentityProvider += async (context) =>
        {
            var idTokenHint = context.Request.Query["id_token_hint"];
            if (!string.IsNullOrEmpty(idTokenHint))
            {
                context.ProtocolMessage.IdTokenHint = idTokenHint;
            }
            await Task.CompletedTask.ConfigureAwait(false);
        };
    }, subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true, openIdConnectScheme: InvitationScheme, cookieScheme: null);

I also have this policy configured:

services
    .AddMvcCore()
    .AddApiExplorer()
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme, AuthenticationExtensions.InvitationScheme)
            .RequireAuthenticatedUser()
            .Build();
        
        options.AddPolicy(AuthenticationExtensions.SmAccessPolicy, policy =>
        {
            policy.AddAuthenticationSchemes(
                OpenIdConnectDefaults.AuthenticationScheme,
                AuthenticationExtensions.InvitationScheme
            );
            policy.RequireAssertion(context => context.User.HasClaim(c => c.Type == "extension_roles" && c.Value.Split(",").Contains("product.sm")));
        });
    })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists enhancement New feature or request fixed multiple auth schemes supported in v.1.10
Projects
None yet
Development

No branches or pull requests

6 participants