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

EPiServer.CMS.UI.AspNetIdentity OWIN authentication

Describes the authentication module for managing users and roles.

You can configure the application to use AspNetIdentity as the authentication module for managing users and roles. This configuration requires the following NuGet package as a dependency: EPiServer.CMS.UI.AspNetIdentity.

To use and configure AspNetIdentity OWIN-based authentication:

  1. Set the authentication mode in the system.web section of the web.config file as shown:

    <authentication mode="None"></authentication>
    
  2. Clear the <membership> and <rolemanager> providers from web.config as shown:

    <membership>
      <providers>
        <clear />
      </providers>
    </membership>
            
    <roleManager enabled="false">
      <providers>
        <clear />
      </providers>
    </roleManager>
    
  3. Because the OWIN pipeline is a startup class needed to configure the application, add the following code to the startup class:

    using EPiServer.Cms.UI.AspNetIdentity;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.Owin;
    using Microsoft.Owin;
    using Microsoft.Owin.Security.Cookies;
    using Owin;
    using System;
    
    [assembly: OwinStartup(typeof (Startup))]
    
    public void Configuration(IAppBuilder app) {
      // Add CMS integration for ASP.NET Identity
      app.AddCmsAspNetIdentity<ApplicationUser>();
      // Use cookie authentication
      app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
          LoginPath = new PathString(login - path),
          Provider = new CookieAuthenticationProvider {
            OnValidateIdentity =
              SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<ApplicationUser>,ApplicationUser> (
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user))
          }
      });
    }
    

The EPiServer.CMS.UI.AspNetIdentity NuGet package implements the UIUsersManager, UIRoleManager, SecurityEntityProvider and SignInManager providers, which you must integrate with the Optimizely user interface. You can manage the users, roles, and access rights from the admin view. And the Optimizely user interface login page (/util/login.aspx) can be used for login.

Custom user database

By default, the ApplicationContext uses the EPiServerDB as a connection string name to save AspNet Users and roles. You can override it like this: 

app.AddCmsAspNetIdentity<ApplicationUser>(new ApplicationOptions() {
  ConnectionStringName = " connection string name"
});

Custom user model

There are two ways to define a custom user model.

  • Inherit from EPiServer.Cms.UI.AspNetIdentity.ApplicationUser, like this:

    public class CustomUser : ApplicationUser {
      //your custom properties
    }
    
  • Inherit from Microsoft.AspNet.Identity.EntityFramework.IdentityUser and the EPiServer.Shell.Security.IUIUser interfaces, like this:

    public class CustomUser: IdentityUser, IUIUser {
      public string Comment {
        get;
        set;
      }
      public bool IsApproved {
        get;
        set;
      }
      public bool IsLockedOut {
        get;
        set;
      }
    
      [Column(TypeName = "datetime2")]
      public DateTime CreationDate {
        get;
        set;
      }
    
      [Column(TypeName = "datetime2")]
      public DateTime ? LastLockoutDate {
        get;
        set;
      }
    
      [Column(TypeName = "datetime2")]
      public DateTime ? LastLoginDate {
        get;
        set;
      }
    
      public string PasswordQuestion {
        get;
      }
    
      public string ProviderName {
        get {
          return "MyProviderName";
        }
      }
    
      [NotMapped]
      public string Username {
        get {
          return base.UserName;
        }
        set {
          base.UserName = value;
        }
      }
    }
    

After defining a custom user model, you need to configure it in the OWIN startup class, like this:

public class Startup {
  public void Configuration(IAppBuilder app) {
    // Add CMS integration for ASP.NET Identity             
    app.AddCmsAspNetIdentity<CustomUser> ();

    // Use cookie authentication
    app.UseCookieAuthentication(new CookieAuthenticationOptions {
      AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString(YourLoginPath or "/Util/Login.aspx"),
        Provider = new CookieAuthenticationProvider {
          OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<CustomUser>,CustomUser> (
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user))
        }
    });
  }
}

SecurityEntityProvider 

The EPiServer.CMS.UI.AspNetIdentity implements and registers the UIUserProvider, UIRoleProvider, UISignInManager and SecurityEntity provider in the container. To override them, register it in the programmaticallyInitializeModule, like this:

