Authentication and Authorization in EPiServer CMS 5

Product version:

EPiServer CMS 5 SP1

Document version:

1.0

Document creation date:

30-10-2007

Document last saved:

16-01-2008

Introduction

The authentication and authorization system in EPiServer 4.x has been completely replaced and now uses the default membership and role system as introduced in ASP.NET 2.0. See Scott Guthrie's blog for some background information: ASP.NET 2.0 Membership, Roles, Forms Authentication, and Security Resources. For more details on the provider model, see the "Introduction to the Provider Model" section on the following page: http://msdn2.microsoft.com/en-us/asp.net/aa336558.aspx.

Table of Contents

Why the Change?

One of the overall design goals of EPiServer is to provide the missing parts in order for web developers to build great Web sites with speed and ease. EPiServer 4.x was based on .NET 1.0 / 1.1 and there was very little support for handling authentication and authorization in those frameworks, therefore we created that part.

With the introduction of ASP.NET 2.0 that piece is already in place and a lot of the new controls and components use the new security infrastructure. Therefore it makes sense for EPiServer to leverage the new official way of doing authentication and authorization.

Advantages of the Provider Model

  • Conforming to a standard API
    The provider model for membership and roles makes it possible to plug in a provider for any type of user database, even using third party providers.
  • Separation of authentication and authorization
    The old "authentication providers" in EPiServer 4.x did both authentication and authorization in a single operation. By separating these concerns into two different modules you increase flexibility.
  • Increased scalability
    Since we call out to a provider it is possible to delegate security operations to a separate machine. I.e. if you have to support millions of users you can use any type of system suitable for that volume and call out to that system from EPiServer.
  • Support standard ASP.NET 2.0 controls
    By using the built-in provider model it is possible to use the built-in controls such as System.Web.UI.WebControls.Login and LoginView.
  • Leverage existing knowledge and documentation
    No need to re-learn a new security system if you already know how to work with ASP.NET 2.0

Migration Issues

If you are moving from EPiServer 4 to EPiServer CMS 5 you will have to look out for the following if you are porting code to EPiServer CMS 5:

  • UnifiedPrincipal is gone
    The UnifiedPrincipal class gave you some nice features such as directly listing the roles/groups that a user is member of. When looking at the current user in System.Web.HttpContext.Current.User you would always get a UnifiedPrincipal object back when running under EPiServer 4.x.
    In EPiServer CMS 5 this class has been removed and you should simlpy treat the returned object as an IPrincipal. Most of the functionality in UnifiedPrincipal has been moved to the EPiServer.Security.PrincipalInfo class.
  • SID:s are gone
    In EPiServer 4.x every role and user was assigned a unique integer number to be able to refer to the role/user in a simple way. This number was referred to as a SID = Security IDentifier. With the new security system there is no possibility to maintain such an identity since providers may be replaced and you would have a "mission impossible" trying to synchronize information across various parts of the system.
    Instead we are now completely name-based. This means that you will refer to a role or a user by only giving the name. This may be a bit simpler in terms of code readability and debuggability, but can cause some problems. See the next bullet.
  • Name-based identities
    SID:s are replaced by plain strings identifying a user or a role. This means that there is no way from the name alone to determine if it is a name or a role with full certanity. Access control lists in EPiServer needs to distinguish between roles and users to avoid security problems, this is done by using the EPiServerSecurity.SecurityEntity class that contains a name and a SecurityEntityType indicating if the name is a role or a user. If you need to store a single string that may contain a user or a role, create a SecurityEntity and store the ToString() representation of the SecurityEntity. To get the SecurityEntity back, simply do a SecurityEntity.TryParse(str, out securityEntity).
  • Single provider
    The ASP.NET provider model for roles and membership only allows for one role provider and one membership provider to be active at any time. In EPiServer 4.x you have an authentication provider chain that allows you to connect one or more user databases to EPiServer, attempting authentication against all providers in the chain until a successful attempt is made. This is not supported by ASP.NET 2.0 out-of-the-box, but we have created a Multiplexing provider for roles and membership. This multiplexing provider simply defines a set of providers to call for authentication and then maps a specific membership provider to a specific role provider. I.e. we emulate the authentication provider chain that was present in EPiServer 4.x.

