OrchardCore icon indicating copy to clipboard operation
OrchardCore copied to clipboard

Support AzureAD B2C

Open Narnain opened this issue 5 years ago • 47 comments

Please support AzureAD B2C under Microsoft Authentication.

Narnain avatar May 27 '19 16:05 Narnain

@MichaelPetrinolis isn't it already supported?

sebastienros avatar May 30 '19 19:05 sebastienros

We support Azure AD and Azure B2B which is a feature of AAD. Azure B2C is a different service. It is a good candidate to replace local authentication, as @PinpointTownes said in #2029. Otherwise it would need roles synchronization and disabling local pasword login for users.

MichaelPetrinolis avatar May 31 '19 08:05 MichaelPetrinolis

Then maybe we should see if we could integrate with other IDaaS providers like auth0, okta, etc...?

psijkof avatar Jul 05 '19 13:07 psijkof

@psijkof you can use the OpenID connect client to link local users with another IDaaS provider

MichaelPetrinolis avatar Jul 05 '19 15:07 MichaelPetrinolis

Where are we at with this it is a year later, we are attempting to integrate with Azure AD B2C right now but after finding this post I wonder if it is pointless?

nanderto avatar Apr 06 '21 17:04 nanderto

I'm interested in this exact scenario. Are there some specific stumbling blocks to be aware of? I notice that it is currently marked for the 1.1 milestone but if we need to roll our own due to time constraints it would help if had an idea of potential problems.

jimitndiaye avatar Sep 23 '21 18:09 jimitndiaye

Hello, have we made any progress on this one? I have it configured, but am getting an error upon login :

An unhandled exception occurred while processing the request. OpenIdConnectProtocolException: IDX21336: Both 'id_token' and 'access_token' should be present in OpenIdConnectProtocolValidationContext.ProtocolMessage received from Token Endpoint. Cannot process the message. Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator.ValidateTokenResponse(OpenIdConnectProtocolValidationContext validationContext)

Exception: An error was encountered while handling the remote login. Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()

aderderian avatar Jul 02 '22 14:07 aderderian

It seems you have configured a flow that requires ID and Access token, like hybrid. If this is your case, I suppose you must configure azuread to provide them for your client. I haven't use B2C but the documentation states it can be used with OpenID connect, so you should be able to configure both parties to work together.

MichaelPetrinolis avatar Jul 02 '22 14:07 MichaelPetrinolis

I am configuring it using the OC Orchard OpenId Client Setup...I configured a basic flow in Azure B2C. Is there a recommend config you know works on both ends? Do I need to set it in Azure Settings to use openid connect somehow? Thanks @MichaelPetrinolis !

aderderian avatar Jul 02 '22 15:07 aderderian

I would try to require OpenID profile and email scopes on orchard core side and enable id_token and access token on server side.

MichaelPetrinolis avatar Jul 02 '22 15:07 MichaelPetrinolis

I think I have all that : Here is the config :

image

image

image

aderderian avatar Jul 02 '22 16:07 aderderian

@MichaelPetrinolis setting up OC OIDC Client settings to use Implicit Flow instead of Code or Hybrid got it working. I am still getting an issue where it is requiring an email for registration and failing for some reason. I added 'email' scope to additional scope in OC settings and am not asking for email in settings.

image

aderderian avatar Jul 05 '22 19:07 aderderian

@aderderian you must add the email claim in AzureAD B2C. Check the documentation. In the AzureAD integration how-to guide we do the same, we add the email optional claim.

MichaelPetrinolis avatar Jul 05 '22 21:07 MichaelPetrinolis

Just an update here :

@MichaelPetrinolis I had reviewed the docs but they are for Azure AD and not Azure B2C. The problem is you can't get the email claim to come back with Azure B2C using the User Flows configuration.

For some reason it takes the User Attribute and puts it into an "emails" claim instead of the expected "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" claim OC expects. You can't select "Email Address" as a "Return Claim" for some reason.

image

I am looking into how to leverage a Custom Policy to send this along, but at the moment the email claim not being sent is prevented the account from being created.

Related Article : https://stackoverflow.com/questions/66021121/azure-ad-b2c-email-claim-is-missing-from-jwt-with-standard-sign-up-policy

aderderian avatar Jul 06 '22 18:07 aderderian

@aderderian so it seems you need to add <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/> in your TrustFrameworkBase.xml file.

MichaelPetrinolis avatar Jul 07 '22 05:07 MichaelPetrinolis

Thanks @MichaelPetrinolis . Is there a blog or document you could point me to on how to take an Out of the Box User Flow and just edit that single line in the existing TrustFrameworkBase.xml file? The path I took was downloading the existing xml for my signin process as well as the other 4 base policies behind it. I then had to split them out and re-upload to custom policies. Super manual and painful process. I also had to create two apps and 4 secrets just to support this. Is there an easier way to achieve this one line change?

Any advice would be great. I think then this ticket could be closed as supported by OC. I can summarize in docs if it helps others as well.

Blogs I looked at :

Step 1 - https://blog.wojtek.pro/azure-ad-b2c-custom-policies-how-to-begin/ Step 2 - https://blog.wojtek.pro/azure-ad-b2c-custom-policies-importing-the-exported/ Step 3 - https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy#register-applications

aderderian avatar Jul 07 '22 14:07 aderderian

@MichaelPetrinolis any idea on how you modify this one setting you mentioned without having to build custom policies? Is there a way to update this TrustFrameworkBase.xml using the baked in User Flows? Thx

aderderian avatar Jul 11 '22 17:07 aderderian

@aderderian unfortunately I haven't used Azure AD B2C. Maybe you should ask Azure Support for help.

MichaelPetrinolis avatar Jul 11 '22 18:07 MichaelPetrinolis

@MichaelPetrinolis do you think we should add an option to allow the email for the account to look at the "emails" claim as well as a setting or fallback so we can support B2C out of the box? We could also add a setting to configure which claim we want to use or override it?

aderderian avatar Jul 12 '22 13:07 aderderian

@aderderian maybe we should extend the IExternalLoginEventHandler and add a method to define the email in the context, and use that in order to match an existing user. But email and email_verified are standard claims defined in the openid spec and they should be used if no email is set in the context.

MichaelPetrinolis avatar Jul 12 '22 22:07 MichaelPetrinolis

@MichaelPetrinolis I have a call with MSFT soon, I will ask why B2C does not return the standard claims here. From what I read online this is by design?? I will also look at IExternalLoginEventHandler. Thanks for all your continued support.

aderderian avatar Jul 13 '22 14:07 aderderian

@MichaelPetrinolis I spoke with MSFT and they're investigating this issue with the email claim not being returned as well. Secondarily, in the end of all this I want to be able to use Azure B2C as my central authorization provider. @sfmskywalker wrote an article some time ago (https://medium.com/swlh/orchard-core-open-id-connect-and-graphql-f003a222260a) that involved using JWTs to validate GraphQL calls via the Token Validation module. The scenario I am testing now is that when I use Azure B2C as my Authentication Provider for OC and then have a completely separate Web App that uses Azure B2C auth, I can't use the token that comes back from Azure B2C via the Web App to then query the GraphQL module. I want to use OC in a headless way so I can return content to my web app via GraphQL.

