2015-02-04 19:24:59 +11:00
using System ;
2015-10-30 15:17:58 +01:00
using System.Threading ;
2020-08-11 16:06:37 +10:00
using System.Web ;
2020-06-19 11:24:03 +10:00
using System.Web.Mvc ;
2020-08-11 16:06:37 +10:00
using System.Web.SessionState ;
2015-03-25 10:57:10 +11:00
using Microsoft.AspNet.Identity ;
using Microsoft.AspNet.Identity.Owin ;
2015-02-04 19:24:59 +11:00
using Microsoft.Owin ;
using Microsoft.Owin.Extensions ;
2015-04-10 14:22:09 +10:00
using Microsoft.Owin.Logging ;
2015-02-19 16:36:39 +01:00
using Microsoft.Owin.Security ;
2015-02-06 14:05:29 +11:00
using Microsoft.Owin.Security.Cookies ;
2018-04-05 23:10:51 +10:00
using Microsoft.Owin.Security.DataHandler ;
using Microsoft.Owin.Security.DataProtection ;
2015-02-04 19:24:59 +11:00
using Owin ;
using Umbraco.Core ;
using Umbraco.Core.Configuration ;
2018-04-06 13:51:54 +10:00
using Umbraco.Core.Configuration.UmbracoSettings ;
2019-03-19 19:16:24 +01:00
using Umbraco.Core.Mapping ;
2015-02-09 17:37:21 +11:00
using Umbraco.Core.Models.Identity ;
using Umbraco.Core.Security ;
2016-09-01 19:06:08 +02:00
using Umbraco.Core.Services ;
2017-05-30 18:13:11 +02:00
using Umbraco.Web.Composing ;
2015-03-25 10:57:10 +11:00
using Constants = Umbraco . Core . Constants ;
2015-02-04 19:24:59 +11:00
2018-08-29 01:15:46 +10:00
namespace Umbraco.Web.Security
2015-02-04 19:24:59 +11:00
{
2016-10-19 11:16:33 +02:00
/// <summary>
/// Provides security/identity extension methods to IAppBuilder.
/// </summary>
2015-02-04 19:24:59 +11:00
public static class AppBuilderExtensions
{
2015-02-09 17:37:21 +11:00
/// <summary>
2015-03-24 13:36:52 +11:00
/// Configure Default Identity User Manager for Umbraco
2015-02-09 17:37:21 +11:00
/// </summary>
/// <param name="app"></param>
2016-09-01 19:06:08 +02:00
/// <param name="services"></param>
2018-04-06 13:51:54 +10:00
/// <param name="contentSettings"></param>
/// <param name="globalSettings"></param>
2015-02-09 17:37:21 +11:00
/// <param name="userMembershipProvider"></param>
2015-06-18 19:16:49 +02:00
public static void ConfigureUserManagerForUmbracoBackOffice ( this IAppBuilder app ,
2016-09-01 19:06:08 +02:00
ServiceContext services ,
2019-04-03 10:39:49 +02:00
UmbracoMapper mapper ,
2018-04-06 13:51:54 +10:00
IContentSection contentSettings ,
IGlobalSettings globalSettings ,
2015-03-24 13:16:32 +11:00
MembershipProviderBase userMembershipProvider )
2015-02-09 17:37:21 +11:00
{
2016-09-01 19:06:08 +02:00
if ( services = = null ) throw new ArgumentNullException ( nameof ( services ) ) ;
if ( userMembershipProvider = = null ) throw new ArgumentNullException ( nameof ( userMembershipProvider ) ) ;
2015-03-26 17:43:22 +11:00
2015-02-09 17:37:21 +11:00
//Configure Umbraco user manager to be created per request
app . CreatePerOwinContext < BackOfficeUserManager > (
( options , owinContext ) = > BackOfficeUserManager . Create (
2015-03-24 12:50:31 +11:00
options ,
2016-09-01 19:06:08 +02:00
services . UserService ,
services . MemberTypeService ,
2017-09-12 16:22:16 +02:00
services . EntityService ,
2016-09-01 19:06:08 +02:00
services . ExternalLoginService ,
2017-09-19 15:51:47 +02:00
userMembershipProvider ,
2019-03-19 19:16:24 +01:00
mapper ,
2018-04-06 13:51:54 +10:00
contentSettings ,
globalSettings ) ) ;
2017-07-20 11:21:28 +02:00
2016-08-12 12:20:00 +02:00
app . SetBackOfficeUserManagerType < BackOfficeUserManager , BackOfficeIdentityUser > ( ) ;
2015-07-01 17:07:29 +02:00
//Create a sign in manager per request
2018-04-06 13:51:54 +10:00
app . CreatePerOwinContext < BackOfficeSignInManager > ( ( options , context ) = > BackOfficeSignInManager . Create ( options , context , globalSettings , app . CreateLogger < BackOfficeSignInManager > ( ) ) ) ;
2015-02-09 17:37:21 +11:00
}
2015-02-04 19:24:59 +11:00
2015-03-24 13:36:52 +11:00
/// <summary>
/// Configure a custom UserStore with the Identity User Manager for Umbraco
/// </summary>
/// <param name="app"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
2015-03-24 13:36:52 +11:00
/// <param name="userMembershipProvider"></param>
/// <param name="customUserStore"></param>
2018-04-06 13:51:54 +10:00
/// <param name="contentSettings"></param>
2015-03-24 13:36:52 +11:00
public static void ConfigureUserManagerForUmbracoBackOffice ( this IAppBuilder app ,
2016-09-01 19:06:08 +02:00
IRuntimeState runtimeState ,
2018-04-06 13:51:54 +10:00
IContentSection contentSettings ,
IGlobalSettings globalSettings ,
2015-03-24 13:36:52 +11:00
MembershipProviderBase userMembershipProvider ,
BackOfficeUserStore customUserStore )
{
2016-09-01 19:06:08 +02:00
if ( runtimeState = = null ) throw new ArgumentNullException ( nameof ( runtimeState ) ) ;
if ( userMembershipProvider = = null ) throw new ArgumentNullException ( nameof ( userMembershipProvider ) ) ;
if ( customUserStore = = null ) throw new ArgumentNullException ( nameof ( customUserStore ) ) ;
2015-03-26 17:43:22 +11:00
2015-03-24 13:36:52 +11:00
//Configure Umbraco user manager to be created per request
app . CreatePerOwinContext < BackOfficeUserManager > (
( options , owinContext ) = > BackOfficeUserManager . Create (
options ,
customUserStore ,
2017-09-19 15:51:47 +02:00
userMembershipProvider ,
2018-04-06 13:51:54 +10:00
contentSettings ) ) ;
2015-07-01 17:07:29 +02:00
2016-08-12 12:20:00 +02:00
app . SetBackOfficeUserManagerType < BackOfficeUserManager , BackOfficeIdentityUser > ( ) ;
2015-07-01 17:07:29 +02:00
//Create a sign in manager per request
2018-04-06 13:51:54 +10:00
app . CreatePerOwinContext < BackOfficeSignInManager > ( ( options , context ) = > BackOfficeSignInManager . Create ( options , context , globalSettings , app . CreateLogger ( typeof ( BackOfficeSignInManager ) . FullName ) ) ) ;
2015-03-24 13:36:52 +11:00
}
2015-03-26 17:43:22 +11:00
/// <summary>
/// Configure a custom BackOfficeUserManager for Umbraco
/// </summary>
/// <param name="app"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
2015-03-26 17:43:22 +11:00
/// <param name="userManager"></param>
public static void ConfigureUserManagerForUmbracoBackOffice < TManager , TUser > ( this IAppBuilder app ,
2016-09-01 19:06:08 +02:00
IRuntimeState runtimeState ,
2018-04-06 13:51:54 +10:00
IGlobalSettings globalSettings ,
2015-03-26 17:43:22 +11:00
Func < IdentityFactoryOptions < TManager > , IOwinContext , TManager > userManager )
2015-06-18 19:16:49 +02:00
where TManager : BackOfficeUserManager < TUser >
2015-03-26 17:43:22 +11:00
where TUser : BackOfficeIdentityUser
{
2016-09-01 19:06:08 +02:00
if ( runtimeState = = null ) throw new ArgumentNullException ( nameof ( runtimeState ) ) ;
if ( userManager = = null ) throw new ArgumentNullException ( nameof ( userManager ) ) ;
2015-03-26 17:43:22 +11:00
//Configure Umbraco user manager to be created per request
app . CreatePerOwinContext < TManager > ( userManager ) ;
2015-07-01 17:07:29 +02:00
2016-08-12 12:20:00 +02:00
app . SetBackOfficeUserManagerType < TManager , TUser > ( ) ;
2015-07-01 17:07:29 +02:00
//Create a sign in manager per request
2016-08-12 12:20:00 +02:00
app . CreatePerOwinContext < BackOfficeSignInManager > (
2018-04-06 13:51:54 +10:00
( options , context ) = > BackOfficeSignInManager . Create ( options , context , globalSettings , app . CreateLogger ( typeof ( BackOfficeSignInManager ) . FullName ) ) ) ;
2015-03-26 17:43:22 +11:00
}
2015-02-04 19:24:59 +11:00
/// <summary>
/// Ensures that the UmbracoBackOfficeAuthenticationMiddleware is assigned to the pipeline
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="userService"></param>
/// <param name="globalSettings"></param>
/// <param name="securitySection"></param>
2015-02-04 19:24:59 +11:00
/// <returns></returns>
2016-03-09 19:37:37 +01:00
/// <remarks>
/// By default this will be configured to execute on PipelineStage.Authenticate
/// </remarks>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoBackOfficeCookieAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IUserService userService , IGlobalSettings globalSettings , ISecuritySection securitySection )
2016-03-09 19:37:37 +01:00
{
2018-04-06 13:51:54 +10:00
return app . UseUmbracoBackOfficeCookieAuthentication ( umbracoContextAccessor , runtimeState , userService , globalSettings , securitySection , PipelineStage . Authenticate ) ;
2016-03-09 19:37:37 +01:00
}
/// <summary>
/// Ensures that the UmbracoBackOfficeAuthenticationMiddleware is assigned to the pipeline
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="userService"></param>
/// <param name="globalSettings"></param>
/// <param name="securitySection"></param>
2016-03-09 19:37:37 +01:00
/// <param name="stage">
/// Configurable pipeline stage
/// </param>
/// <returns></returns>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoBackOfficeCookieAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IUserService userService , IGlobalSettings globalSettings , ISecuritySection securitySection , PipelineStage stage )
2015-02-04 19:24:59 +11:00
{
2016-07-18 10:09:46 +02:00
//Create the default options and provider
2018-04-06 13:51:54 +10:00
var authOptions = app . CreateUmbracoCookieAuthOptions ( umbracoContextAccessor , globalSettings , runtimeState , securitySection ) ;
2015-12-15 16:44:03 +01:00
2018-04-06 13:51:54 +10:00
authOptions . Provider = new BackOfficeCookieAuthenticationProvider ( userService , runtimeState , globalSettings )
2015-12-15 16:44:03 +01:00
{
2016-06-09 11:57:13 +02:00
// Enables the application to validate the security stamp when the user
// logs in. This is a security feature which is used when you
// change a password or add an external login to your account.
2021-02-23 10:41:00 +11:00
OnValidateIdentity = context = >
{
var identity = context . Identity ;
return SecurityStampValidator
. OnValidateIdentity < BackOfficeUserManager , BackOfficeIdentityUser , int > (
2021-02-23 11:25:27 +11:00
TimeSpan . FromMinutes ( 30 ) ,
2021-02-23 10:41:00 +11:00
async ( manager , user ) = >
{
var regenerated = await manager . GenerateUserIdentityAsync ( user ) ;
// Keep any custom claims from the original identity
regenerated . MergeClaimsFromBackOfficeIdentity ( identity ) ;
return regenerated ;
} ,
identity = > identity . GetUserId < int > ( ) ) ( context ) ;
}
2016-07-18 10:09:46 +02:00
2015-12-15 16:44:03 +01:00
} ;
2018-04-06 13:51:54 +10:00
return app . UseUmbracoBackOfficeCookieAuthentication ( umbracoContextAccessor , runtimeState , globalSettings , securitySection , authOptions , stage ) ;
2016-07-18 10:09:46 +02:00
}
2015-12-15 16:44:03 +01:00
2016-07-18 10:09:46 +02:00
/// <summary>
/// Ensures that the UmbracoBackOfficeAuthenticationMiddleware is assigned to the pipeline
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
/// <param name="securitySection"></param>
2016-07-18 10:09:46 +02:00
/// <param name="cookieOptions">Custom auth cookie options can be specified to have more control over the cookie authentication logic</param>
/// <param name="stage">
/// Configurable pipeline stage
/// </param>
/// <returns></returns>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoBackOfficeCookieAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IGlobalSettings globalSettings , ISecuritySection securitySection , CookieAuthenticationOptions cookieOptions , PipelineStage stage )
2016-07-18 10:09:46 +02:00
{
2016-09-01 19:06:08 +02:00
if ( app = = null ) throw new ArgumentNullException ( nameof ( app ) ) ;
if ( runtimeState = = null ) throw new ArgumentNullException ( nameof ( runtimeState ) ) ;
if ( cookieOptions = = null ) throw new ArgumentNullException ( nameof ( cookieOptions ) ) ;
if ( cookieOptions . Provider = = null )
throw new ArgumentNullException ( "cookieOptions.Provider cannot be null." , nameof ( cookieOptions ) ) ;
if ( cookieOptions . Provider is BackOfficeCookieAuthenticationProvider = = false )
throw new ArgumentException ( $"cookieOptions.Provider must be of type {typeof(BackOfficeCookieAuthenticationProvider)}." , nameof ( cookieOptions ) ) ;
app . UseUmbracoBackOfficeCookieAuthenticationInternal ( cookieOptions , runtimeState , stage ) ;
2015-06-18 19:16:49 +02:00
2016-07-18 10:09:46 +02:00
//don't apply if app is not ready
2016-09-01 19:06:08 +02:00
if ( runtimeState . Level ! = RuntimeLevel . Upgrade & & runtimeState . Level ! = RuntimeLevel . Run ) return app ;
2018-04-05 23:10:51 +10:00
var cookieAuthOptions = app . CreateUmbracoCookieAuthOptions (
2018-04-06 13:51:54 +10:00
umbracoContextAccessor , globalSettings , runtimeState , securitySection ,
2016-09-01 19:06:08 +02:00
//This defines the explicit path read cookies from for this middleware
2018-04-06 13:51:54 +10:00
new [ ] { $"{globalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds" } ) ;
2018-04-05 23:10:51 +10:00
cookieAuthOptions . Provider = cookieOptions . Provider ;
2016-09-01 19:06:08 +02:00
//This is a custom middleware, we need to return the user's remaining logged in seconds
app . Use < GetUserSecondsMiddleWare > (
2018-04-05 23:10:51 +10:00
cookieAuthOptions ,
2019-01-07 10:43:28 +01:00
Current . Configs . Global ( ) ,
Current . Configs . Settings ( ) . Security ,
2016-09-01 19:06:08 +02:00
app . CreateLogger < GetUserSecondsMiddleWare > ( ) ) ;
2015-11-19 18:12:21 +01:00
2018-04-05 23:10:51 +10:00
//This is required so that we can read the auth ticket format outside of this pipeline
app . CreatePerOwinContext < UmbracoAuthTicketDataProtector > (
( options , context ) = > new UmbracoAuthTicketDataProtector ( cookieOptions . TicketDataFormat ) ) ;
2015-11-19 18:12:21 +01:00
return app ;
}
2016-08-12 12:20:00 +02:00
private static bool _markerSet = false ;
/// <summary>
/// This registers the exact type of the user manager in owin so we can extract it
/// when required in order to extract the user manager instance
/// </summary>
/// <typeparam name="TManager"></typeparam>
/// <typeparam name="TUser"></typeparam>
/// <param name="app"></param>
/// <remarks>
/// This is required because a developer can specify a custom user manager and due to generic types the key name will registered
/// differently in the owin context
2017-07-20 11:21:28 +02:00
/// </remarks>
2016-08-12 12:20:00 +02:00
private static void SetBackOfficeUserManagerType < TManager , TUser > ( this IAppBuilder app )
where TManager : BackOfficeUserManager < TUser >
where TUser : BackOfficeIdentityUser
{
if ( _markerSet ) throw new InvalidOperationException ( "The back office user manager marker has already been set, only one back office user manager can be configured" ) ;
2017-07-20 11:21:28 +02:00
//on each request set the user manager getter -
2016-08-12 12:20:00 +02:00
// this is required purely because Microsoft.Owin.IOwinContext is super inflexible with it's Get since it can only be
// a generic strongly typed instance
app . Use ( ( context , func ) = >
{
context . Set ( BackOfficeUserManager . OwinMarkerKey , new BackOfficeUserManagerMarker < TManager , TUser > ( ) ) ;
return func ( ) ;
2017-07-20 11:21:28 +02:00
} ) ;
2016-08-12 12:20:00 +02:00
}
2016-09-01 19:06:08 +02:00
private static void UseUmbracoBackOfficeCookieAuthenticationInternal ( this IAppBuilder app , CookieAuthenticationOptions options , IRuntimeState runtimeState , PipelineStage stage )
2015-11-19 18:12:21 +01:00
{
2016-09-01 19:06:08 +02:00
if ( app = = null ) throw new ArgumentNullException ( nameof ( app ) ) ;
if ( runtimeState = = null ) throw new ArgumentNullException ( nameof ( runtimeState ) ) ;
2015-11-19 18:12:21 +01:00
//First the normal cookie middleware
app . Use ( typeof ( CookieAuthenticationMiddleware ) , app , options ) ;
2016-09-01 19:06:08 +02:00
//don't apply if app is not ready
if ( runtimeState . Level = = RuntimeLevel . Upgrade | | runtimeState . Level = = RuntimeLevel . Run )
2015-11-27 21:23:24 +01:00
{
//Then our custom middlewares
2016-06-09 11:57:13 +02:00
app . Use ( typeof ( ForceRenewalCookieAuthenticationMiddleware ) , app , options , Current . UmbracoContextAccessor ) ;
2020-06-19 11:24:03 +10:00
app . Use ( typeof ( FixWindowsAuthMiddlware ) ) ;
2015-11-27 21:23:24 +01:00
}
2016-03-09 17:35:50 +01:00
2016-03-09 19:37:37 +01:00
//Marks all of the above middlewares to execute on Authenticate
2016-09-01 19:06:08 +02:00
app . UseStageMarker ( stage ) ;
2015-02-04 19:24:59 +11:00
}
2016-03-09 19:37:37 +01:00
2015-02-04 19:24:59 +11:00
2015-02-22 15:10:14 +01:00
/// <summary>
/// Ensures that the cookie middleware for validating external logins is assigned to the pipeline with the correct
/// Umbraco back office configuration
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
2015-02-22 15:10:14 +01:00
/// <returns></returns>
2016-03-09 19:37:37 +01:00
/// <remarks>
/// By default this will be configured to execute on PipelineStage.Authenticate
/// </remarks>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IGlobalSettings globalSettings )
2016-03-09 19:37:37 +01:00
{
2018-04-06 13:51:54 +10:00
return app . UseUmbracoBackOfficeExternalCookieAuthentication ( umbracoContextAccessor , runtimeState , globalSettings , PipelineStage . Authenticate ) ;
2016-03-09 19:37:37 +01:00
}
/// <summary>
/// Ensures that the cookie middleware for validating external logins is assigned to the pipeline with the correct
/// Umbraco back office configuration
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
2016-03-09 19:37:37 +01:00
/// <param name="stage"></param>
/// <returns></returns>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication ( this IAppBuilder app ,
IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState ,
IGlobalSettings globalSettings , PipelineStage stage )
2015-02-06 16:13:02 +11:00
{
2016-09-01 19:06:08 +02:00
if ( app = = null ) throw new ArgumentNullException ( nameof ( app ) ) ;
if ( runtimeState = = null ) throw new ArgumentNullException ( nameof ( runtimeState ) ) ;
2015-06-09 12:17:45 +02:00
2015-02-19 16:36:39 +01:00
app . UseCookieAuthentication ( new CookieAuthenticationOptions
{
AuthenticationType = Constants . Security . BackOfficeExternalAuthenticationType ,
AuthenticationMode = AuthenticationMode . Passive ,
2015-03-25 12:21:41 +11:00
CookieName = Constants . Security . BackOfficeExternalCookieName ,
2015-02-19 16:36:39 +01:00
ExpireTimeSpan = TimeSpan . FromMinutes ( 5 ) ,
//Custom cookie manager so we can filter requests
2018-04-06 13:51:54 +10:00
CookieManager = new BackOfficeCookieManager ( umbracoContextAccessor , runtimeState , globalSettings ) ,
2015-02-19 16:36:39 +01:00
CookiePath = "/" ,
2018-04-06 13:51:54 +10:00
CookieSecure = globalSettings . UseHttps ? CookieSecureOption . Always : CookieSecureOption . SameAsRequest ,
2015-02-19 16:36:39 +01:00
CookieHttpOnly = true ,
2019-01-07 10:43:28 +01:00
CookieDomain = Current . Configs . Settings ( ) . Security . AuthCookieDomain
2016-03-09 19:37:37 +01:00
} , stage ) ;
2015-02-19 16:36:39 +01:00
2015-02-06 16:13:02 +11:00
return app ;
2015-06-18 19:16:49 +02:00
}
2016-03-09 17:35:50 +01:00
/// <summary>
/// In order for preview to work this needs to be called
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
/// <param name="securitySettings"></param>
2016-03-09 17:35:50 +01:00
/// <returns></returns>
/// <remarks>
/// This ensures that during a preview request that the back office use is also Authenticated and that the back office Identity
/// is added as a secondary identity to the current IPrincipal so it can be used to Authorize the previewed document.
/// </remarks>
2016-03-09 19:37:37 +01:00
/// <remarks>
/// By default this will be configured to execute on PipelineStage.PostAuthenticate
/// </remarks>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoPreviewAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IGlobalSettings globalSettings , ISecuritySection securitySettings )
2016-03-09 19:37:37 +01:00
{
2018-04-06 13:51:54 +10:00
return app . UseUmbracoPreviewAuthentication ( umbracoContextAccessor , runtimeState , globalSettings , securitySettings , PipelineStage . PostAuthenticate ) ;
2016-03-09 19:37:37 +01:00
}
/// <summary>
/// In order for preview to work this needs to be called
/// </summary>
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
2016-09-01 19:06:08 +02:00
/// <param name="runtimeState"></param>
2018-04-06 13:51:54 +10:00
/// <param name="globalSettings"></param>
/// <param name="securitySettings"></param>
2016-03-09 19:37:37 +01:00
/// <param name="stage"></param>
/// <returns></returns>
/// <remarks>
/// This ensures that during a preview request that the back office use is also Authenticated and that the back office Identity
/// is added as a secondary identity to the current IPrincipal so it can be used to Authorize the previewed document.
/// </remarks>
2018-04-06 13:51:54 +10:00
public static IAppBuilder UseUmbracoPreviewAuthentication ( this IAppBuilder app , IUmbracoContextAccessor umbracoContextAccessor , IRuntimeState runtimeState , IGlobalSettings globalSettings , ISecuritySection securitySettings , PipelineStage stage )
2016-03-09 17:35:50 +01:00
{
2016-09-01 19:06:08 +02:00
if ( runtimeState . Level ! = RuntimeLevel . Run ) return app ;
2016-03-09 19:37:37 +01:00
2018-04-06 13:51:54 +10:00
var authOptions = app . CreateUmbracoCookieAuthOptions ( umbracoContextAccessor , globalSettings , runtimeState , securitySettings ) ;
2019-01-07 10:43:28 +01:00
app . Use ( typeof ( PreviewAuthenticationMiddleware ) , authOptions , Current . Configs . Global ( ) ) ;
2016-06-09 11:57:13 +02:00
2016-09-01 19:06:08 +02:00
// This middleware must execute at least on PostAuthentication, by default it is on Authorize
// The middleware needs to execute after the RoleManagerModule executes which is during PostAuthenticate,
// currently I've had 100% success with ensuring this fires after RoleManagerModule even if this is set
// to PostAuthenticate though not sure if that's always a guarantee so by default it's Authorize.
if ( stage < PipelineStage . PostAuthenticate )
throw new InvalidOperationException ( "The stage specified for UseUmbracoPreviewAuthentication must be greater than or equal to " + PipelineStage . PostAuthenticate ) ;
2016-03-09 17:35:50 +01:00
2016-09-01 19:06:08 +02:00
app . UseStageMarker ( stage ) ;
2016-03-09 17:35:50 +01:00
return app ;
}
2015-02-06 16:13:02 +11:00
2020-06-19 11:24:03 +10:00
/// <summary>
/// Enable the back office to detect and handle errors registered with external login providers
/// </summary>
/// <param name="app"></param>
/// <param name="stage"></param>
/// <returns></returns>
public static IAppBuilder UseUmbracoBackOfficeExternalLoginErrors ( this IAppBuilder app , PipelineStage stage = PipelineStage . Authorize )
2020-08-11 16:06:37 +10:00
{
2020-06-19 11:24:03 +10:00
app . Use ( typeof ( BackOfficeExternalLoginProviderErrorMiddlware ) ) ;
app . UseStageMarker ( stage ) ;
return app ;
}
2015-10-30 15:17:58 +01:00
public static void SanitizeThreadCulture ( this IAppBuilder app )
{
2015-11-17 16:53:56 +01:00
Thread . CurrentThread . SanitizeThreadCulture ( ) ;
2015-10-30 15:17:58 +01:00
}
2016-03-09 17:35:50 +01:00
/// <summary>
/// Create the default umb cookie auth options
/// </summary>
2016-07-18 10:09:46 +02:00
/// <param name="app"></param>
2018-04-06 13:51:54 +10:00
/// <param name="umbracoContextAccessor"></param>
/// <param name="globalSettings"></param>
/// <param name="runtimeState"></param>
/// <param name="securitySettings"></param>
2016-03-09 17:35:50 +01:00
/// <param name="explicitPaths"></param>
/// <returns></returns>
2018-04-06 13:51:54 +10:00
public static UmbracoBackOfficeCookieAuthOptions CreateUmbracoCookieAuthOptions ( this IAppBuilder app ,
2018-12-12 17:49:24 +01:00
IUmbracoContextAccessor umbracoContextAccessor ,
2018-04-06 13:51:54 +10:00
IGlobalSettings globalSettings , IRuntimeState runtimeState , ISecuritySection securitySettings , string [ ] explicitPaths = null )
2016-03-09 17:35:50 +01:00
{
2018-04-05 23:10:51 +10:00
//this is how aspnet wires up the default AuthenticationTicket protector so we'll use the same code
var ticketDataFormat = new TicketDataFormat (
app . CreateDataProtector ( typeof ( CookieAuthenticationMiddleware ) . FullName ,
Constants . Security . BackOfficeAuthenticationType ,
"v1" ) ) ;
2016-03-09 17:35:50 +01:00
var authOptions = new UmbracoBackOfficeCookieAuthOptions (
explicitPaths ,
2018-04-06 13:51:54 +10:00
umbracoContextAccessor ,
securitySettings ,
globalSettings ,
runtimeState ,
2018-04-05 23:10:51 +10:00
ticketDataFormat ) ;
2016-03-09 17:35:50 +01:00
return authOptions ;
}
2015-02-04 19:24:59 +11:00
}
2017-07-20 11:21:28 +02:00
}