HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Configure mixed-mode OWIN authentication

Describes how to set up mixed-mode OWIN authentication.

A common use case for mixed-mode authentication is having ADFS for your back-end users and another authentication provider for website users. Configuring mixed-mode authentication for the Optimizely Content Management System (CMS) platform requires the following NuGet packages as dependencies:

  • Microsoft.Owin.Security.Cookies
  • Microsoft.Owin.Host.SystemWeb
  • Microsoft.Owin.Security.WsFederation

To configure mixed-mode OWIN authentication, set the authentication type in the <system.web> section of the web.config.

<authentication mode="None"></authentication>

To configure mixed-mode authentication, create a Startup file in your project that handles the configuration of the different authentication middleware.

using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Google;
using Owin;
using WebApplication1.Models;

namespace WebApplication1 {
  public partial class Startup {
    const string LogoutUrl = "/util/logout.aspx";
    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app) {
      // This will configure cookie authentication at the following urls.  
      // In those pages you are responsible for authentication and calling 
      // the OwinContext.Authentication.SignIn method to properly sign in the user
      // and OwinContext.Authentication.SignOut to logout a user
      app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = "Application", LoginPath = new PathString("/Login"), LogoutPath = new PathString("/Logout")
      });

      //This will set ADFS as the default authentication provider 
      app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
      app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
      });
      //Enable federated authentication
      app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions() {
        //Trusted URL to federation server meta data
        MetadataAddress = "https://devdc.dev.test/federationmetadata/2007-06/federationmetadata.xml",
          //Value of Wtreal must *exactly* match what is configured in the federation server
          Wtrealm = "https://localhost:44303/",
          Notifications = new WsFederationAuthenticationNotifications() {
            RedirectToIdentityProvider = (ctx) => {
                //To avoid a redirect loop to the federation server send 403 when user is authenticated but does not have access
                if (ctx.OwinContext.Response.StatusCode == 401 && ctx.OwinContext.Authentication.User.Identity.IsAuthenticated) {
                  ctx.OwinContext.Response.StatusCode = 403;
                  ctx.HandleResponse();
                }
                return Task.FromResult(0);
              },
              SecurityTokenValidated = (ctx) => {
                //Ignore scheme/host name in redirect Uri to make sure a redirect to HTTPS does not redirect back to HTTP
                var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
                if (redirectUri.IsAbsoluteUri) {
                  ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
                }
                //Sync user and the roles to EPiServer in the background
                ServiceLocator.Current.GetInstance().SynchronizeAsync(ctx.AuthenticationTicket.Identity);
                return Task.FromResult(0);
              }
          }
      });
      // Add stage marker to make sure WsFederation runs on Authenticate (before URL Authorization and virtual roles)
      app.UseStageMarker(PipelineStage.Authenticate);

      //Remap logout to a federated logout
      app.Map(LogoutUrl, map => {
        map.Run(ctx => {
          ctx.Authentication.SignOut();
          return Task.FromResult(0);
        });
      });

      //Tell antiforgery to use the name claim
      AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
    }
  }
}