Merge branch temp8 into temp8-di
This commit is contained in:
@@ -300,7 +300,7 @@ namespace Umbraco.Web.Security
|
||||
if (member == null)
|
||||
{
|
||||
//this should not happen
|
||||
Current.Logger.Warn<MembershipHelper>("The member validated but then no member was returned with the username " + username);
|
||||
Current.Logger.Warn<MembershipHelper>(() => $"The member validated but then no member was returned with the username {username}");
|
||||
return false;
|
||||
}
|
||||
//Log them in
|
||||
|
||||
@@ -1,115 +1,115 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration.Provider;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Membership Provider for Umbraco Members (User authentication for Frontend applications NOT umbraco CMS)
|
||||
/// </summary>
|
||||
public class MembersMembershipProvider : UmbracoMembershipProvider<IMembershipMemberService, IMember>, IUmbracoMemberTypeMembershipProvider
|
||||
{
|
||||
public MembersMembershipProvider()
|
||||
: this(Current.Services.MemberService, Current.Services.MemberTypeService)
|
||||
{ }
|
||||
|
||||
public MembersMembershipProvider(IMembershipMemberService<IMember> memberService, IMemberTypeService memberTypeService)
|
||||
: base(memberService)
|
||||
{
|
||||
LockPropertyTypeAlias = Constants.Conventions.Member.IsLockedOut;
|
||||
LastLockedOutPropertyTypeAlias = Constants.Conventions.Member.LastLockoutDate;
|
||||
FailedPasswordAttemptsPropertyTypeAlias = Constants.Conventions.Member.FailedPasswordAttempts;
|
||||
ApprovedPropertyTypeAlias = Constants.Conventions.Member.IsApproved;
|
||||
CommentPropertyTypeAlias = Constants.Conventions.Member.Comments;
|
||||
LastLoginPropertyTypeAlias = Constants.Conventions.Member.LastLoginDate;
|
||||
LastPasswordChangedPropertyTypeAlias = Constants.Conventions.Member.LastPasswordChangeDate;
|
||||
PasswordRetrievalQuestionPropertyTypeAlias = Constants.Conventions.Member.PasswordQuestion;
|
||||
PasswordRetrievalAnswerPropertyTypeAlias = Constants.Conventions.Member.PasswordAnswer;
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private string _defaultMemberTypeAlias = "Member";
|
||||
private volatile bool _hasDefaultMember;
|
||||
private static readonly object Locker = new object();
|
||||
private bool _providerKeyAsGuid;
|
||||
|
||||
public override string ProviderName => "MembersMembershipProvider";
|
||||
|
||||
protected override MembershipUser ConvertToMembershipUser(IMember entity)
|
||||
{
|
||||
return entity.AsConcreteMembershipUser(Name, _providerKeyAsGuid);
|
||||
}
|
||||
|
||||
public string LockPropertyTypeAlias { get; }
|
||||
public string LastLockedOutPropertyTypeAlias { get; }
|
||||
public string FailedPasswordAttemptsPropertyTypeAlias { get; }
|
||||
public string ApprovedPropertyTypeAlias { get; }
|
||||
public string CommentPropertyTypeAlias { get; }
|
||||
public string LastLoginPropertyTypeAlias { get; }
|
||||
public string LastPasswordChangedPropertyTypeAlias { get; }
|
||||
public string PasswordRetrievalQuestionPropertyTypeAlias { get; }
|
||||
public string PasswordRetrievalAnswerPropertyTypeAlias { get; }
|
||||
|
||||
public override void Initialize(string name, NameValueCollection config)
|
||||
{
|
||||
base.Initialize(name, config);
|
||||
|
||||
// test for membertype (if not specified, choose the first member type available)
|
||||
if (config["defaultMemberTypeAlias"] != null)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultMemberTypeAlias"];
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default member type alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
|
||||
//devs can configure the provider user key to be a guid if they want, by default it is int
|
||||
if (config["providerKeyType"] != null)
|
||||
{
|
||||
if (config["providerKeyType"] == "guid")
|
||||
{
|
||||
_providerKeyAsGuid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Attempt<string> GetRawPassword(string username)
|
||||
{
|
||||
var found = MemberService.GetByUsername(username);
|
||||
if (found == null) return Attempt<string>.Fail();
|
||||
return Attempt.Succeed(found.RawPasswordValue);
|
||||
}
|
||||
|
||||
public override string DefaultMemberTypeAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = _memberTypeService.GetDefault();
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default member type alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _defaultMemberTypeAlias;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration.Provider;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Membership Provider for Umbraco Members (User authentication for Frontend applications NOT umbraco CMS)
|
||||
/// </summary>
|
||||
public class MembersMembershipProvider : UmbracoMembershipProvider<IMembershipMemberService, IMember>, IUmbracoMemberTypeMembershipProvider
|
||||
{
|
||||
public MembersMembershipProvider()
|
||||
: this(Current.Services.MemberService, Current.Services.MemberTypeService)
|
||||
{ }
|
||||
|
||||
public MembersMembershipProvider(IMembershipMemberService<IMember> memberService, IMemberTypeService memberTypeService)
|
||||
: base(memberService)
|
||||
{
|
||||
LockPropertyTypeAlias = Constants.Conventions.Member.IsLockedOut;
|
||||
LastLockedOutPropertyTypeAlias = Constants.Conventions.Member.LastLockoutDate;
|
||||
FailedPasswordAttemptsPropertyTypeAlias = Constants.Conventions.Member.FailedPasswordAttempts;
|
||||
ApprovedPropertyTypeAlias = Constants.Conventions.Member.IsApproved;
|
||||
CommentPropertyTypeAlias = Constants.Conventions.Member.Comments;
|
||||
LastLoginPropertyTypeAlias = Constants.Conventions.Member.LastLoginDate;
|
||||
LastPasswordChangedPropertyTypeAlias = Constants.Conventions.Member.LastPasswordChangeDate;
|
||||
PasswordRetrievalQuestionPropertyTypeAlias = Constants.Conventions.Member.PasswordQuestion;
|
||||
PasswordRetrievalAnswerPropertyTypeAlias = Constants.Conventions.Member.PasswordAnswer;
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private string _defaultMemberTypeAlias = "Member";
|
||||
private volatile bool _hasDefaultMember;
|
||||
private static readonly object Locker = new object();
|
||||
private bool _providerKeyAsGuid;
|
||||
|
||||
public override string ProviderName => "MembersMembershipProvider";
|
||||
|
||||
protected override MembershipUser ConvertToMembershipUser(IMember entity)
|
||||
{
|
||||
return entity.AsConcreteMembershipUser(Name, _providerKeyAsGuid);
|
||||
}
|
||||
|
||||
public string LockPropertyTypeAlias { get; }
|
||||
public string LastLockedOutPropertyTypeAlias { get; }
|
||||
public string FailedPasswordAttemptsPropertyTypeAlias { get; }
|
||||
public string ApprovedPropertyTypeAlias { get; }
|
||||
public string CommentPropertyTypeAlias { get; }
|
||||
public string LastLoginPropertyTypeAlias { get; }
|
||||
public string LastPasswordChangedPropertyTypeAlias { get; }
|
||||
public string PasswordRetrievalQuestionPropertyTypeAlias { get; }
|
||||
public string PasswordRetrievalAnswerPropertyTypeAlias { get; }
|
||||
|
||||
public override void Initialize(string name, NameValueCollection config)
|
||||
{
|
||||
base.Initialize(name, config);
|
||||
|
||||
// test for membertype (if not specified, choose the first member type available)
|
||||
if (config["defaultMemberTypeAlias"] != null)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultMemberTypeAlias"];
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default member type alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
|
||||
//devs can configure the provider user key to be a guid if they want, by default it is int
|
||||
if (config["providerKeyType"] != null)
|
||||
{
|
||||
if (config["providerKeyType"] == "guid")
|
||||
{
|
||||
_providerKeyAsGuid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Attempt<string> GetRawPassword(string username)
|
||||
{
|
||||
var found = MemberService.GetByUsername(username);
|
||||
if (found == null) return Attempt<string>.Fail();
|
||||
return Attempt.Succeed(found.RawPasswordValue);
|
||||
}
|
||||
|
||||
public override string DefaultMemberTypeAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = _memberTypeService.GetDefault();
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default member type alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _defaultMemberTypeAlias;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Web.Security.Providers
|
||||
if (MemberService.Exists(username))
|
||||
{
|
||||
status = MembershipCreateStatus.DuplicateUserName;
|
||||
Current.Logger.Warn<UmbracoMembershipProvider<T, TEntity>>("Cannot create member as username already exists: " + username);
|
||||
Current.Logger.Warn<UmbracoMembershipProvider<T, TEntity>>(() => $"Cannot create member as username already exists: {username}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -157,8 +157,7 @@ namespace Umbraco.Web.Security.Providers
|
||||
if (MemberService.GetByEmail(email) != null && RequiresUniqueEmail)
|
||||
{
|
||||
status = MembershipCreateStatus.DuplicateEmail;
|
||||
Current.Logger.Warn<UmbracoMembershipProvider<T, TEntity>>(
|
||||
"Cannot create member as a member with the same email address exists: " + email);
|
||||
Current.Logger.Warn<UmbracoMembershipProvider<T, TEntity>>(() => $"Cannot create member as a member with the same email address exists: {email}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -525,11 +524,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
if (member == null)
|
||||
{
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt failed for username {0} from IP address {1}, the user does not exist",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt failed for username {username} from IP address {GetCurrentRequestIpAddress()}, the user does not exist" );
|
||||
|
||||
return new ValidateUserResult
|
||||
{
|
||||
@@ -539,11 +535,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
if (member.IsApproved == false)
|
||||
{
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt failed for username {0} from IP address {1}, the user is not approved",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt failed for username {username} from IP address {GetCurrentRequestIpAddress()}, the user is not approved");
|
||||
|
||||
return new ValidateUserResult
|
||||
{
|
||||
@@ -553,11 +546,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
}
|
||||
if (member.IsLockedOut)
|
||||
{
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt failed for username {0} from IP address {1}, the user is locked",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt failed for username {username} from IP address {GetCurrentRequestIpAddress()}, the user is locked");
|
||||
|
||||
return new ValidateUserResult
|
||||
{
|
||||
@@ -581,19 +571,13 @@ namespace Umbraco.Web.Security.Providers
|
||||
member.IsLockedOut = true;
|
||||
member.LastLockoutDate = DateTime.Now;
|
||||
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt failed for username {0} from IP address {1}, the user is now locked out, max invalid password attempts exceeded",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt failed for username {username} from IP address {GetCurrentRequestIpAddress()}, the user is now locked out, max invalid password attempts exceeded");
|
||||
}
|
||||
else
|
||||
{
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt failed for username {0} from IP address {1}",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt failed for username {username} from IP address {GetCurrentRequestIpAddress()}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -606,11 +590,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
member.LastLoginDate = DateTime.Now;
|
||||
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(
|
||||
string.Format(
|
||||
"Login attempt succeeded for username {0} from IP address {1}",
|
||||
username,
|
||||
GetCurrentRequestIpAddress()));
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>(() =>
|
||||
$"Login attempt succeeded for username {username} from IP address {GetCurrentRequestIpAddress()}");
|
||||
}
|
||||
|
||||
//don't raise events for this! It just sets the member dates, if we do raise events this will
|
||||
|
||||
@@ -1,188 +1,188 @@
|
||||
using System;
|
||||
using System.Configuration.Provider;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Membership Provider for Umbraco Users (User authentication for Umbraco Backend CMS)
|
||||
/// </summary>
|
||||
public class UsersMembershipProvider : UmbracoMembershipProvider<IMembershipUserService, IUser>, IUsersMembershipProvider
|
||||
{
|
||||
|
||||
public UsersMembershipProvider()
|
||||
: this(Current.Services.UserService, Current.Services.MemberTypeService)
|
||||
{
|
||||
}
|
||||
|
||||
public UsersMembershipProvider(IMembershipMemberService<IUser> memberService, IMemberTypeService memberTypeService)
|
||||
: base(memberService)
|
||||
{
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private string _defaultMemberTypeAlias = "writer";
|
||||
private volatile bool _hasDefaultMember = false;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public override string ProviderName
|
||||
{
|
||||
get { return UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider; }
|
||||
}
|
||||
|
||||
protected override MembershipUser ConvertToMembershipUser(IUser entity)
|
||||
{
|
||||
//the provider user key is always the int id
|
||||
return entity.AsConcreteMembershipUser(Name, true);
|
||||
}
|
||||
|
||||
private bool _allowManuallyChangingPassword = false;
|
||||
private bool _enablePasswordReset = false;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the membership provider is configured to allow users to reset their passwords.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>true if the membership provider supports password reset; otherwise, false. The default is FALSE for users.</returns>
|
||||
public override bool EnablePasswordReset
|
||||
{
|
||||
get { return _enablePasswordReset; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility, this provider supports this option by default it is FALSE for users
|
||||
/// </summary>
|
||||
public override bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return _allowManuallyChangingPassword; }
|
||||
}
|
||||
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
base.Initialize(name, config);
|
||||
|
||||
if (config == null) { throw new ArgumentNullException("config"); }
|
||||
|
||||
_allowManuallyChangingPassword = config.GetValue("allowManuallyChangingPassword", false);
|
||||
_enablePasswordReset = config.GetValue("enablePasswordReset", false);
|
||||
|
||||
// test for membertype (if not specified, choose the first member type available)
|
||||
// We'll support both names for legacy reasons: defaultUserTypeAlias & defaultUserGroupAlias
|
||||
|
||||
if (config["defaultUserTypeAlias"] != null)
|
||||
{
|
||||
if (config["defaultUserTypeAlias"].IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultUserTypeAlias"];
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
if (_hasDefaultMember == false && config["defaultUserGroupAlias"] != null)
|
||||
{
|
||||
if (config["defaultUserGroupAlias"].IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultUserGroupAlias"];
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultMemberTypeAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = _memberTypeService.GetDefault();
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default user group alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _defaultMemberTypeAlias;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden in order to call the BackOfficeUserManager.UnlockUser method in order to raise the user audit events
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="member"></param>
|
||||
/// <returns></returns>
|
||||
internal override bool PerformUnlockUser(string username, out IUser member)
|
||||
{
|
||||
var result = base.PerformUnlockUser(username, out member);
|
||||
if (result)
|
||||
{
|
||||
var userManager = GetBackofficeUserManager();
|
||||
if (userManager != null)
|
||||
{
|
||||
userManager.RaiseAccountUnlockedEvent(member.Id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in order to raise appropriate events via the <see cref="BackOfficeUserManager"/>
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
internal override ValidateUserResult PerformValidateUser(string username, string password)
|
||||
{
|
||||
var result = base.PerformValidateUser(username, password);
|
||||
|
||||
var userManager = GetBackofficeUserManager();
|
||||
|
||||
if (userManager == null) return result;
|
||||
|
||||
if (result.Authenticated == false)
|
||||
{
|
||||
var count = result.Member.FailedPasswordAttempts;
|
||||
if (count >= MaxInvalidPasswordAttempts)
|
||||
{
|
||||
userManager.RaiseAccountLockedEvent(result.Member.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Member.FailedPasswordAttempts > 0)
|
||||
{
|
||||
//we have successfully logged in, if the failed password attempts was modified it means it was reset
|
||||
if (result.Member.WasPropertyDirty("FailedPasswordAttempts"))
|
||||
{
|
||||
userManager.RaiseResetAccessFailedCountEvent(result.Member.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal BackOfficeUserManager<BackOfficeIdentityUser> GetBackofficeUserManager()
|
||||
{
|
||||
return HttpContext.Current == null
|
||||
? null
|
||||
: HttpContext.Current.GetOwinContext().GetBackOfficeUserManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Configuration.Provider;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Membership Provider for Umbraco Users (User authentication for Umbraco Backend CMS)
|
||||
/// </summary>
|
||||
public class UsersMembershipProvider : UmbracoMembershipProvider<IMembershipUserService, IUser>, IUsersMembershipProvider
|
||||
{
|
||||
|
||||
public UsersMembershipProvider()
|
||||
: this(Current.Services.UserService, Current.Services.MemberTypeService)
|
||||
{
|
||||
}
|
||||
|
||||
public UsersMembershipProvider(IMembershipMemberService<IUser> memberService, IMemberTypeService memberTypeService)
|
||||
: base(memberService)
|
||||
{
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private string _defaultMemberTypeAlias = "writer";
|
||||
private volatile bool _hasDefaultMember = false;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public override string ProviderName
|
||||
{
|
||||
get { return UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider; }
|
||||
}
|
||||
|
||||
protected override MembershipUser ConvertToMembershipUser(IUser entity)
|
||||
{
|
||||
//the provider user key is always the int id
|
||||
return entity.AsConcreteMembershipUser(Name, true);
|
||||
}
|
||||
|
||||
private bool _allowManuallyChangingPassword = false;
|
||||
private bool _enablePasswordReset = false;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the membership provider is configured to allow users to reset their passwords.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>true if the membership provider supports password reset; otherwise, false. The default is FALSE for users.</returns>
|
||||
public override bool EnablePasswordReset
|
||||
{
|
||||
get { return _enablePasswordReset; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility, this provider supports this option by default it is FALSE for users
|
||||
/// </summary>
|
||||
public override bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return _allowManuallyChangingPassword; }
|
||||
}
|
||||
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
base.Initialize(name, config);
|
||||
|
||||
if (config == null) { throw new ArgumentNullException("config"); }
|
||||
|
||||
_allowManuallyChangingPassword = config.GetValue("allowManuallyChangingPassword", false);
|
||||
_enablePasswordReset = config.GetValue("enablePasswordReset", false);
|
||||
|
||||
// test for membertype (if not specified, choose the first member type available)
|
||||
// We'll support both names for legacy reasons: defaultUserTypeAlias & defaultUserGroupAlias
|
||||
|
||||
if (config["defaultUserTypeAlias"] != null)
|
||||
{
|
||||
if (config["defaultUserTypeAlias"].IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultUserTypeAlias"];
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
if (_hasDefaultMember == false && config["defaultUserGroupAlias"] != null)
|
||||
{
|
||||
if (config["defaultUserGroupAlias"].IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = config["defaultUserGroupAlias"];
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultMemberTypeAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (_hasDefaultMember == false)
|
||||
{
|
||||
_defaultMemberTypeAlias = _memberTypeService.GetDefault();
|
||||
if (_defaultMemberTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ProviderException("No default user group alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config");
|
||||
}
|
||||
_hasDefaultMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _defaultMemberTypeAlias;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden in order to call the BackOfficeUserManager.UnlockUser method in order to raise the user audit events
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="member"></param>
|
||||
/// <returns></returns>
|
||||
internal override bool PerformUnlockUser(string username, out IUser member)
|
||||
{
|
||||
var result = base.PerformUnlockUser(username, out member);
|
||||
if (result)
|
||||
{
|
||||
var userManager = GetBackofficeUserManager();
|
||||
if (userManager != null)
|
||||
{
|
||||
userManager.RaiseAccountUnlockedEvent(member.Id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in order to raise appropriate events via the <see cref="BackOfficeUserManager"/>
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
internal override ValidateUserResult PerformValidateUser(string username, string password)
|
||||
{
|
||||
var result = base.PerformValidateUser(username, password);
|
||||
|
||||
var userManager = GetBackofficeUserManager();
|
||||
|
||||
if (userManager == null) return result;
|
||||
|
||||
if (result.Authenticated == false)
|
||||
{
|
||||
var count = result.Member.FailedPasswordAttempts;
|
||||
if (count >= MaxInvalidPasswordAttempts)
|
||||
{
|
||||
userManager.RaiseAccountLockedEvent(result.Member.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Member.FailedPasswordAttempts > 0)
|
||||
{
|
||||
//we have successfully logged in, if the failed password attempts was modified it means it was reset
|
||||
if (result.Member.WasPropertyDirty("FailedPasswordAttempts"))
|
||||
{
|
||||
userManager.RaiseResetAccessFailedCountEvent(result.Member.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal BackOfficeUserManager<BackOfficeIdentityUser> GetBackofficeUserManager()
|
||||
{
|
||||
return HttpContext.Current == null
|
||||
? null
|
||||
: HttpContext.Current.GetOwinContext().GetBackOfficeUserManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
public enum ValidateRequestAttempt
|
||||
{
|
||||
Success = 0,
|
||||
|
||||
FailedNoPrivileges = 100,
|
||||
|
||||
//FailedTimedOut,
|
||||
|
||||
FailedNoContextId = 101,
|
||||
FailedNoSsl = 102
|
||||
}
|
||||
}
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
public enum ValidateRequestAttempt
|
||||
{
|
||||
Success = 0,
|
||||
|
||||
FailedNoPrivileges = 100,
|
||||
|
||||
//FailedTimedOut,
|
||||
|
||||
FailedNoContextId = 101,
|
||||
FailedNoSsl = 102
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,299 +1,299 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Web.Composing;
|
||||
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class used for dealing with USER security in Umbraco
|
||||
/// </summary>
|
||||
public class WebSecurity : DisposableObjectSlim
|
||||
{
|
||||
private HttpContextBase _httpContext;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public WebSecurity(HttpContextBase httpContext, IUserService userService, IGlobalSettings globalSettings)
|
||||
{
|
||||
_httpContext = httpContext;
|
||||
_userService = userService;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true or false if the currently logged in member is authorized based on the parameters provided
|
||||
/// </summary>
|
||||
/// <param name="allowAll"></param>
|
||||
/// <param name="allowTypes"></param>
|
||||
/// <param name="allowGroups"></param>
|
||||
/// <param name="allowMembers"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use MembershipHelper.IsMemberAuthorized instead")]
|
||||
public bool IsMemberAuthorized(
|
||||
bool allowAll = false,
|
||||
IEnumerable<string> allowTypes = null,
|
||||
IEnumerable<string> allowGroups = null,
|
||||
IEnumerable<int> allowMembers = null)
|
||||
{
|
||||
if (Current.UmbracoContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var helper = Current.Container.GetInstance<MembershipHelper>();
|
||||
return helper.IsMemberAuthorized(allowAll, allowTypes, allowGroups, allowMembers);
|
||||
}
|
||||
|
||||
private IUser _currentUser;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current user.
|
||||
/// </summary>
|
||||
/// <value>The current user.</value>
|
||||
public virtual IUser CurrentUser
|
||||
{
|
||||
get
|
||||
{
|
||||
//only load it once per instance! (but make sure groups are loaded)
|
||||
if (_currentUser == null)
|
||||
{
|
||||
var id = GetUserId();
|
||||
_currentUser = id ? _userService.GetUserById(id.Result) : null;
|
||||
}
|
||||
|
||||
return _currentUser;
|
||||
}
|
||||
}
|
||||
|
||||
private BackOfficeSignInManager _signInManager;
|
||||
private BackOfficeSignInManager SignInManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_signInManager == null)
|
||||
{
|
||||
var mgr = _httpContext.GetOwinContext().Get<BackOfficeSignInManager>();
|
||||
if (mgr == null)
|
||||
{
|
||||
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeSignInManager) + " from the " + typeof(IOwinContext));
|
||||
}
|
||||
_signInManager = mgr;
|
||||
}
|
||||
return _signInManager;
|
||||
}
|
||||
}
|
||||
|
||||
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
|
||||
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager
|
||||
=> _userManager ?? (_userManager = _httpContext.GetOwinContext().GetBackOfficeUserManager());
|
||||
|
||||
/// <summary>
|
||||
/// Logs a user in.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user Id</param>
|
||||
/// <returns>returns the number of seconds until their session times out</returns>
|
||||
public virtual double PerformLogin(int userId)
|
||||
{
|
||||
var owinCtx = _httpContext.GetOwinContext();
|
||||
//ensure it's done for owin too
|
||||
owinCtx.Authentication.SignOut(Constants.Security.BackOfficeExternalAuthenticationType);
|
||||
|
||||
var user = UserManager.FindByIdAsync(userId).Result;
|
||||
|
||||
SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false).Wait();
|
||||
|
||||
_httpContext.SetPrincipalForRequest(owinCtx.Request.User);
|
||||
|
||||
return TimeSpan.FromMinutes(_globalSettings.TimeOutInMinutes).TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current login for the currently logged in user
|
||||
/// </summary>
|
||||
public virtual void ClearCurrentLogin()
|
||||
{
|
||||
_httpContext.UmbracoLogout();
|
||||
_httpContext.GetOwinContext().Authentication.SignOut(
|
||||
Core.Constants.Security.BackOfficeAuthenticationType,
|
||||
Core.Constants.Security.BackOfficeExternalAuthenticationType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renews the user's login ticket
|
||||
/// </summary>
|
||||
public virtual void RenewLoginTimeout()
|
||||
{
|
||||
_httpContext.RenewUmbracoAuthTicket();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates credentials for a back office user
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This uses ASP.NET Identity to perform the validation
|
||||
/// </remarks>
|
||||
public virtual bool ValidateBackOfficeCredentials(string username, string password)
|
||||
{
|
||||
//find the user by username
|
||||
var user = UserManager.FindByNameAsync(username).Result;
|
||||
return user != null && UserManager.CheckPasswordAsync(user, password).Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current user to see if they have access to the specified app
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
internal bool ValidateUserApp(string app)
|
||||
{
|
||||
//if it is empty, don't validate
|
||||
if (app.IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return CurrentUser.AllowedSections.Any(uApp => uApp.InvariantEquals(app));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current user's id.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Attempt<int> GetUserId()
|
||||
{
|
||||
var identity = _httpContext.GetCurrentIdentity(false);
|
||||
return identity == null ? Attempt.Fail<int>() : Attempt.Succeed(Convert.ToInt32(identity.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current user's unique session id - used to mitigate csrf attacks or any other reason to validate a request
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GetSessionId()
|
||||
{
|
||||
var identity = _httpContext.GetCurrentIdentity(false);
|
||||
return identity?.SessionId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the currently logged in user and ensures they are not timed out
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool ValidateCurrentUser()
|
||||
{
|
||||
return ValidateCurrentUser(false, true) == ValidateRequestAttempt.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current user assigned to the request and ensures the stored user data is valid
|
||||
/// </summary>
|
||||
/// <param name="throwExceptions">set to true if you want exceptions to be thrown if failed</param>
|
||||
/// <param name="requiresApproval">If true requires that the user is approved to be validated</param>
|
||||
/// <returns></returns>
|
||||
public virtual ValidateRequestAttempt ValidateCurrentUser(bool throwExceptions, bool requiresApproval = true)
|
||||
{
|
||||
//This will first check if the current user is already authenticated - which should be the case in nearly all circumstances
|
||||
// since the authentication happens in the Module, that authentication also checks the ticket expiry. We don't
|
||||
// need to check it a second time because that requires another decryption phase and nothing can tamper with it during the request.
|
||||
|
||||
if (IsAuthenticated() == false)
|
||||
{
|
||||
//There is no user
|
||||
if (throwExceptions) throw new InvalidOperationException("The user has no umbraco contextid - try logging in");
|
||||
return ValidateRequestAttempt.FailedNoContextId;
|
||||
}
|
||||
|
||||
var user = CurrentUser;
|
||||
|
||||
// Check for console access
|
||||
if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContext)))
|
||||
{
|
||||
if (throwExceptions) throw new ArgumentException("You have no priviledges to the umbraco console. Please contact your administrator");
|
||||
return ValidateRequestAttempt.FailedNoPrivileges;
|
||||
}
|
||||
return ValidateRequestAttempt.Success;
|
||||
|
||||
}
|
||||
|
||||
private static bool RequestIsInUmbracoApplication(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower(), StringComparison.Ordinal) > -1;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Web.Composing;
|
||||
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class used for dealing with USER security in Umbraco
|
||||
/// </summary>
|
||||
public class WebSecurity : DisposableObjectSlim
|
||||
{
|
||||
private HttpContextBase _httpContext;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public WebSecurity(HttpContextBase httpContext, IUserService userService, IGlobalSettings globalSettings)
|
||||
{
|
||||
_httpContext = httpContext;
|
||||
_userService = userService;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorizes the full request, checks for SSL and validates the current user
|
||||
/// </summary>
|
||||
/// <param name="throwExceptions">set to true if you want exceptions to be thrown if failed</param>
|
||||
/// <returns></returns>
|
||||
internal ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false)
|
||||
{
|
||||
// check for secure connection
|
||||
if (_globalSettings.UseHttps && _httpContext.Request.IsSecureConnection == false)
|
||||
{
|
||||
if (throwExceptions) throw new SecurityException("This installation requires a secure connection (via SSL). Please update the URL to include https://");
|
||||
return ValidateRequestAttempt.FailedNoSsl;
|
||||
}
|
||||
return ValidateCurrentUser(throwExceptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified user as access to the app
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
internal virtual bool UserHasSectionAccess(string section, IUser user)
|
||||
{
|
||||
return user.HasSectionAccess(section);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified user by username as access to the app
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
internal bool UserHasSectionAccess(string section, string username)
|
||||
{
|
||||
var user = _userService.GetByUsername(username);
|
||||
if (user == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return user.HasSectionAccess(section);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a back office user is logged in
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsAuthenticated()
|
||||
{
|
||||
return _httpContext.User.Identity.IsAuthenticated && _httpContext.GetCurrentIdentity(false) != null;
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
_httpContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true or false if the currently logged in member is authorized based on the parameters provided
|
||||
/// </summary>
|
||||
/// <param name="allowAll"></param>
|
||||
/// <param name="allowTypes"></param>
|
||||
/// <param name="allowGroups"></param>
|
||||
/// <param name="allowMembers"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use MembershipHelper.IsMemberAuthorized instead")]
|
||||
public bool IsMemberAuthorized(
|
||||
bool allowAll = false,
|
||||
IEnumerable<string> allowTypes = null,
|
||||
IEnumerable<string> allowGroups = null,
|
||||
IEnumerable<int> allowMembers = null)
|
||||
{
|
||||
if (Current.UmbracoContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var helper = Current.Container.GetInstance<MembershipHelper>();
|
||||
return helper.IsMemberAuthorized(allowAll, allowTypes, allowGroups, allowMembers);
|
||||
}
|
||||
|
||||
private IUser _currentUser;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current user.
|
||||
/// </summary>
|
||||
/// <value>The current user.</value>
|
||||
public virtual IUser CurrentUser
|
||||
{
|
||||
get
|
||||
{
|
||||
//only load it once per instance! (but make sure groups are loaded)
|
||||
if (_currentUser == null)
|
||||
{
|
||||
var id = GetUserId();
|
||||
_currentUser = id ? _userService.GetUserById(id.Result) : null;
|
||||
}
|
||||
|
||||
return _currentUser;
|
||||
}
|
||||
}
|
||||
|
||||
private BackOfficeSignInManager _signInManager;
|
||||
private BackOfficeSignInManager SignInManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_signInManager == null)
|
||||
{
|
||||
var mgr = _httpContext.GetOwinContext().Get<BackOfficeSignInManager>();
|
||||
if (mgr == null)
|
||||
{
|
||||
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeSignInManager) + " from the " + typeof(IOwinContext));
|
||||
}
|
||||
_signInManager = mgr;
|
||||
}
|
||||
return _signInManager;
|
||||
}
|
||||
}
|
||||
|
||||
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
|
||||
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager
|
||||
=> _userManager ?? (_userManager = _httpContext.GetOwinContext().GetBackOfficeUserManager());
|
||||
|
||||
/// <summary>
|
||||
/// Logs a user in.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user Id</param>
|
||||
/// <returns>returns the number of seconds until their session times out</returns>
|
||||
public virtual double PerformLogin(int userId)
|
||||
{
|
||||
var owinCtx = _httpContext.GetOwinContext();
|
||||
//ensure it's done for owin too
|
||||
owinCtx.Authentication.SignOut(Constants.Security.BackOfficeExternalAuthenticationType);
|
||||
|
||||
var user = UserManager.FindByIdAsync(userId).Result;
|
||||
|
||||
SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false).Wait();
|
||||
|
||||
_httpContext.SetPrincipalForRequest(owinCtx.Request.User);
|
||||
|
||||
return TimeSpan.FromMinutes(_globalSettings.TimeOutInMinutes).TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current login for the currently logged in user
|
||||
/// </summary>
|
||||
public virtual void ClearCurrentLogin()
|
||||
{
|
||||
_httpContext.UmbracoLogout();
|
||||
_httpContext.GetOwinContext().Authentication.SignOut(
|
||||
Core.Constants.Security.BackOfficeAuthenticationType,
|
||||
Core.Constants.Security.BackOfficeExternalAuthenticationType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renews the user's login ticket
|
||||
/// </summary>
|
||||
public virtual void RenewLoginTimeout()
|
||||
{
|
||||
_httpContext.RenewUmbracoAuthTicket();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates credentials for a back office user
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This uses ASP.NET Identity to perform the validation
|
||||
/// </remarks>
|
||||
public virtual bool ValidateBackOfficeCredentials(string username, string password)
|
||||
{
|
||||
//find the user by username
|
||||
var user = UserManager.FindByNameAsync(username).Result;
|
||||
return user != null && UserManager.CheckPasswordAsync(user, password).Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current user to see if they have access to the specified app
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
internal bool ValidateUserApp(string app)
|
||||
{
|
||||
//if it is empty, don't validate
|
||||
if (app.IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return CurrentUser.AllowedSections.Any(uApp => uApp.InvariantEquals(app));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current user's id.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Attempt<int> GetUserId()
|
||||
{
|
||||
var identity = _httpContext.GetCurrentIdentity(false);
|
||||
return identity == null ? Attempt.Fail<int>() : Attempt.Succeed(Convert.ToInt32(identity.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current user's unique session id - used to mitigate csrf attacks or any other reason to validate a request
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GetSessionId()
|
||||
{
|
||||
var identity = _httpContext.GetCurrentIdentity(false);
|
||||
return identity?.SessionId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the currently logged in user and ensures they are not timed out
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool ValidateCurrentUser()
|
||||
{
|
||||
return ValidateCurrentUser(false, true) == ValidateRequestAttempt.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current user assigned to the request and ensures the stored user data is valid
|
||||
/// </summary>
|
||||
/// <param name="throwExceptions">set to true if you want exceptions to be thrown if failed</param>
|
||||
/// <param name="requiresApproval">If true requires that the user is approved to be validated</param>
|
||||
/// <returns></returns>
|
||||
public virtual ValidateRequestAttempt ValidateCurrentUser(bool throwExceptions, bool requiresApproval = true)
|
||||
{
|
||||
//This will first check if the current user is already authenticated - which should be the case in nearly all circumstances
|
||||
// since the authentication happens in the Module, that authentication also checks the ticket expiry. We don't
|
||||
// need to check it a second time because that requires another decryption phase and nothing can tamper with it during the request.
|
||||
|
||||
if (IsAuthenticated() == false)
|
||||
{
|
||||
//There is no user
|
||||
if (throwExceptions) throw new InvalidOperationException("The user has no umbraco contextid - try logging in");
|
||||
return ValidateRequestAttempt.FailedNoContextId;
|
||||
}
|
||||
|
||||
var user = CurrentUser;
|
||||
|
||||
// Check for console access
|
||||
if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContext)))
|
||||
{
|
||||
if (throwExceptions) throw new ArgumentException("You have no priviledges to the umbraco console. Please contact your administrator");
|
||||
return ValidateRequestAttempt.FailedNoPrivileges;
|
||||
}
|
||||
return ValidateRequestAttempt.Success;
|
||||
|
||||
}
|
||||
|
||||
private static bool RequestIsInUmbracoApplication(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower(), StringComparison.Ordinal) > -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorizes the full request, checks for SSL and validates the current user
|
||||
/// </summary>
|
||||
/// <param name="throwExceptions">set to true if you want exceptions to be thrown if failed</param>
|
||||
/// <returns></returns>
|
||||
internal ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false)
|
||||
{
|
||||
// check for secure connection
|
||||
if (_globalSettings.UseHttps && _httpContext.Request.IsSecureConnection == false)
|
||||
{
|
||||
if (throwExceptions) throw new SecurityException("This installation requires a secure connection (via SSL). Please update the URL to include https://");
|
||||
return ValidateRequestAttempt.FailedNoSsl;
|
||||
}
|
||||
return ValidateCurrentUser(throwExceptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified user as access to the app
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
internal virtual bool UserHasSectionAccess(string section, IUser user)
|
||||
{
|
||||
return user.HasSectionAccess(section);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified user by username as access to the app
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
internal bool UserHasSectionAccess(string section, string username)
|
||||
{
|
||||
var user = _userService.GetByUsername(username);
|
||||
if (user == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return user.HasSectionAccess(section);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a back office user is logged in
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsAuthenticated()
|
||||
{
|
||||
return _httpContext.User.Identity.IsAuthenticated && _httpContext.GetCurrentIdentity(false) != null;
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
_httpContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user