Sitecore 9 : Content Editors Federated Authentication with Gmail

Recently in one of my Sitecore project, I got a requirement where content editor can log in using third party identity provider like google. In my previous project, I have used multiple times to authenticate the website user but for the Sitecore content user it was a bit different. There were multiple articles which I referred to implement this and this article is basically a consolidation of those articles along with some changes related to user builder and google authentication provider. Below are few references which are worth reading as they provide the flow in depth.

https://doc.sitecore.net/sitecore_experience_platform/developing/developing_with_sitecore/federated_authentication/using_federated_authentication_with_sitecore

http://blog.baslijten.com/enable-federated-authentication-and-configure-auth0-as-an-identity-provider-in-sitecore-9-0/

https://doc.sitecore.net/sitecore_experience_platform/developing/developing_with_sitecore/federated_authentication/configure_federated_authentication

The code I listed is based on the repository provided by BasLitjen at

https://github.com/BasLijten/sitecore-federated-authentication/tree/master/BasLijten.FederatedAuthentication

I have provide the code mentioned in this article at github repository which is ready to use at https://github.com/rdhaundiyal/SitecoreFederatedAuthenticationGmail

Though Sitecore 9 provides out of the box feature for OWIN authentication, there are few places where you might end up writing some piece of custom code. Below article shows how you can authenticate the content editor through google.

Before starting the Sitecore part make sure you have created a google application and have corresponding client id and secret which can be used for google authentication.

To create a google application for your application integration please refere to:

https://doc.sitecore.net/social_connected/setting_up_social_connected/configuring/walkthrough_configuring_social_connector_to_work_with_a_social_network

Steps:

  1. Start with creating a new project in Visual studio 2017, .net framework 4.6.2 and select the class library option.
  2. Add nugget package Microsoft.Owin.Security.Google and Microsoft.asp.net.identity
  3. Add references to Sitecore.Kernel, Sitecore.Owin, Sitecore.Owin.Authentication, Add reference to System.web and Microsoft.Owin.Security.Google;
  4. Create a class GmailIdentityProcessor inheriting from IdentityProvidersProcessor
  5. Override the ProcessCore method where you set the provider to GoogleOAuth2AuthenticationProvider which is provided by Microsoft identity providers and in the last set app to use googleauthentication as below
args.App.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId =ClientId,
ClientSecret = ClientSecret",
Provider = provider
});
  1. In the app_config\include add the file Sitecore.Owin.Authentication.Enabler.config. The only change done in this file is enabling FederatedAuthentication as below
    <settings>

    <setting name=”FederatedAuthentication.Enabled”>

    <patch:attribute name=”value”>true</patch:attribute>

    </setting>

    </settings>

  2. Add GmailIdentityProvider.config to app_config\include

Changes that need to be done in this config are In the pipleline for identity provider, we added our own custom provider

<pipelines>

<owin.identityProviders>

<!– Processors for coniguring providers. Each provider must have its own processor–>

<processor type=”SitecoreGmailAuth.Processor.GmailIdentityProcessor, SitecoreGmailAuth” resolve=”true” />

</owin.identityProviders>

</pipelines>

 

Please note in identity provider section you have to give the exact id of property you created in custom identity provider

<identityProviders hint=”list:AddIdentityProvider”>

<identityProvider ref=”federatedAuthentication/identityProviders/identityProvider[@id=’Google’]” />

</identityProviders>

  1. And last update is the setting for google client id and secret
     

<settings>

<setting name=”FedAuth.Google.ClientId” value=”yourclientid.apps.googleusercontent.com” />

<setting name=”FedAuth.Google.ClientSecret” value=”yourclient secret” />

<setting name=”FedAuth.Google.Domain” value=”Sitecore” />

 

</settings>

Reset the application pool and try to run the Sitecore instance. You will get a screen like below with an additional button to login using google.

SCGL-initial

On clicking you will be redirected to google login page and after providing the user you will be redirected back to Sitecore login page with the error below

SCGL-first login

Now the user is created in sitecore but it does not have any access to the system. Admin user need to provide the access so that the user can use Sitecore cms as editor.

Before that, one more thing we need to change. The default implementation of  ExternalUserBuilder in Sitecore create a user name with a GUID which is very difficult to identify. To resolve this issue, create another class CustomUserBuilder inheriting from ExternalUserBuilder and override the CreateUniqueUserName method to pass email as user id.

protected virtual string CreateUniqueUserName(UserManager userManager, ExternalLoginInfo externalLoginInfo)
{
Assert.ArgumentNotNull((object)userManager, nameof(userManager));
Assert.ArgumentNotNull((object)externalLoginInfo, nameof(externalLoginInfo));
IdentityProvider identityProvider = this.FederatedAuthenticationConfiguration.GetIdentityProvider(externalLoginInfo.ExternalIdentity);
if (identityProvider == null)
throw new InvalidOperationException("Unable to retrieve identity provider for given identity");
string domain = identityProvider.Domain;
return domain + "\\" + externalLoginInfo.Email;
}

