Files
Umbraco-CMS/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs
2020-05-28 23:24:32 +10:00

155 lines
7.0 KiB
C#

using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Models.Membership;
using Umbraco.Web.Composing;
using System;
using Umbraco.Net;
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>
{
public MembersMembershipProvider()
: this(Current.Services.MemberService, Current.Services.MemberTypeService, Current.UmbracoVersion, Current.HostingEnvironment, Current.IpResolver)
{ }
public MembersMembershipProvider(IMembershipMemberService<IMember> memberService, IMemberTypeService memberTypeService, IUmbracoVersion umbracoVersion, IHostingEnvironment hostingEnvironment, IIpResolver ipResolver)
: base(memberService, umbracoVersion, hostingEnvironment, ipResolver)
{
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;
_memberTypeService = memberTypeService;
}
private readonly IMemberTypeService _memberTypeService;
private string _defaultMemberTypeAlias = "Member";
private volatile bool _hasDefaultMember;
private static readonly object Locker = new object();
public override string ProviderName => "MembersMembershipProvider";
protected override MembershipUser ConvertToMembershipUser(IMember entity)
{
return entity.AsConcreteMembershipUser(Name);
}
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 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;
}
// these need to be lazy else we get a stack overflow since we cannot access Membership.HashAlgorithmType without initializing the providers
_passwordConfig = new Lazy<IPasswordConfiguration>(() => new MembershipProviderPasswordConfiguration(
MinRequiredPasswordLength,
MinRequiredNonAlphanumericCharacters > 0,
false, false, false, UseLegacyEncoding,
CustomHashAlgorithmType.IsNullOrWhiteSpace() ? Membership.HashAlgorithmType : CustomHashAlgorithmType,
MaxInvalidPasswordAttempts));
_passwordSecurity = new Lazy<LegacyPasswordSecurity>(() => new LegacyPasswordSecurity(PasswordConfiguration));
}
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;
}
}
private Lazy<LegacyPasswordSecurity> _passwordSecurity;
private Lazy<IPasswordConfiguration> _passwordConfig;
public override LegacyPasswordSecurity PasswordSecurity => _passwordSecurity.Value;
public IPasswordConfiguration PasswordConfiguration => _passwordConfig.Value;
private class MembershipProviderPasswordConfiguration : IPasswordConfiguration
{
public MembershipProviderPasswordConfiguration(int requiredLength, bool requireNonLetterOrDigit, bool requireDigit, bool requireLowercase, bool requireUppercase, bool useLegacyEncoding, string hashAlgorithmType, int maxFailedAccessAttemptsBeforeLockout)
{
RequiredLength = requiredLength;
RequireNonLetterOrDigit = requireNonLetterOrDigit;
RequireDigit = requireDigit;
RequireLowercase = requireLowercase;
RequireUppercase = requireUppercase;
UseLegacyEncoding = useLegacyEncoding;
HashAlgorithmType = hashAlgorithmType ?? throw new ArgumentNullException(nameof(hashAlgorithmType));
MaxFailedAccessAttemptsBeforeLockout = maxFailedAccessAttemptsBeforeLockout;
}
public int RequiredLength { get; }
public bool RequireNonLetterOrDigit { get; }
public bool RequireDigit { get; }
public bool RequireLowercase { get; }
public bool RequireUppercase { get; }
public bool UseLegacyEncoding { get; }
public string HashAlgorithmType { get; }
public int MaxFailedAccessAttemptsBeforeLockout { get; }
}
}
}