Azure-Samples / active-directory-b2c-advanced-policies

Sample for use with Azure AD B2C with Custom Policies.
http://aka.ms/aadb2ccustom
MIT License
218 stars 143 forks source link

Azure AD B2C: Azure AD IdP does not work with custom domain #19

Open apedzko opened 6 years ago

apedzko commented 6 years ago

Hi!

I'm using custom policy to add Azure AD as an identity provider for my Azure Ad B2C instance.

To make it work i had to add the following redirect uri for my app registration (otherwise i saw an error when redirecting to b2c from azure ad):

It works fine on my localhost, with the following redirect uris configured:

however when i publish it to my web app, i need to add another redirect uri for my application:

The portal does not allow me to save 3 redirect uris for the app registration - it says "You may not use more than 1 external domain(s)"

Please advise how can i fix that.

gsacavdm commented 6 years ago

I'm unclear why the Azure AD app needs to redirect back to your application as well (both the localhost and the coredwexposure). In theory, your application should only talk to B2C and only B2C should talk to that non-B2C Azure AD app, so you should only need the login.microsoftonline.com... URL.

apedzko commented 6 years ago

Hi! Thanks for your response.

I tried to remove http://localhost:55838/signin-oidc from the list of reply uris in b2c and my application stopped working - it is giving 404 when trying to redirect from b2c to my app. When i am adding it back it works fine.

  1. My application is registered in B2C.
  2. Azure AD is registered as an IdP.
  3. When i log into my app, i'm redirected to B2C page, then to AzureAD page, then back to B2C (https://login.microsoftonline.com/te/coredwexposureb2c.onmicrosoft.com/oauth2/authresp) where the claims are transformed and then to my app.

Thus it looks like i need both redirect uris, however cannot do that on any host besides localhost due to limit of 2 custom namespaces.

gsacavdm commented 6 years ago

You need two separate app registrations:

This article has more info.

apedzko commented 6 years ago

I believe my scenario is a bit different. I'm trying to link the common tenant to support the multi-tenant scenario. Thus i cannot use any app registrations inside Azure AD, since i do not know the directories in advance and can support login from any of them.

Here is my policy provider for AzureAD:

<ClaimsProvider>
      <Domain>MultiTenant</Domain>
      <DisplayName>Login using Azure AD</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="MultiTenantProfile">
          <DisplayName>Organizational or Microsoft Account</DisplayName>
          <Description>Organizational or Microsoft Account</Description>
          <Protocol Name="OpenIdConnect"/>
          <OutputTokenFormat>JWT</OutputTokenFormat>
          <Metadata>
            <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
            <Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
            <Item Key="authorization_endpoint">https://login.windows.net/common/oauth2/v2.0/authorize</Item>
            <Item Key="client_id">a4802af6-d0a1-4551-810e-2dee5d2edcbd</Item>
            <!-- AppID from B2C tenant's WebApp Application -->
            <Item Key="IdTokenAudience">a4802af6-d0a1-4551-810e-2dee5d2edcbd</Item>
            <Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
            <Item Key="scope">openid profile</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="response_types">id_token</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_MultiTenantSignInKey"/>
            <!-- AppSecret from B2C tenant's WebApp Application, saved to policy keys in Azure -->
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid"/>
            <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="AzureAD" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="AzureADMultiTenant" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="preferred_username" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId"/>
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
gsacavdm commented 6 years ago

The guidance still stands though, create both apps in your tenant and make the Azure AD one a "multi-tenant" app. (See these instructions to configure it as such).

apedzko commented 6 years ago

Having 2 applications: one in Azure ADB2C and one in Azure Ad will give me 2 application ids. How do i link them together? I will use the id from B2C in my application's config file. Where should i put the id from Azure AD?

chrispadgettlivecom commented 6 years ago

The application ID that is registered with the Azure AD tenant, i.e. the identifier of the application that represents the Azure AD B2C tenant, must be set in the "client_id" metadata item of the "MultiTenantProfile" technical profile:

<Item Key="client_id"><!-- Enter the application ID --></Item>

This application ID is how the Azure AD B2C tenant identifies itself with the Azure AD tenant.

apedzko commented 6 years ago