Not all characters are supported when creating names for roles and groups, the characters that are not allowed are: [ ] : | < > + = ; , ? * ' "

Configuration of Authentication and Authorization

Configuration of membership and role providers are done with web.config. Note that if you change providers you may have to revise the security settings (ACL:s) for your entire site, since it is highly likely that user names and role names changes when you switch providers. An example Web.Config section:

<roleManager enabled="true" defaultProvider="WindowsRoleProvider">

  <providers>

    <clear />

    <add name="MultiplexingRoleProvider"

         type="EPiServer.Security.MultiplexingRoleProvider, EPiServer"

         provider1="SqlServerRoleProvider"

         provider2="WindowsRoleProvider"

         providerMap1="SqlServermembershipProvider"

         providerMap2="WindowsMembershipProvider" />

    <add name="WindowsRoleProvider"

         applicationName="EPiServerSample"

         type="EPiServer.Security.WindowsRoleProvider, EPiServer" />

    <add name="SqlServerRoleProvider"

         connectionStringName="EPiServerDB"

         applicationName="EPiServerSample"

         type="System.Web.Security.SqlRoleProvider,

          System.Web, Version=2.0.0.0, Culture=neutral,

          PublicKeyToken=b03f5f7f11d50a3a" />

  </providers>

</roleManager>

 

<membership defaultProvider="WindowsMembershipProvider"

            userIsOnlineTimeWindow="10">

  <providers>

    <clear />

    <add name="MultiplexingMembershipProvider"

         type="EPiServer.Security.MultiplexingMembershipProvider, EPiServer"

         provider1="SqlServerMembershipProvider"

         provider2="WindowsMembershipProvider" />

    <add name="WindowsMembershipProvider"

         type="EPiServer.Security.WindowsMembershipProvider, EPiServer"

         deletePrefix="BUILTIN\" />

    <add name="SqlServerMembershipProvider"

         type="System.Web.Security.SqlMembershipProvider, System.Web,

             Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

         connectionStringName="EPiServerDB"

         requiresQuestionAndAnswer="false"

         applicationName="EPiServerSample"

         requiresUniqueEmail="true"

         passwordFormat="Hashed"

         maxInvalidPasswordAttempts="5"

         minRequiredPasswordLength="7"

         minRequiredNonalphanumericCharacters="0"

         passwordAttemptWindow="10"

         passwordStrengthRegularExpression="" />

  </providers>

</membership>

The <membership> section controls the membership provider to use. Note that even though there are three providers listed in the <providers> section, only one is active at this time - the WindowsMembershipProvder (controlled by the defaultProvider attribute of the <membership> tag). I.e. the <add ...> lines for MultiplexingMembershipProvider and SqlServerMembershipProvider could be removed without affecting the functionality. There is one exception to this statement - if you have selected the MultiplexingMembershipProvider as the default provider, it will make use of additional providers as defined by the provider<n> attributes.

Similarily the <roleManager> section controls the role provider to use. The same basic principles of defaultProvider / Multiplexing provider as for membership applies here as well.

When you select the provider to use you are deciding which user database that EPiServer authenticates its users against. As previously stated it is possible to change the provider at any time but this may cause problems, forcing you to revise the security settings in EPiServer.

Also note that the membership and role providers are configured separately, but a specific membership provider may require a certain role provider and vice versa. For the current set of providers you must have matching role and membership providers, i.e. if you decide to use WindowsMembershipProvider you must use the WindowsRoleProvider.

Administering Security and Access Rights in EPiServer

When you administer access rights to pages in EPiServer you will use three distinct components that are tied very loosely together. This will cause the UI to show information that may appear confusing. The three components are:

  1. Users (delivered by the current membership provider).
  2. Roles (delivered by the current role provider and the virtual roles).
  3. Access control lists (ACL:s).

An ACL is simply a list of SecurityEntities and an access level. The security entity is a name and information stating if the name represents a role or a user. Once you have a security entity in an ACL, it will not be affected by changes in the membership or role provider. One aspect of this is that when you delete a role and then look at an ACL that had an access entry for this role, the role will still be displayed in the ACL.

