allBlogsList

Sitecore Authentication using OpenID Connect

Recently, I have been working on setting up OpenID Connect for end user authentication performed by Authorization server, as well as to obtain basic user profile information. I will be sharing my experiences on how I made it work in a Sitecore MVC application. In this article, we will go over on setting up Owin Middleware using Microsoft Katana.

SItecore_OpenIDConnect

  1. OpenID Connect: Also, known as OAuth (Open Authorization) is an industry standard for token based authentication and authorization
  2. Owin: Owin (Open Web Interface for .NET) is a standard interface between .NET web servers and web applications. The primary goal of using Owin is to facilitate a simple pluggable architecture
  3. Owin Middleware: This serves as a pipeline between a server and application where we can inspect, route, modify requests and response messages.
  4. Katana: It is a collection of projects for supporting OWIN with various Microsoft components

The middleware here will help the communication between Client(Sitecore application) and the Server(Identity Server 3).

Step 1: Configure a client which will be used by the Sitecore application

Download the IdentityServer3 sample application from GitHub here. We will be referring to the MVCAuthentication project for this post.

Navigate to ~\MVC Authentication\EmbeddedMvc\IdentityServer\Clients.cs and add a new client definition

                new Client
                {
                    ClientName = "Sitecore 8.2.3 client",
                    ClientId = "1a6cb582-d5cb-4a44-ab2b-472a06ddc378",
                    Flow = Flows.Implicit,
                    RequireConsent = true,
                    ClientSecrets = new List
                    {
                        new Secret("0c1ec1e0-6d1b-4c78-901c-0d21b767b141".Sha256())
                    },
                    AllowedScopes = new List
                    {
                        "openid",
                        "profile",
                        "roles"
                    },
                    RedirectUris = new List
                    {
                        "http://xckondapally823.local"
                    },
                    PostLogoutRedirectUris = new List
                    {
                        "http://xckondapally823.local"
                    }
                }

Step 2: Changes needed in the Sitecore application are as follows: 

The following list will give you an idea about list of NuGet packages you need for this implementation

  1. Sitecore.Owin 2.0.0: Download the source code from GitHub here and make the following updates

    • Navigate to ~/Sitecore.Owin/StartUp.cs file and add the following line of code which will define the startupType. Giving a specific type prevents conflicts with any existing Owin Startup files in your application. In my example, I named it as SitecoreOwin

      [assembly: OwinStartup("SitecoreOwin", typeof(Sitecore.Owin.Startup))]
      
      namespace Sitecore.Owin
      {
      
        public class Startup
        {
          public virtual void Configuration(IAppBuilder app)
          {
            CorePipeline.Run("initializeOwinMiddleware", new InitializeOwinMiddlewareArgs(app));
          }
        }
      }
      
      
    • Add a reference to the Sitecore.Kernel.dll which matches the version of your Sitecore instance

    • Change Target Framework if needed and build the solution

    • Reference the Sitecore.Owin.dll in your project

  2. Using the Package Manager Console, install the following NuGet packages

    • Install-Package Microsoft.AspNet.Identity.Owin
    • Install-Package Microsoft.AspNet.Identity.Core
    • Install-Package Microsoft.Owin.Security.OpenIdConnect

    Some of the NuGet packages which get added to your application might conflict with the existing assemblies shipped out of the box with a Sitecore Installation. In my case, I had to add binding redirects for Newtonsoft.Json and System.IdentityModel.Tokens.Jwt

  3. The next step is to create a class which will be used to initialize the Middleware. Create a class XCOwinKatanaMiddleware

        public class XCOwinKatanaMiddleware
    {
        /// 
    
        /// This is required for Owin Katana Middleware startup
        /// 
    
        /// 
        public void Process(InitializeOwinMiddlewareArgs args)
        {
            args.App.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
            //Set the authentication type to use cookies
            args.App.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,               
            });
    
            //OpenId authentication options
            args.App.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                Authority = "https://localhost:44319/identity",
                ClientId = "1a6cb582-d5cb-4a44-ab2b-472a06ddc378",
                ClientSecret = "0c1ec1e0-6d1b-4c78-901c-0d21b767b141",
                ResponseType = "id_token",
                Scope = "openid profile roles",
                CallbackPath = new Microsoft.Owin.PathString("/blah/"),
                SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = baseContext =>
                    {
    
                        var uri = baseContext.Request.Uri;
                        //Adding RedirectUri based on request to support multitenant structure
                        baseContext.ProtocolMessage.RedirectUri = string.Format("https://{0}/signincallback", uri.Host);
    
                        return System.Threading.Tasks.Task.FromResult(0);
                    }
                }
            });
        }
    }
    
    
  4. The following configuration changes are needed in order to initialize the Owin middleware.

    • Add the following appSetting in the web.config file

      <add key="owin:appStartup" value="Sitecore.Owin.Startup, Sitecore.Owin"></add>
      
    • Add a new config file under App_Config/Include which has the processor to initialize our Owin Middleware pipeline

      <!--?xml version="1.0" encoding="utf-8" ?-->
              <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
              <sitecore>
              <pipelines>
              <initializeowinmiddleware>
              <processor mode="on" type="skondapally82u3.XCAuthentication.XCOwinKatanaMiddleware, skondapally82u3"></processor>
              </initializeowinmiddleware>
              </pipelines>
              </sitecore>
              </configuration>
      
    • Set the authentication mode to "None" in web.config

          <authentication mode="None">
            <forms name=".ASPXAUTH" cookieless="UseCookies"></forms>
          </authentication>
      
  5. The set-up is now complete. In order to test this functionality, lets create a Sitecore Controller Rendering and decorate it with System.Web.MVC.AuthorizeAttribute

        public class XCAuthenticationController : SitecoreController
        {
            [Authorize]
            public ActionResult GetUserClaims()
            {
                return PartialView("~/Views/XCViews/UserClaims.cshtml", (User.Identity as ClaimsIdentity).Claims);
            }
        }
    

When an anonymous user tries to access the page making use of this controller, the application throws an Unauthorizedexception i.e., 401. The 401 status code indicates that the HTTP request has not been applied because it lacks valid authentication credentials (usually username and password) for the target resource.

The Owin Middleware will intercept these requests and redirects the user to the Authorization Provider as per the configuration added above.

I created a sample page which uses this Controller Rendering. When the user is extranet\Anonymous, we get redirected to the Identity Server running on my localhost.

Identity_Server_Login_Page

Once the user credentials(username = bob | password = secret) are passed, they will be presented by a form which mentions that the Sitecore application is asking for the user's consent.

Identity_Server_User_Consent_Form

At this point, Identity server validates the user and redirects the user back to the client based on what has been defined as the Redirect_Uri.

The example used in this blog post has been implemented on the latest version of Sitecore 8.2.3, a MVC application running on .NET Framework 4.5.2.

Stay tuned for the next article which will outline the following details:

  • What are the claims returned from Identity Server?
  • How do we use those claims to Authenticate the user in Sitecore.Context
  • How to sign off the user?
  • Support for Multisite Sitecore instance

Important Notes:

  • Go through the Identity Server documentation here
  • Understand how to install the Identity Server certificates here

References: