CMS

Sitecore with Azure AD and OAuth for Signup/Login of End User

Sitecore with Azure AD & OAuth for Signup/Login of End User

                                                                                 – Pratik Wasnik

 

Introduction:

This blog explains how we can use the benefits of Sitecore’s APIs and Azure’s default policies to authenticate and authorize end user using OAuth for signup/login.

The combination used for this is OpenID and claims.

What is OAuth & OpenID?

OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. This mechanism is used by companies such as Google, Facebook, Microsoft and Twitter to permit the users to share information about their accounts with third party applications or websites.

OpenID standard provides a framework for the communication that must take place between the identity provider and the OpenID acceptor (the “relying party”).An extension to the standard (the OpenID Attribute Exchange) facilitates the transfer of user attributes, such as name and gender, from the OpenID identity provider to the relying party (each relying party may request a different set of attributes, depending on its requirements).

When should AzureAD-OAuth combination be used?

When end users should be created in Azure AD (Not in Core Database of Sitecore) and we have to give benefits of Sitecore API for functionality/Customization to developers, this approach is the solution to follow.

If user is not logged in and tries to access restricted page then he will be redirected to Azure AD Policy Page which is shown as follows:

 

If not signed in, after clicking on Sign up now link, will be redirected to Signup page fields which were chosen while creating the policy, shown as follows:

 

 

The process flow diagram is as follows:

Courtesy:  Pablo Urquiza

 

 

 

For this, we will require the following:

Part A: In Azure AD Create:

  • Active Directory
  • Application
  • Signin/Sign-up policy

Part B: In Sitecore Create:

  • Patch-up file consisting of metadata entries, loginPage and custom processors
  • Custom processors
  • Helper classes
  • Presentation item

 

 

Note: User must register for Azure Account in order to create AD, Application and Policies.

Part A is simple to create and does not require any special customization.

To create Part A, please refer to the following article:

https://devandme.wordpress.com/2016/04/14/authenticating-a-sitecore-external-user-as-a-customer-via-azure-b2c-part-2/

However, Part B is where the coding is involved and requires lot of changes to be done.

Part B involves

  • Making a sign in/up request.
  • Calling B2C to get the keys we will need to validate the received token.
  • Actually validating the token
  • Creating a virtual user and adding the token claims to its profile.

 

Here, to get data of the policies made,  the request is made and response is serialized into B2CMetadata object.

[Serializable]

public class B2CMetadata
{
    public string issuer { get; set; }
    public string authorization_endpoint { get; set; }
    public string token_endpoint { get; set; }
    public string end_session_endpoint { get; set; }
    public string jwks_uri { get; set; }
    public List response_modes_supported { get; set; }
    public List response_types_supported { get; set; }
    public List scopes_supported { get; set; }
    public List subject_types_supported { get; set; }
    public List id_token_signing_alg_values_supported { get; set; }
    public List token_endpoint_auth_methods_supported { get; set; }
    public List claims_supported { get; set; }
    public B2CMetadata()
    {
        //Playing nice with the Serializer here
    }
}

[Serializable]
public class KeysWrapper
{
    public List keys { get; set; }
    public KeysWrapper()
    {
        //Again, empty constructor to please the serializer
    }

    public Dictionary FindByKidValue(string kid)
    {
        return keys.Where(k => k.Keys.Contains("kid") && k["kid"].Equals(kid)).FirstOrDefault();
    }
}

Now this object is stored in Application as every user is treated/validated same way and we will need this value to validate.

Here, we need to initialize the metadata , create keys and pass it from Azure Policies to Web Application to validate it.

 

Now,

We need to implement the InitiateCustomerSignInUp and LogOut methods in the B2CHelper

