November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Federated security lets you separate the service a client is accessing from the associated authentication and authorization procedures; for example, to enable collaboration across multiple systems, networks, and organizations. This topic describes how to configure federated security where Episerver acts as a claims aware application.
This topic shows how to configure Episerver and does not cover basics in federated security or how to configure ADFS.
Note: Episerver Mail and Episerver Relate (using Common Framework), do not support federated security.
Federated security includes features such as Single-Sign-On (SSO) that allows a single user authentication process across multiple IT systems or even organizations. The protocol used is WS-Federation which is a specification supported by a wide range of federation software, such as Active Directory Federation Services (ADFS). Other federation specifications may require third-party software. In documentation the Relying party (RP) refers to the website running Episerver. The identity server/identity provider/federation server/Security Token Service(STS) is a third-party software, such as ADFS.
In short, when authentication is required (Episerver sends HTTP status code 401), a redirect sends the user to an identity provider that after authentication sends back claims about the user. You can use role claims to assign access rights to content or enable access to edit mode. There is no user interface to manage roles and users synchronized from the identity provider; everything that is synchronized is visible for setting access rights by an editor.
To support assigning access rights to role claims or sending notifications to a user that is not logged in, users and roles are synchronized to the database. The synchronization of users and roles is triggered when an identity provider sends back claims about a user to Episerver.
Federated security was originally implemented in Windows Identity Foundation (WIF), but is fully integrated into the core framework (as of .NET 4.5). Since the release of .NET 4.5, Microsoft has developed a new module called Microsoft.Owin.Security.WSFederation that simplifies configuration but builds on the same proven platform support. This module requires the OWIN framework, which contains abstractions to simplify building .NET middleware that need to run on multiple hosts. See OWIN and Episerver.
The OWIN provider for WS Federation does not support multi-tenancy so each site must run in it's own web application for authentication to work on all URL's (the WtRealm configuration specified in the example below cannot vary per request). The OWIN provider for OpenID connect can work with multiple URL's, see integration with Azure Active Directory.
Disable the built-in Role and Membership providers in web.config because they do not support federated security:
<authentication mode="None" />
<membership>
<providers>
<clear/>
</providers>
</membership>
<roleManager enabled="false">
<providers>
<clear/>
</providers>
</roleManager>
Note: roleManager is disabled to prevent administrators from adding users to group membership in the admin view, because these users cannot log in with federated security in place.
Enable claims on virtual roles by setting the addClaims property. Also add the provider for security entities, which is used by the set access rights dialog and impersonating users. The SynchronizingRolesSecurityEntityProvider configured in the following example is using the SynchronizingUserService that is used in step 4.
<episerver.framework>
<securityEntity>
<providers>
<add name="SynchronizingProvider" type ="EPiServer.Security.SynchronizingRolesSecurityEntityProvider, EPiServer"/>
</providers>
</securityEntity>
<virtualRoles addClaims="true">
//existing virtual roles
</virtualRoles>
Open Package Manager in Visual Studio and install the following packages:
Install-Package Microsoft.Owin.Security.Cookies
Install-Package Microsoft.Owin.Security.WsFederation
Install-Package Microsoft.Owin.Host.SystemWeb
Update-Package Microsoft.IdentityModel.Protocol.Extensions -Safe
Note: Always use Microsoft.IdentityModel.Protocol.Extensions package version 1.0.2 or later, previous versions contain a critical bug that might cause threads to hang.
The WSFederation package is configured from code rather from configuration files, which is a practice used for Owin based middleware. See ASP.NET documentation for details about having different configuration in production and development.
Add the following code to the template project. Replace the MetadataAdress with the URL to the federation server and the Wtrealm must match exacly what is registrered in the federation server. See inline comments for more details.
using EPiServer.Framework;
using EPiServer.Security;
using EPiServer.ServiceLocation;
using Microsoft.Owin;
using Microsoft.Owin.Extensions;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.WsFederation;
using Owin;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web.Helpers;
using WsFederationSite;
[assembly: OwinStartup(typeof(Startup))]
namespace WsFederationSite
{
public class Startup
{
const string LogoutUrl = "/util/logout.aspx";
public void Configuration(IAppBuilder app)
{
//Enable cookie authentication, used to store the claims between requests
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<ISynchronizingUserService>().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;
}
}
}
Identity providers, such as ADFS, will not display helpful error information on the login screen because that could compromise security. Check the event log of the identity provider to get details about the cause of an error.
The most common cause is that WtRealm in the code above does not exactly match the value entered as "Relying party identifiers" in the identity provider. Be aware that the value of the WtRealm is just an identifier and does not have to be the URL to the site. The URL that the identity provider posts back the claims to is in most cases another setting defined in the identity provider.
Both servers should be using SSL to the protect the communication for dev/test purposes. You can use self-signed certificates on both the web server and identity server. The web server must trust the certificate of the SSL connection to the identity server to access the metadata document defined in the code, when using self-signed certificates you can add the root certificate to the web server.
You may not configure the identity provider to send a Name-claim. See the identity provider documentation to resolve this.
Alloy templates use Forms Authentication in the Login/Logout link at the bottom the layout, to provide federated authentication change the Login link to send a 401 Access Denied, which triggers the WS Federation middleware. For Logout, use either /Util/Logout.aspx, which is remapped in the previous example, or call the same Signout method in the templates.
If the project previously did not have an Owin startup class and optimizeCompilations was enabled, then sometimes the new code is not executed, the result is that you get a 401.2 Access Denied message instead of the redirect to the identity provider. Temporarily set optimizeCompilations in web.config to false to clear the cache.
When the identity provider does not send the required role claims, you will not get access to edit mode. You could configure the identity provider to send the CmsAdmins role claim for a specific group of users.
You can view warning messages reported by Owin Security by adding the following configuration to web.config. These warning messages may contain information about errors in the WS-Federation communication protocol.
<system.diagnostics>
<switches>
<add name="Microsoft.Owin.Security" value="Warning" />
</switches>
<trace autoflush="true"></trace>
<sharedListeners>
<add name="file" type="System.Diagnostics.TextWriterTraceListener" initializeData="App_Data\OwinSecurity.log" />
</sharedListeners>
<sources>
<source name="Microsoft.Owin.Security">
<listeners>
<add name="file" />
</listeners>
</source>
</sources>
</system.diagnostics>
The Alloy templates assume you are running forms authentication. You can remove the login link if not required, or implement custom login functionality. For example, create a controller or web forms page that sends a 401 Access Denied message for non-authenticated users.
Last updated: Sep 21, 2015