V13: Add config to limit concurrent logins (#14989)
* Add config to limit concurrent logins (#14967) * Add new config options * Change validation interval + related changes * Fix typo * Temp fix * Set new setting to false for new dotnet projects * Added logic to update security stamp on sign in + fixed wierd code calling handle signIn twice * Cleanup * Adding empty ctors --------- Co-authored-by: Elitsa <elm@umbraco.dk> * Set default setting to false + remove it from templates --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
committed by
GitHub
parent
42bc50eccf
commit
b0ca3444f4
@@ -17,6 +17,7 @@ public class SecuritySettings
|
|||||||
internal const bool StaticHideDisabledUsersInBackOffice = false;
|
internal const bool StaticHideDisabledUsersInBackOffice = false;
|
||||||
internal const bool StaticAllowPasswordReset = true;
|
internal const bool StaticAllowPasswordReset = true;
|
||||||
internal const bool StaticAllowEditInvariantFromNonDefault = false;
|
internal const bool StaticAllowEditInvariantFromNonDefault = false;
|
||||||
|
internal const bool StaticAllowConcurrentLogins = false;
|
||||||
internal const string StaticAuthCookieName = "UMB_UCONTEXT";
|
internal const string StaticAuthCookieName = "UMB_UCONTEXT";
|
||||||
|
|
||||||
internal const string StaticAllowedUserNameCharacters =
|
internal const string StaticAllowedUserNameCharacters =
|
||||||
@@ -109,4 +110,10 @@ public class SecuritySettings
|
|||||||
[Obsolete("Use ContentSettings.AllowEditFromInvariant instead")]
|
[Obsolete("Use ContentSettings.AllowEditFromInvariant instead")]
|
||||||
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
|
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
|
||||||
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
|
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to allow concurrent logins.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(StaticAllowConcurrentLogins)]
|
||||||
|
public bool AllowConcurrentLogins { get; set; } = StaticAllowConcurrentLogins;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ public class BackOfficeSignInManager : UmbracoSignInManager<BackOfficeIdentityUs
|
|||||||
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||||
IAuthenticationSchemeProvider schemes,
|
IAuthenticationSchemeProvider schemes,
|
||||||
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
||||||
IEventAggregator eventAggregator)
|
IEventAggregator eventAggregator,
|
||||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
IOptions<SecuritySettings> securitySettings)
|
||||||
|
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_externalLogins = externalLogins;
|
_externalLogins = externalLogins;
|
||||||
@@ -45,7 +46,34 @@ public class BackOfficeSignInManager : UmbracoSignInManager<BackOfficeIdentityUs
|
|||||||
_globalSettings = globalSettings.Value;
|
_globalSettings = globalSettings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ctor with all params")]
|
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||||
|
public BackOfficeSignInManager(
|
||||||
|
BackOfficeUserManager userManager,
|
||||||
|
IHttpContextAccessor contextAccessor,
|
||||||
|
IBackOfficeExternalLoginProviders externalLogins,
|
||||||
|
IUserClaimsPrincipalFactory<BackOfficeIdentityUser> claimsFactory,
|
||||||
|
IOptions<IdentityOptions> optionsAccessor,
|
||||||
|
IOptions<GlobalSettings> globalSettings,
|
||||||
|
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||||
|
IAuthenticationSchemeProvider schemes,
|
||||||
|
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
||||||
|
IEventAggregator eventAggregator)
|
||||||
|
: this(
|
||||||
|
userManager,
|
||||||
|
contextAccessor,
|
||||||
|
externalLogins,
|
||||||
|
claimsFactory,
|
||||||
|
optionsAccessor,
|
||||||
|
globalSettings,
|
||||||
|
logger,
|
||||||
|
schemes,
|
||||||
|
confirmation,
|
||||||
|
eventAggregator,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||||
public BackOfficeSignInManager(
|
public BackOfficeSignInManager(
|
||||||
BackOfficeUserManager userManager,
|
BackOfficeUserManager userManager,
|
||||||
IHttpContextAccessor contextAccessor,
|
IHttpContextAccessor contextAccessor,
|
||||||
@@ -56,7 +84,18 @@ public class BackOfficeSignInManager : UmbracoSignInManager<BackOfficeIdentityUs
|
|||||||
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||||
IAuthenticationSchemeProvider schemes,
|
IAuthenticationSchemeProvider schemes,
|
||||||
IUserConfirmation<BackOfficeIdentityUser> confirmation)
|
IUserConfirmation<BackOfficeIdentityUser> confirmation)
|
||||||
: this(userManager, contextAccessor, externalLogins, claimsFactory, optionsAccessor, globalSettings, logger, schemes, confirmation, StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>())
|
: this(
|
||||||
|
userManager,
|
||||||
|
contextAccessor,
|
||||||
|
externalLogins,
|
||||||
|
claimsFactory,
|
||||||
|
optionsAccessor,
|
||||||
|
globalSettings,
|
||||||
|
logger,
|
||||||
|
schemes,
|
||||||
|
confirmation,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>(),
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
using Umbraco.Cms.Web.Common.Security;
|
using Umbraco.Cms.Web.Common.Security;
|
||||||
|
|
||||||
namespace Umbraco.Cms.Web.BackOffice.Security;
|
namespace Umbraco.Cms.Web.BackOffice.Security;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the back office security stamp options
|
/// Configures the back office security stamp options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class
|
public class ConfigureBackOfficeSecurityStampValidatorOptions : IConfigureOptions<BackOfficeSecurityStampValidatorOptions>
|
||||||
ConfigureBackOfficeSecurityStampValidatorOptions : IConfigureOptions<BackOfficeSecurityStampValidatorOptions>
|
|
||||||
{
|
{
|
||||||
|
private readonly SecuritySettings _securitySettings;
|
||||||
|
|
||||||
|
public ConfigureBackOfficeSecurityStampValidatorOptions()
|
||||||
|
: this(StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigureBackOfficeSecurityStampValidatorOptions(IOptions<SecuritySettings> securitySettings)
|
||||||
|
=> _securitySettings = securitySettings.Value;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void Configure(BackOfficeSecurityStampValidatorOptions options)
|
public void Configure(BackOfficeSecurityStampValidatorOptions options)
|
||||||
=> ConfigureSecurityStampOptions.ConfigureOptions(options);
|
=> ConfigureSecurityStampOptions.ConfigureOptions(options, _securitySettings);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,44 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
using Umbraco.Extensions;
|
using Umbraco.Extensions;
|
||||||
|
|
||||||
namespace Umbraco.Cms.Web.Common.Security;
|
namespace Umbraco.Cms.Web.Common.Security;
|
||||||
|
|
||||||
public class ConfigureSecurityStampOptions : IConfigureOptions<SecurityStampValidatorOptions>
|
public class ConfigureSecurityStampOptions : IConfigureOptions<SecurityStampValidatorOptions>
|
||||||
{
|
{
|
||||||
|
private readonly SecuritySettings _securitySettings;
|
||||||
|
|
||||||
|
public ConfigureSecurityStampOptions()
|
||||||
|
: this(StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigureSecurityStampOptions(IOptions<SecuritySettings> securitySettings)
|
||||||
|
=> _securitySettings = securitySettings.Value;
|
||||||
|
|
||||||
|
[Obsolete("Use the overload accepting SecuritySettings instead. Scheduled for removal in v14.")]
|
||||||
|
public static void ConfigureOptions(SecurityStampValidatorOptions options)
|
||||||
|
=> ConfigureOptions(options, StaticServiceProvider.Instance.GetRequiredService<SecuritySettings>());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures security stamp options and ensures any custom claims
|
/// Configures security stamp options and ensures any custom claims
|
||||||
/// set on the identity are persisted to the new identity when it's refreshed.
|
/// set on the identity are persisted to the new identity when it's refreshed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options"></param>
|
/// <param name="options">Options for <see cref="ISecurityStampValidator"/>.</param>
|
||||||
public static void ConfigureOptions(SecurityStampValidatorOptions options)
|
/// <param name="securitySettings">The <see cref="SecuritySettings" /> options.</param>
|
||||||
|
public static void ConfigureOptions(SecurityStampValidatorOptions options, SecuritySettings securitySettings)
|
||||||
{
|
{
|
||||||
options.ValidationInterval = TimeSpan.FromMinutes(30);
|
// Adjust the security stamp validation interval to a shorter duration
|
||||||
|
// when concurrent logins are not allowed and the duration has the default interval value
|
||||||
|
// (currently defaults to 30 minutes), ensuring quicker re-validation.
|
||||||
|
if (securitySettings.AllowConcurrentLogins is false && options.ValidationInterval == TimeSpan.FromMinutes(30))
|
||||||
|
{
|
||||||
|
options.ValidationInterval = TimeSpan.FromSeconds(30);
|
||||||
|
}
|
||||||
|
|
||||||
// When refreshing the principal, ensure custom claims that
|
// When refreshing the principal, ensure custom claims that
|
||||||
// might have been set with an external identity continue
|
// might have been set with an external identity continue
|
||||||
@@ -34,6 +58,7 @@ public class ConfigureSecurityStampOptions : IConfigureOptions<SecurityStampVali
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void Configure(SecurityStampValidatorOptions options)
|
public void Configure(SecurityStampValidatorOptions options)
|
||||||
=> ConfigureOptions(options);
|
=> ConfigureOptions(options, _securitySettings);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
using Umbraco.Cms.Core.DependencyInjection;
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
using Umbraco.Cms.Core.Events;
|
using Umbraco.Cms.Core.Events;
|
||||||
using Umbraco.Cms.Core.Notifications;
|
using Umbraco.Cms.Core.Notifications;
|
||||||
@@ -30,14 +31,40 @@ public class MemberSignInManager : UmbracoSignInManager<MemberIdentityUser>, IMe
|
|||||||
IAuthenticationSchemeProvider schemes,
|
IAuthenticationSchemeProvider schemes,
|
||||||
IUserConfirmation<MemberIdentityUser> confirmation,
|
IUserConfirmation<MemberIdentityUser> confirmation,
|
||||||
IMemberExternalLoginProviders memberExternalLoginProviders,
|
IMemberExternalLoginProviders memberExternalLoginProviders,
|
||||||
IEventAggregator eventAggregator)
|
IEventAggregator eventAggregator,
|
||||||
: base(memberManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
IOptions<SecuritySettings> securitySettings)
|
||||||
|
: base(memberManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings)
|
||||||
{
|
{
|
||||||
_memberExternalLoginProviders = memberExternalLoginProviders;
|
_memberExternalLoginProviders = memberExternalLoginProviders;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ctor with all params")]
|
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||||
|
public MemberSignInManager(
|
||||||
|
UserManager<MemberIdentityUser> memberManager,
|
||||||
|
IHttpContextAccessor contextAccessor,
|
||||||
|
IUserClaimsPrincipalFactory<MemberIdentityUser> claimsFactory,
|
||||||
|
IOptions<IdentityOptions> optionsAccessor,
|
||||||
|
ILogger<SignInManager<MemberIdentityUser>> logger,
|
||||||
|
IAuthenticationSchemeProvider schemes,
|
||||||
|
IUserConfirmation<MemberIdentityUser> confirmation,
|
||||||
|
IMemberExternalLoginProviders memberExternalLoginProviders,
|
||||||
|
IEventAggregator eventAggregator)
|
||||||
|
: this(
|
||||||
|
memberManager,
|
||||||
|
contextAccessor,
|
||||||
|
claimsFactory,
|
||||||
|
optionsAccessor,
|
||||||
|
logger,
|
||||||
|
schemes,
|
||||||
|
confirmation,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IMemberExternalLoginProviders>(),
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>(),
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||||
public MemberSignInManager(
|
public MemberSignInManager(
|
||||||
UserManager<MemberIdentityUser> memberManager,
|
UserManager<MemberIdentityUser> memberManager,
|
||||||
IHttpContextAccessor contextAccessor,
|
IHttpContextAccessor contextAccessor,
|
||||||
|
|||||||
@@ -2,26 +2,32 @@ using System.Security.Claims;
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
using Umbraco.Cms.Core.Security;
|
using Umbraco.Cms.Core.Security;
|
||||||
using Umbraco.Extensions;
|
using Umbraco.Extensions;
|
||||||
|
|
||||||
namespace Umbraco.Cms.Web.Common.Security;
|
namespace Umbraco.Cms.Web.Common.Security;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract sign in manager implementation allowing modifying all defeault authentication schemes
|
/// Abstract sign in manager implementation allowing modifying all default authentication schemes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TUser"></typeparam>
|
/// <typeparam name="TUser"></typeparam>
|
||||||
public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
||||||
where TUser : UmbracoIdentityUser
|
where TUser : UmbracoIdentityUser
|
||||||
{
|
{
|
||||||
|
private SecuritySettings _securitySettings;
|
||||||
|
|
||||||
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
|
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
|
||||||
protected const string UmbracoSignInMgrLoginProviderKey = "LoginProvider";
|
protected const string UmbracoSignInMgrLoginProviderKey = "LoginProvider";
|
||||||
|
|
||||||
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
|
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
|
||||||
protected const string UmbracoSignInMgrXsrfKey = "XsrfId";
|
protected const string UmbracoSignInMgrXsrfKey = "XsrfId";
|
||||||
|
|
||||||
|
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||||
public UmbracoSignInManager(
|
public UmbracoSignInManager(
|
||||||
UserManager<TUser> userManager,
|
UserManager<TUser> userManager,
|
||||||
IHttpContextAccessor contextAccessor,
|
IHttpContextAccessor contextAccessor,
|
||||||
@@ -30,8 +36,30 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
|||||||
ILogger<SignInManager<TUser>> logger,
|
ILogger<SignInManager<TUser>> logger,
|
||||||
IAuthenticationSchemeProvider schemes,
|
IAuthenticationSchemeProvider schemes,
|
||||||
IUserConfirmation<TUser> confirmation)
|
IUserConfirmation<TUser> confirmation)
|
||||||
|
: this(
|
||||||
|
userManager,
|
||||||
|
contextAccessor,
|
||||||
|
claimsFactory,
|
||||||
|
optionsAccessor,
|
||||||
|
logger,
|
||||||
|
schemes,
|
||||||
|
confirmation,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UmbracoSignInManager(
|
||||||
|
UserManager<TUser> userManager,
|
||||||
|
IHttpContextAccessor contextAccessor,
|
||||||
|
IUserClaimsPrincipalFactory<TUser> claimsFactory,
|
||||||
|
IOptions<IdentityOptions> optionsAccessor,
|
||||||
|
ILogger<SignInManager<TUser>> logger,
|
||||||
|
IAuthenticationSchemeProvider schemes,
|
||||||
|
IUserConfirmation<TUser> confirmation,
|
||||||
|
IOptions<SecuritySettings> securitySettingsOptions)
|
||||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
||||||
{
|
{
|
||||||
|
_securitySettings = securitySettingsOptions.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract string AuthenticationType { get; }
|
protected abstract string AuthenticationType { get; }
|
||||||
@@ -47,7 +75,7 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
|||||||
{
|
{
|
||||||
// override to handle logging/events
|
// override to handle logging/events
|
||||||
SignInResult result = await base.PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
|
SignInResult result = await base.PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
|
||||||
return await HandleSignIn(user, user.UserName, result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -340,6 +368,11 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
|||||||
|
|
||||||
await UserManager.UpdateAsync(user);
|
await UserManager.UpdateAsync(user);
|
||||||
|
|
||||||
|
if (_securitySettings.AllowConcurrentLogins is false)
|
||||||
|
{
|
||||||
|
await UserManager.UpdateSecurityStampAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
Logger.LogInformation("User: {UserName} logged in from IP address {IpAddress}", username, Context.Connection.RemoteIpAddress);
|
Logger.LogInformation("User: {UserName} logged in from IP address {IpAddress}", username, Context.Connection.RemoteIpAddress);
|
||||||
}
|
}
|
||||||
else if (result.IsLockedOut)
|
else if (result.IsLockedOut)
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ public class MemberSignInManagerTests
|
|||||||
Mock.Of<IAuthenticationSchemeProvider>(),
|
Mock.Of<IAuthenticationSchemeProvider>(),
|
||||||
Mock.Of<IUserConfirmation<MemberIdentityUser>>(),
|
Mock.Of<IUserConfirmation<MemberIdentityUser>>(),
|
||||||
Mock.Of<IMemberExternalLoginProviders>(),
|
Mock.Of<IMemberExternalLoginProviders>(),
|
||||||
Mock.Of<IEventAggregator>());
|
Mock.Of<IEventAggregator>(),
|
||||||
|
Mock.Of<IOptions<SecuritySettings>>(x => x.Value == new SecuritySettings()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mock<MemberManager> MockMemberManager()
|
private static Mock<MemberManager> MockMemberManager()
|
||||||
|
|||||||
Reference in New Issue
Block a user