Azure AD B2C requires you to register two applications that it uses to sign up and sign in users with local accounts: IdentityExperienceFramework, a web API, and ProxyIdentityExperienceFramework, a native app with delegated permission to the IdentityExperienceFramework app. Your users can sign up with an email address or username and a password to access tenant-registered applications, which creates a "local account." Local accounts exist only in Azure AD B2C tenant.
- Select App registrations, and then select New registration.
- For Name, enter Zimbra SAML IdentityExperienceFramework.
- Under Supported account types, select Accounts in this organizational directory only.
- Under Redirect URI, select Web, and then enter
https://tenant.b2clogin.com/tenant.onmicrosoft.com
. - Under Permissions, select the Grant admin consent to openid and offline_access permissions check box.
- Select Register.
Next, expose the API by adding a scope:
- In the left menu, under Manage, select Expose an API.
- Select Add a scope, then select Save and continue to accept the default application ID URI.
- Enter the following values to create a scope that allows custom policy execution in Azure AD B2C tenant
- Scope name: user_impersonation
- Admin consent display name: Access IdentityExperienceFramework
- Admin consent description: Allow the application to access IdentityExperienceFramework on behalf of the signed-in user.
- Select Add scope
- Select App registrations, and then select New registration.
- For Name, enter Zimbra SAML ProxyIdentityExperienceFramework.
- Under Supported account types, select Accounts in this organizational directory only.
- Under Redirect URI, use the drop-down to select Public client/native (mobile & desktop).
- For Redirect URI, enter
myapp://auth
. - Under Permissions, select the Grant admin consent to openid and offline_access permissions check box.
- Select Register.
Next, specify that the application should be treated as a public client:
- In the left menu, under Manage, select Authentication.
- Under Advanced settings, in the Allow public client flows section, set Enable the following mobile and desktop flows to Yes.
- Select Save.
- Ensure that "allowPublicClient": true is set in the application manifest:
- In the left menu, under Manage, select Manifest to open application manifest.
- Find allowPublicClient key and ensure its value is set to true.
Now, grant permissions to the API scope you exposed earlier in the IdentityExperienceFramework registration:
- In the left menu, under Manage, select API permissions.
- Under Configured permissions, select Add a permission.
- Select the My APIs tab, then select the IdentityExperienceFramework application.
- Under Permission, select the user_impersonation scope that you defined earlier.
- Select Add permissions. As directed, wait a few minutes before proceeding to the next step.
- Select Grant admin consent for .....
- Select Yes.
- Select Refresh, and then verify that "Granted for ..." appears under Status for the scope.
- Select App registrations, and then select New registration.
- Enter a Name for the application such as: Zimbra SAML SSO.
- Under Supported account types, select Accounts in any organizational directory or any identity provider. For authenticating users with Azure AD B2C.
- Under Redirect URI, select Web, and then enter the URL of Zimbra Application. Example:
https://tenant.onmicrosoft.com
- Select Register.
- Under Manage, click on Expose an API.
- Click on Set for the Application ID URI and then click on Save, accepting the default value.
In the Azure portal, search for and select Azure AD B2C. On the overview page, under Policies, select Identity Experience Framework
- Select Policy Keys and then select Add.
- For Options, choose Generate.
- In Name, enter ZimbraSAMLTokenSigningKeyContainer. The prefix B2C_1A_ might be added automatically.
- For Key type, select RSA.
- For Key usage, select Signature.
- Select Create.
- Select Policy Keys and then select Add.
- For Options, choose Generate.
- In Name, enter ZimbraSAMLTokenEncryptionKeyContainer. The prefix B2C_1A_ might be added automatically.
- For Key type, select RSA.
- For Key usage, select Encryption.
- Select Create.
To have a trust relationship between SAML application and Azure AD B2C, create a signing certificate for the SAML response. Azure AD B2C uses this certificate to sign the SAML response sent to SAML application
- Create a SAML policy key
- By using openssl
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -subj '/CN=saml.tenant.onmicrosoft.com' openssl pkcs12 -export -out ZimbraSAMLIdpCertificate.pfx -inkey key.pem -in cert.pem
- By using PowerShell
New-SelfSignedCertificate ` -KeyExportPolicy Exportable ` -Subject "CN=saml.tenant.onmicrosoft.com" ` -KeyAlgorithm RSA ` -KeyLength 2048 ` -KeyUsage DigitalSignature ` -NotAfter (Get-Date).AddMonths(36) ` -CertStoreLocation "Cert:\CurrentUser\My"
- Under Policies, select Identity Experience Framework and then Policy keys.
- Select Add, and then select Options > Upload
- Enter the Name as ZimbraSAMLIdpCertificate. The prefix B2C_1A_ is automatically added to the name of policy key.
- Using the upload file control, upload certificate that was generated in the above steps along with the SSO policies (ZimbraSAMLIdpCertificate.pfx).
- Enter the certificate's password as tenant name and click on Create.
- You should be able to see a new policy key with the name B2C_1A_ZimbraSAMLIdpCertificate.
Custom policies are a set of XML files you upload to Azure AD B2C tenant to define technical profiles and user journeys.
Get the custom policy starter packs from GitHub, then update the XML files in the LocalAccounts starter pack with Azure AD B2C tenant name.
- Download the .zip file or clone the repository:
git clone https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack
- In all of the files in the LocalAccounts directory, replace the string yourtenant with the name of Azure AD B2C tenant. For example, if the name of B2C tenant is contosotenant, all instances of yourtenant.onmicrosoft.com become contosotenant.onmicrosoft.com.
- Open LocalAccounts/TrustFrameworkExtensions.xml and find the element
<TechnicalProfile Id="login-NonInteractive">
. - Replace B2C_1A_TrustFrameworkLocalization with B2C_1A_TrustFrameworkBase
- Replace both instances of IdentityExperienceFrameworkAppId with the application ID of the IdentityExperienceFramework application that you created earlier.
- Replace both instances of ProxyIdentityExperienceFrameworkAppId with the application ID of the ProxyIdentityExperienceFramework application that you created earlier.
- Save the file.
- Clone LocalAccounts/SignUpOrSignin.xml to LocalAccounts/SignUpOrSigninSAML.xml
- Open LocalAccounts/SignUpOrSigninSAML.xml with preferred editor and then remove
<RelyingParty>
section. - Change the PolicyId and PublicPolicyUri values of the policy to B2C_1A_Zimbra_SAML_Signin and
http://tenant.onmicrosoft.com/B2C_1A_Zimbra_SAML_Signin
- Enable custom policy to connect with a SAML application by adding the
<ClaimsProviders>
section in<TrustFrameworkPolicy>
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles>
<!-- SAML Token Issuer technical profile -->
<TechnicalProfile Id="Saml2AssertionIssuer">
<DisplayName>Token Issuer</DisplayName>
<Protocol Name="SAML2" />
<OutputTokenFormat>SAML2</OutputTokenFormat>
<Metadata>
<Item Key="IssuerUri">https://tenant.b2clogin.com/tenant.onmicrosoft.com/B2C_1A_Zimbra_SAML_Signin</Item>
</Metadata>
<CryptographicKeys>
<Key Id="MetadataSigning" StorageReferenceId="B2C_1A_SamlIdpCert" />
<Key Id="SamlAssertionSigning" StorageReferenceId="B2C_1A_SamlIdpCert" />
<Key Id="SamlMessageSigning" StorageReferenceId="B2C_1A_SamlIdpCert" />
</CryptographicKeys>
<InputClaims/>
<OutputClaims/>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Saml" />
</TechnicalProfile>
<!-- Session management technical profile for SAML based tokens -->
<TechnicalProfile Id="SM-Saml">
<DisplayName>Session Management Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.SamlSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
- Create a sign-up or sign-in policy configured for SAML by adding the
<UserJourneys>
section and<RelyingParty>
section in<TrustFrameworkPolicy>
<UserJourneys>
<UserJourney Id="SignUpOrSigninSAML">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- This step reads any user attributes that we may not have received when in the token. -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="Saml2AssertionIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSigninSAML" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="SAML2"/>
<Metadata>
<Item Key="PartnerEntity">https://zimbra.server/service/extension/saml/metadata</Item>
<!-- <Item Key="PartnerEntity"><![CDATA[
Embed the metadata directly
]]></Item> -->
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="signInName" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="signInName" ExcludeAsClaim="true"/>
</TechnicalProfile>
</RelyingParty>
- Select the Identity Experience Framework menu item in B2C tenant in the Azure portal.
- Select Upload custom policy.
- As per the following order, upload the policy files in the above steps: TrustFrameworkBase.xml, TrustFrameworkExtensions.xml, SignUpOrSigninSAML.xml
After the policy files are uploaded, Azure AD B2C uses the configuration information to generate the identity provider's SAML metadata document that the application will use. The SAML metadata document contains the locations of services, such as sign-in methods, logout methods, and certificates. The Azure AD B2C policy metadata is available at the following URL: https://tenant.b2clogin.com/tenant.onmicrosoft.com/B2C_1A_Zimbra_SAML_Signin/samlp/metadata
- Register an application tutorial: https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications
- Create custom policies tutorial: https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows
- TrustFrameworkPolicy reference: https://docs.microsoft.com/en-us/azure/active-directory-b2c/trustframeworkpolicy
- Register a SAML application in Azure AD B2C tutorial: https://docs.microsoft.com/en-us/azure/active-directory-b2c/saml-service-provider
- WordPress SAML SSO with Azure B2C SAML IdP tutorial: https://plugins.miniorange.com/saml-single-sign-on-sso-wordpress-using-azure-b2c
- Define a SAML identity provider technical profile in an Azure Active Directory B2C custom policy: https://docs.microsoft.com/en-us/azure/active-directory-b2c/saml-identity-provider-technical-profile
- Define a technical profile for a SAML token issuer in an Azure Active Directory B2C custom policy: https://docs.microsoft.com/en-us/azure/active-directory-b2c/saml-issuer-technical-profile