The issue I am getting is that the ValidationOptions are failing with the Issuer not matching. When you use the Token Validation module I set the Authority to the policy endpoint like in the Client Settings. ({https://xxx.b2clogin.com/{domain}/B2C_1_Blazor_SignUp_Signin/v2.0}

This results in the Issuer in the token being "https://xxx.b2clogin.com/{tenantid}/v2.0/" and the issuer it seems to be matching on being "https://xxx.b2clogin.com/{domain}/B2C_1_Blazor_SignUp_Signin/v2.0". Any insight here? Has anyone used an extracted provider in this way?

It is saying it is supposed to download the Issuer using the metadata document, but I don't see this happening on load of the module. And later on it is not replacing the value when it issues the request :

https://github.com/iaspnetcore/OrchardCore/blob/d424bd7793fe2fa1f0b4c73c6142a5f2c57ee94c/src/OrchardCore.Modules/OrchardCore.OpenId/Configuration/OpenIdValidationConfiguration.cs#L99

aderderian avatar Jul 25 '22 21:07 aderderian

So I solved the issue with uploading a custom policy to AzureB2C and following a simpler route than the blogs provided.

The remaining issue here is the TokenValidation module. @iaspnetcore wrote the module it seems. Anyone who is more experience with OIDC and this module understand the problem here with the token not being validated? @MichaelPetrinolis ?

aderderian avatar Aug 20 '22 13:08 aderderian

Good to hear that you solved the issue with email claim and AzureB2C! If you can, please share the solution in case anyone else tries to use AzureB2C with OC.

Now, If I understand correctly, you have the following scenario

  1. OC Identity Provider that uses AzureB2C as external Provider. So all your users are in AzureB2C and they are authenticated through OC IdP.
  2. A SPA application that authenticates with OC.
  3. An API that is protected by AzureB2C
  4. Authenticate users from SPA with OC IdP and store the user tokens provided by AzureB2C.
  5. Make calls from SPA to API with the stored user tokens

check the .well-known/openid-configuration/jwks of the AzureB2C authority to see the metadata it receives. OrchardCore OpenId Token Validation feature is based on the fantastic OpenIdDict lib, written by @kevinchalet, and should work out of the box for OpenIdConnect authorities.

MichaelPetrinolis avatar Aug 20 '22 15:08 MichaelPetrinolis

I will definitely post the solution here!

Your description is a little off. Here it is and picture below.

  1. OC IDP that uses Azure B2C as external provider. So users are registered via Azure B2C Custom Policy and put into the OC Users repository as well for now.
  2. A Blazor Web/Client SPA that authenticates users via Azure B2C. New users would get pushed to register through OC flows for Azure B2C so they appear in Azure B2C and OC.
  3. When a user is authenticated via the Client Blazor App, then we can load information about them via B2C as well as OC if needed. We then can query content which is stored in OC via the GraphQL Api.
  4. We want to make calls to OC GraphQL Api via the token provided by Azure B2C being the main goal. Secondarily, administrators of content would be allowed into the OC side of the house as well to administer content that appears in their SPA. Web, Mobile apps via the GraphQL Api.

Currently, the Token Validation is failing when I uses the token given to me via Azure B2C in the Blazor App to try and access the OC GraphQL Api. I assume the issue is that token has a different authority than the one OC is expecting based on its settings. The best I could find is that the well known documentation was not being downloaded in the Token Validation module for the authority, and instead using the authority provided in the Token Validation configuration screen.

Here is what we're looking at :

image

aderderian avatar Aug 21 '22 15:08 aderderian

@MichaelPetrinolis I think what I am seeing is that the token I get back from Azure B2C in my spa has an issue of https://{mytenant}.b2clogin.com/{mytenantid}/v2.0/. Then in the Authority settings of OC for the token validation module I am setting it to https://{mytenant}.b2clogin.com/cloudgamingbetatenant.onmicrosoft.com/{mypolicy}/v2.0 to match the Authority in my OIDC Client Settings of OC. The code in OC checks the issuer against the authority rather than downloading the well known metadata and comparing the issuer. I "think" this is the problem, but I am not 100% sure. Perhaps the setting in the Token Validation module should be "Issuer"?

aderderian avatar Aug 21 '22 16:08 aderderian

@MichaelPetrinolis after some more investigation, here is what I cam up with. I modified OpenIdValidationConfiguration.cs in the OrchardCore OpenId module to manually set the Issuer and MetadataAddress. Doing this allows the well known information to be properly downloaded and the Issuer is set to the proper Issuer as well.

Currently the code sets the Issuer only and sets it to the Authority server url we put in the Token Validation module. Should we have more options to set the proper urls? Is Azure B2C causing the Issuer and Authority to not match and thus resulting in mismatches? Can we add more field to the Orchard module to support this situation? I appreciate any insight here as I am not sure the proper solution @MichaelPetrinolis .

//options.Issuer = settings.Authority; options.Issuer = new Uri("https://{mytenant}.b2clogin.com/{tenantid}/v2.0/"); options.Audiences.Add(settings.Audience); options.MetadataAddress = new Uri("https://{mytenant}.b2clogin.com/{mytenant}.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/v2.0/.well-known/openid-configuration");

aderderian avatar Aug 23 '22 20:08 aderderian

Is Azure B2C causing the Issuer and Authority to not match and thus resulting in mismatches?

Unsurprisingly, Azure B2C is not standard-compliant: the OIDC discovery spec explicitly says that the metadata URL is created by concatenating the issuer and /.well-known/openid-configuration: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata

Can we add more field to the Orchard module to support this situation?

I'm personally not against making the metadata address configurable, but it will need to be optional and in an "advanced" section with a proper comment indicating it shouldn't be necessary to set it in most cases.

kevinchalet avatar Aug 24 '22 13:08 kevinchalet

Hey @kevinchalet I think the issue is with how the OpenId OC module is setting the Issuer in the OpenID Validation Configuration options. It seems to be setting the ValidIssuer to the Authority url when configuring the Open ID Settings. When I set the Authority url in the token validation module to the Issuer instead, the OpenID modules fails because it can't download the configuration properly. Perhaps we should not be setting Issuer at all? Something is not right :). Any guidance from OIDC experts would be great.

aderderian avatar Aug 24 '22 13:08 aderderian

Authority is not really an OIDC concept but is used as a synonymous of "issuer" (retrospectively, we should have used "issuer" in OpenIdValidationSettings - like in OpenIddict - instead of "authority", but it's likely too late to change that 🤣)

It seems to be setting the ValidIssuer to the Authority url when configuring the Open ID Settings.

It's the right thing to do 😃

When I set the Authority url in the token validation module to the Issuer instead, the OpenID modules fails because it can't download the configuration properly. Perhaps we should not be setting Issuer at all? Something is not right :)

As I said, the address of the server configuration document in Azure B2C is not standard, so if something is not right, you know where to look at 🤣

Making the metadata address configurable should be enough to fix the kind of issue you're seeing. Interested in sending a PR? 😄

kevinchalet avatar Aug 24 '22 13:08 kevinchalet