Should it also be set to IdTokenAudience?

Will i need to change the client secret to be the secret of AzureAD application?

chrispadgettlivecom commented 6 years ago

Yes to both.

apedzko commented 6 years ago

Thanks for your assistance.

Once i introduced AzureAd app registration i managed to overcome the domain name restriction. However it showed me the following error then:

AADSTS90130: Application '529438c4-ae3d-4101-a1ae-9812e3bab261' (CoreDWExposure ODATA API) is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.

I had to change the authorization endpoint from /common to /organizations for it to work. Thus my ClaimsProvider looks like below:

<ClaimsProvider>
      <Domain>MultiTenant</Domain>
      <DisplayName>Login using Azure AD</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="MultiTenantProfile">
          <DisplayName>Organizational or Microsoft Account</DisplayName>
          <Description>Organizational or Microsoft Account</Description>
          <Protocol Name="OpenIdConnect"/>
          <OutputTokenFormat>JWT</OutputTokenFormat>
          <Metadata>
            <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
            <Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
            <Item Key="authorization_endpoint">https://login.windows.net/organizations/oauth2/v2.0/authorize</Item>
            <Item Key="client_id">529438c4-ae3d-4101-a1ae-9812e3bab261</Item>
            <!-- AppID from B2C tenant's WebApp Application -->
            <Item Key="IdTokenAudience">529438c4-ae3d-4101-a1ae-9812e3bab261</Item>
            <Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
            <Item Key="scope">openid profile</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="response_types">id_token</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_MultiTenantSigningKey2"/>
            <!-- AppSecret from B2C tenant's WebApp Application, saved to policy keys in Azure -->
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid"/>
            <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="AzureAD" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="AzureADMultiTenant" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="preferred_username" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId"/>
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
chrispadgettlivecom commented 6 years ago

"Application '529438c4-ae3d-4101-a1ae-9812e3bab261' (CoreDWExposure ODATA API)" appears to indicate you have entered the client ID for the "CoreDWExposure ODATA API" app, not that for Azure AD B2C, that is registered with the Azure AD tenant.

The "/common" endpoint is supported.

apedzko commented 6 years ago

Ok. I'm a bit lost then.

Could you please advise which application identifier (Azure AD/B2C) and secret for which application (Azure AD/B2C) need to go into these fields:

<Item Key="client_id"></Item>
<Item Key="IdTokenAudience"></Item>
...
 <Key Id="client_secret" StorageReferenceId=/>
chrispadgettlivecom commented 6 years ago

As per @gsacavdm's earlier comment, you must create an app registration in Azure AD for use by Azure AD B2C, as described by https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom#create-an-azure-ad-app.

The reply URL for this app registration is https://login.microsoftonline.com/te/coredwexposureb2c.onmicrosoft.com/oauth2/authresp.

It is the client ID and secret for this app registration that must be entered in the "MultiTenantProfile" technical profile.

This technical profile uses this client ID and secret to generate the authorization and token requests to Azure AD's common endpoint.

apedzko commented 6 years ago

Could we use my specific case as an example here:

  1. My B2C App registration: CoreDW Exposure API a4802af6-d0a1-4551-810e-2dee5d2edcbd

  2. My Azure AD App registration: CoreDWExposure ODATA API 529438c4-ae3d-4101-a1ae-9812e3bab261 The key for this application is stored in B2C_1A_MultiTenantSigningKey2 key of B2C.

My ClaimsProvider element from custom policy:

<ClaimsProvider>
      <Domain>MultiTenant</Domain>
      <DisplayName>Login using Azure AD</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="MultiTenantProfile">
          <DisplayName>Organizational or Microsoft Account</DisplayName>
          <Description>Organizational or Microsoft Account</Description>
          <Protocol Name="OpenIdConnect"/>
          <OutputTokenFormat>JWT</OutputTokenFormat>
          <Metadata>
            <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
            <Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
            <Item Key="authorization_endpoint">https://login.windows.net/common/oauth2/v2.0/authorize</Item>
            <Item Key="client_id">529438c4-ae3d-4101-a1ae-9812e3bab261</Item>
            <Item Key="IdTokenAudience">529438c4-ae3d-4101-a1ae-9812e3bab261</Item>
            <Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
            <Item Key="scope">openid profile</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="response_types">id_token</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_MultiTenantSigningKey2"/>
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid"/>
            <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="AzureAD" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="AzureADMultiTenant" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="preferred_username" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId"/>
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