Now, if you login as a admin user you will see the user created in Sitecore

SCGL-Role

Provide appropriate member role to the user. The user should now be able to login.

SCGL-logged in

One important thing to take care of while using external provider is that the access to URL should be protected from the website user or else you will end up having so many users created in the Sitecore system which are not content editor and also it can be a possible security threat as well.

Advertisements

Autofac as DI container in Sitecore Helix architecture

The following article describe how to use Autofac as DI container in Sitecore application based on Helix architecture. As you must be knowing in Helix architecture the whole application functionality is divided into multiple features with each feature being an independent functionality not dependent on other features. This article is based on the article written by Kevin Brechbühl at https://ctor.io/one-way-to-implement-dependency-injection-for-sitecore-habitat/

The only difference is that instead of creating processes in individual feature project I will be registering all the dependency at one place using the module feature of autofac.

To start with we will create a project in foundation layer with name “ProjectName.Foundation.DependencyInjection” . I have given my project name as Piccolo and hence the project name will be “Piccolo.Foundation.DependencyInjection

Follow the following steps after creating the project

  1. Add nugget package for Autofac to the project. Command line for nugget is as below: Install-Package Autofac.Mvc5 -Version 4.0.2
  2. We will be creating a custom pipeline in order to set autofac as dependency injection container in Sitecore pipeline. Add folder named Pipelines in the “Piccolo.Foundation.DependencyInjection”
  3. Inside Pipelines add another folder InitializeContainer and within InitializeContainer add a class InitializeContainer.cs.
  4. Add another folder Foundation to the project “Piccolo.Foundation.DependencyInjection” and add config file Foundation.DependencyInection.config to it.

The project should look like as below once you have finished the above steps.

autofac-sitecore-project

Populate the class InitializeContainer with following listing

public class InitializeContainer

{

public void Process(PipelineArgs args)

{

var builder = new ContainerBuilder();

// Register dependencies in controllers

var assembliesInAppDomain = AppDomain.CurrentDomain.GetAssemblies().ToArray();

builder.RegisterControllers(assembliesInAppDomain);

// Register dependencies in filter attributes

builder.RegisterFilterProvider();

// Register dependencies in custom views

builder.RegisterSource(new ViewRegistrationSource());

builder.RegisterAssemblyModules(assembliesInAppDomain);

var container = builder.Build();

// Set MVC DI resolver to use our Autofac container

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

} }

As you can see in the listing, all the module and controller within the appdomain assemblies are registerd in the lines below

var assembliesInAppDomain = AppDomain.CurrentDomain.GetAssemblies().ToArray();

builder.RegisterControllers(assembliesInAppDomain);

builder.RegisterAssemblyModules(assembliesInAppDomain)

Add the following configuration in Foundation.DependencyInjection.config where we are adding our process just before sitecore calls its initialize controller factory


<configuration xmlns:patch=”http://www.sitecore.net/xmlconfig/”&gt;

<sitecore>

<pipelines>

<initialize>

<processor type =”Piccolo.Foundation.DependencyInjection.Pipelines.InitializeContainer.InitializeContainer, Piccolo.Foundation.DependencyInjection”

patch:before=”processor[@type=’Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc’]” />

</initialize>

<initializeContainer>

</initializeContainer>

</pipelines>

</sitecore>

</configuration>

Now in individual Feature modules we need to create autofac module which will automatically be picked up by our sitecore custom pipleline.

For illustration, I will take one feature as example. The name of feature project is Piccolo.Feature.Gallery

Add a class GalleryModule to the project inherited from module where you will register all the dependencies for corresponding feature


public class GalleryModule:Module

{

protected override void Load(ContainerBuilder builder)

{

builder.RegisterType().As<IRepository>();

}

}

For each feature you can create a module in same way.

Now the GalleryController in the above feature expects a constructor with parameter IRepository which will be provided by autofac.

public class GalleryController : Controller

{

private IRepository _imageArticleRepository;

public GalleryController(IRepository imageArticleRepository)

{

_imageArticleRepository = imageArticleRepository;

}

// GET: Gallery

public ActionResult Search(string searchTerm = “”)

{

var rootPath = Sitecore.Context.Database.GetItem(“/sitecore/content/Home/Album”);

var result = _imageArticleRepository.Get(rootPath.ID);

return View(result);

}

}

Autofac will automatically inject the dependency in to constructor into the controller which will then be available for use in the controller.