public static void InitiateCustomerSignInUp(string returnUrl, B2CMetadata b2cMetadata)
{
    var config = (B2CMetadata)HttpContext.Current.Application["_B2CMETADATA_"];
    config = config != null ? config : b2cMetadata;
    string authEndpoint = config.authorization_endpoint;
    //We are using the Nonce parameter to avoid replay attacks
    string nonce = Guid.NewGuid().ToString();
    HttpContext.Current.Session["_NONCE_"] = nonce;
    //We use the State attribute to send the Url where we should redirect to when done with the auth stuff
    string state = returnUrl;
    string rType = "id_token";
    string rMode = "form_post";
    string clientId = appID;
    string redirUri = redirectURL;
    string scope = "openid";
    string policy = policyName;
    string prompt = "login";
    var sb = new StringBuilder(authEndpoint)
    .Append($"&client_id={clientId}")
    .Append($"&scope={scope}")
    .Append($"&response_type={rType}&response_mode={rMode}")
    .Append($"&redirect_uri={redirUri}")
    .Append($"&state={state}&nonce={nonce}")
    .Append($"&prompt={prompt}");
    WebUtil.Redirect(sb.ToString());
}

public static void LogOut()
{
    //Just logout
    Sitecore.Security.Authentication.AuthenticationManager.Logout();
}

 

The InitiateCustomerSignInUp method will be requiring the object of B2CMetadata class and has to be passed as 2nd input parameter.

 

We can call this method from the SignUp method of B2C Authorization method as follows :

[System.Web.Mvc.HttpGet]
[AllowAnonymous]
public void SignInUp()
{
    //string returnUrl = Request.UrlReferrer.AbsolutePath;
    string returnUrl= "~/demo";
    if (!Sitecore.Context.User.IsAuthenticated)
    {
        B2CHelper.InitiateCustomerSignInUp(returnUrl,(B2CMetadata)System.Web.HttpContext.Current.Application["_B2CMETADATA_"]);
    }
}

 

When B2C processes our authorization request, it POSTs the response data in a new request to our defined RedirectUri

For this example, we will be using the given_name and family_name claims to build the Sitecore virtual user, but of course you can use other claims from the ones you configured in B2C.

With this processor in place, things look pretty complete, except for the B2CHelper.CreateVirtualUser method, and the most important part, the B2CHelper.ValidateToken method.

So, let’s add those methods to out B2CHelper class.

 

Building the Sitecore User:

The CreateVirtualUser method is pretty simple and is in charge of creating a virtual user object, assigning a role to it (which you should already have created in Sitecore), and adding a set of properties to its profile.

 

The core of the token validation logic is done by the System.IdentityModel.Tokens.Jwt assembly, part of the System.IdentityModel framework by MS.

 

After the claims validation is done, a virtual non-persistent user is created and the stored in Azure AD not in Sitecore’s User Manager.

It is better to use Application than Session to store the state as we are targeting extranet/anonymous  end user and every user should have the same way of validation.

We can set login page as per following in patchup file.

                      
<site name="website" set:loginPage="/api/sitecore/B2CAuthorization/signinup" >                   

 

Advantages of using OAuth and Azure AD:

  • (Important one) You can use the same login for web as well as native(mobile) apps
  • You don’t have to save session information on the server, use Application
  • You can easily set expiry date in token itself
  • Simplicity
  • We can use the benefits of Sitecore API.
  • We can use default Signup/Sign in policies of Azure AD, saving lot of development time and providing better security for User Account.
  • We can provide multifactor authentication while signing up and signing in to user.

This option is made optional by Azure.

  • End users can be classified as per group provided in Azure.
  • By unlocking specific user in application, user can be given special permissions to access restricted page

 

Important Points To Remember:

  • Application should be used instead of Session when all end users are given same access permissions to a specific or group of pages.
  • To Initialize Metadata add custom processor in “preprocessRequest” pipeline and User Resolver in “httpRequestBegin” pipeline.
  • As per the best practice the settings such as LogoutEndpoint, ClientId etc. should be given in custom patch file but if these settings are not accessible at runtime then , in tha respective class assign the value for these settings and then proceed.
  • While creating the policy those fields which are selected/checked , should be included in claims in UserResolver class.

 

 

This blog is with reference to blog by Pablo Urquiza https://devandme.wordpress.com/2016/04/09/authenticating-a-sitecore-external-user-as-a-customer-via-azure-b2c-part-1/.

Special Thanks to Venkataphani Abburi for his help in this POC

 

About The Author

Leave a Reply

*