Could you please advise which specific changes are necessary?

monty-dev commented 6 years ago
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/common/oauth2/authorize</Item>
<Item Key="client_id">df5b2515-a8d2-4d91-ab4f-eac6e1e416c2</Item>
<Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
<Item Key="scope">openid</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="response_types">id_token</Item>
<Item Key="IdTokenAudience">df5b2515-a8d2-4d91-ab4f-eac6e1e416c2</Item>

If you want to use the common endpoint, here is the snippet that you need to modify to get working. I highly recommend that you read the article https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom from top to bottom and get Azure AD single tenant authentication working, then use the above snippit to enable multi-tenant authentication. Note that you will only be able to receive the following claims from users via AAD https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims

If you want more claims, you'll have to enable another orchestration step to retrieve claims via the Graph API. Here's a general idea on how to do that with Logic Apps. https://monteledwards.com/2017/10/18/a-complete-integration-azure-ad-b2c-azure-ad-graph-api-logic-apps/

apedzko commented 6 years ago

Guys,

I really appreciate your help, but let's stick to my particular example. Jumping back and forth does not bring more understanding.

I have done exactly as you said: i have configured the single tenant scenario according to https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom. It works fine.

Now i have questions with a multi-tenant scenario that is not very well documented.

In your latest example you are using some application id df5b2515-a8d2-4d91-ab4f-eac6e1e416c2

In my case i have 2 app registrations: My B2C App registration: CoreDW Exposure API a4802af6-d0a1-4551-810e-2dee5d2edcbd

My Azure AD App registration: CoreDWExposure ODATA API 529438c4-ae3d-4101-a1ae-9812e3bab261

Which identifier should be used in my case? Also which application should be used to create a key in CryptographicKeys?

gsacavdm commented 6 years ago

Understand that people are trying to help, no need to discourage others from offering help, tips or insights, even if they are not doing the work for you.

My B2C app registration is used in your app's code. My Azure AD app registration is used in your MultiTenantProfile, including the CryptographicKeys.

apedzko commented 6 years ago

Thanks for the update. I did not mean to be rude or offensive.

I did use the identifier from Azure AD app registration in the MultiTenantProfile, but got the following error with the common tenant:

AADSTS90130: Application '529438c4-ae3d-4101-a1ae-9812e3bab261' (CoreDWExposure ODATA API) is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.

gsacavdm commented 6 years ago

You need to configure your application as a multi-tenant application

vetrivelmp commented 6 years ago

Hi, We also had this problem but finally we were able to call custom idp from B2C. We used IdentityServer4 as custom IDP. Step 1: Create a Client inside Custom IDP . Say Client ID=>B2C_Client Add OpenId Scope Add reply url => https://login.microsoftonline.com/te/coredwexposureb2c.onmicrosoft.com/oauth2/authresp Publish to APP service (example =>www.customidp.azure.net) Step2: ****Have to create Identity server from B2C to configure your custom IDP www.customidp.azure.net Select Identity server => OPenIdConnect(preview) Configure your custome idp well-know/openid-configuration url Given Client as B2C_Client that you created insided your custom idp Configure your app for implicit flow dont add secret key . select id_token as response. From claim mapping username textbox give input "sub". (very important). displayname => name

Step3: Create Application in B2C. Provide reply url (very important step)

http://localhost:55838/signin-oidc https://coredwexposure.onmicrosoft.com/signin-oidc

Step4: Create your signin policy and check this custom idp inside your policy. Step5: Refer and download quick start from this url to configure your client application. https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-quickstarts-web-app

This should work.

sewalsh commented 6 years ago

@vetrivelmp I'm trying to achieve the same architecture as you describe. Do you have any repositories I can look at for inspiration?

vetrivelmp commented 6 years ago

@sewalsh I dont have repository.Ii have given detailed steps in my previous comment. Just follow the comments and let me know.