[EPiServer.Framework.InitializableModule]
[EPiServer.Framework.ModuleDependency(typeof (EPiServer.Cms.UI.AspNetIdentity.ApplicationSecurityEntityInitialization))]
[EPiServer.Framework.ModuleDependency(typeof (EPiServerUIInitialization))]
public class MyInitializeModule: EPiServer.ServiceLocation.IConfigurableModule {
    public void ConfigureContainer(EPiServer.ServiceLocation.ServiceConfigurationContext context) {
      //Configure your providers
    }
    public void Initialize(EPiServer.Framework.Initialization.InitializationEngine context) {}
    public void Uninitialize(EPiServer.Framework.Initialization.InitializationEngine context) {}

Extend the Cms Asp.net Identity implementation

The Asp.NET Identity system uses the OWIN pipeline, making replacing our default implementation a bit harder. It is not just a matter of registering a new class in the IoC container.

Instead, you need to take control of the pipeline setup. You are exposing the default create delegates for standard Asp.NET Identity classes; create a pipeline initialization method and call the create delegates in the correct order. The following example shows how you can in an IAppBuilder extension method.

public static class ApplicationBuilderExtensions {
  public static IAppBuilder SetupCustomAspNetIdentity<TUser>(this IAppBuilder app) where TUser: IdentityUser, IUIUser, new() {
    var applicationOptions = new ApplicationOptions {
      DataProtectionProvider = app.GetDataProtectionProvider()
    };

    // Configure the db context, user manager and signin manager to use a single instance per request by using
    // the default create delegates
    app.CreatePerOwinContext<ApplicationOptions>(() => applicationOptions);
    app.CreatePerOwinContext<ApplicationDbContext<TUser>> (ApplicationDbContext<TUser>.Create);
    app.CreatePerOwinContext<ApplicationRoleManager<TUser>> (ApplicationRoleManager<TUser>.Create);
    app.CreatePerOwinContext<ApplicationUserManager<TUser>> (ApplicationUserManager<TUser>.Create);
    app.CreatePerOwinContext<ApplicationSignInManager<TUser>> (ApplicationSignInManager<TUser>.Create);

    // Configure the application 
    app.CreatePerOwinContext<UIUserProvider>(ApplicationUserProvider<TUser>.Create);
    app.CreatePerOwinContext<UIRoleProvider>(ApplicationRoleProvider<TUser>.Create);
    app.CreatePerOwinContext<UIUserManager>(ApplicationUIUserManager<TUser>.Create);
    app.CreatePerOwinContext<UISignInManager>(ApplicationUISignInManager<TUser>.Create);

    // Saving the connection string in the case dbcontext be requested from none web context
    ConnectionStringNameResolver.ConnectionStringNameFromOptions = applicationOptions.ConnectionStringName;

    return app;
  }
}

When you have your setup method, call that method in the Startup instead of the built-in one.

public class Startup {
  public void Configuration(IAppBuilder app) {
    ...

    // Add CMS integration for ASP.NET Identity
    app.SetupCustomAspNetIdentity<ApplicationUser>();

    ...
  }
}

When you have your custom pipeline running, you can change things like the default PasswordHasher, the default PasswordValidator, and so on.

Create a create delegate for the ApplicationUserManager and change the relevant values.

public static class ApplicationBuilderExtensions {
  public static ApplicationUserManager<TUser>CreateApplicationUserManager<TUser>(IdentityFactoryOptions<ApplicationUserManager<TUser>> options, IOwinContext context) where TUser: IdentityUser, IUIUser, new() {
    var manager = new ApplicationUserManager<TUser>(new UserStore<TUser>(context.Get<ApplicationDbContext<TUser>>()));

    // Configure validation logic for usernames
    manager.UserValidator = new UserValidator<TUser>(manager) {
      AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };

    // Change Password hasher
    manager.PasswordHasher = new SqlPasswordHasher();

    // Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator {
      RequiredLength = 6,
        RequireNonLetterOrDigit = true,
        RequireDigit = true,
        RequireLowercase = true,
        RequireUppercase = true
    };

    // Configure user lockout defaults
    manager.UserLockoutEnabledByDefault = true;
    manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
    manager.MaxFailedAccessAttemptsBeforeLockout = 5;

    var provider = context.Get<ApplicationOptions>().DataProtectionProvider.Create("EPiServerAspNetIdentity");
    manager.UserTokenProvider = new DataProtectorTokenProvider<TUser>(provider);

    return manager;
  }
}

When you have your own create delegate you have to replace the default create delegate in the SetupCustomAspNetIdentity method.

Change

app.CreatePerOwinContext<ApplicationUserManager<TUser>>(ApplicationUserManager<TUser>.Create);

to

app.CreatePerOwinContext<ApplicationUserManager<TUser>>(CreateApplicationUserManager);