Membership providers have API:s for creating, editing and deleting users, but not all providers support updates of the user database. The SQL membership provider allows you to modify the user database, but the Windows membership provider does not. This will be reflected in the UI when you browse users.

Note: If you are using the Multiplexing membership provider and want to create users, then the first provider in the multiplexing list (provider1) must support it.
The same applies for role providers.

Virtual Roles

EPiServer CMS 5 introduces an extension of the Role concept called Virtual Roles. These are roles where the membership criteria is determined at runtime for each call to IsInRole. In other words, the virtual role membership is not stored in the database but depends on programmatic criterias.

Virtual roles are controlled by the <virtualRoles> configuration section in web.config. A typical configuration looks like this:

<virtualRoles replacePrincipal="true">

  <providers>

    <add name="Administrators"

    type="EPiServer.Security.WindowsAdministratorsRole, EPiServer" />

    <add name="Everyone"

    type="EPiServer.Security.EveryoneRole, EPiServer" />

    <add name="Authenticated"

    type="EPiServer.Security.AuthenticatedRole, EPiServer" />

    <add name="Anonymous"

    type="EPiServer.Security.AnonymousRole, EPiServer" />

    <add name="Creator"

    type="EPiServer.Security.CreatorRole, EPiServer" />

  </providers>

</virtualRoles>

The EPiServer.Configuration.VirtualRolesElement.ReplacePrincipal attribute controls wether the current principal object gets replaced with a principal object wrapper that also supports Virtual roles. The current principal object can be accessed in several different ways, the recommended approach is to use EPiServer.Security.PrincipalInfo.CurrentPrincipal , but alternate ways such as System.Web.HttpContext.Current.User are also supported.

If replacePrincipal="false" then virtual roles will only be evaluated when checking access rights based on ACL:s in EPiServer, any principal.IsInRole calls for a virtual role will return false.

The <providers> section contains a series of <add...> tags. Each <add> defines a virtual role implementation (as identified by the type attribute) and gives the role a name with the name attribute.

We deliver five virtual roles with EPiServer:

  1. Anonymous
  2. Authenticated
  3. Creator
  4. Everyone
  5. Administrator

In addition to the precreated roles it is very easy to create new virtual roles to allow access based on business rules, such as only allow access during business hours. A common scenario is to define virtual roles that evaluates to true if the user is member of role1 and role2. This can be used to reduce the number of groups needed for setting the required permissions in EPiServer.

The built-in virtual roles are fairly self-explanatory. The two that may require a bit more in-depth explanations are Administrator and Creator.

Administrator is needed to support localized versions of Windows where the Administrators group has been translated, for example in Swedish Windows versions the Administrators group is named Administratörer. The Administrators virtual role will do a localization independent test for the Administrators group, thus eliminating the need to manually modify web.config or access rights in EPiServer.

Creator is only used when evaluating AccessControlLists in EPiServer and it will return true if the current principal is the same as the Creator for an ACL.

Enterprise Configuration Issues

If you are running in an Enterprise configuration and have a web.config file with multiple site definitions, there are some security related issues you should be aware of.

The membership and role provider definitions cannot be configured on a per-site basis; if you have to have separate provider definitions for each site you cannot share the web.config file. This is a restriction in the Microsoft implementation of ASP.NET 2.0 and not a restrinction in EPiServer CMS 5.

If you are using the SQl Server membership/role provider and want to use the same set of users / roles for all sites using the same web.config files (probably the most common scenario), you need to use a separate database for the user/role information.

  1. Create a new database with the SQL Server management tools.
  2. Prepare the new database with the aspnet_regsql tool (part of the Microsoft .NET Framework) to set up the schema needed for the SQL providers.
  3. Add a new connection string to the <connectionStrings> section in web.config (it may be placed in a separate connectionStrings.config file) that points to the newly created database.
  4. Change the connectionStringName attributes of the SqlMembershipProvider and SqlRoleProvider to point to the connection string added in step 3.