Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/align-infrastructure-namespaces

# Conflicts:
#	src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs
#	src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs
#	src/Umbraco.Infrastructure/PropertyEditors/PropertyEditorsComponent.cs
#	src/Umbraco.Infrastructure/Security/BackOfficeClaimsPrincipalFactory.cs
#	src/Umbraco.Infrastructure/Security/IBackOfficeUserManager.cs
#	src/Umbraco.Infrastructure/Security/IUmbracoUserManager.cs
#	src/Umbraco.Infrastructure/Security/SignOutAuditEventArgs.cs
#	src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs
#	src/Umbraco.Infrastructure/Security/UserInviteEventArgs.cs
#	src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs
#	src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackOffice/BackOfficeLookupNormalizerTests.cs
#	src/Umbraco.Web.BackOffice/Controllers/MemberController.cs
#	src/Umbraco.Web/Security/IBackOfficeUserPasswordChecker.cs
#	src/Umbraco.Web/Security/Providers/MembersRoleProvider.cs
This commit is contained in:
Mole
2021-02-23 08:51:09 +01:00
64 changed files with 2799 additions and 485 deletions

View File

@@ -1,7 +1,7 @@
namespace Umbraco.Cms.Core.Configuration
{
/// <summary>
/// The password configuration for back office users
/// The password configuration for members
/// </summary>
public class MemberPasswordConfiguration : PasswordConfiguration, IMemberPasswordConfiguration
{

View File

@@ -41,6 +41,9 @@ namespace Umbraco.Cms.Core
public const string EmptyPasswordPrefix = "___UIDEMPTYPWORD__";
public const string DefaultMemberTypeAlias = "Member";
/// <summary>
/// The prefix used for external identity providers for their authentication type
/// </summary>

View File

@@ -0,0 +1,33 @@
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
namespace Umbraco.Core.Models.Mapping
{
/// <inheritdoc />
public class MemberMapDefinition : IMapDefinition
{
/// <inheritdoc />
public void DefineMaps(UmbracoMapper mapper) => mapper.Define<MemberSave, IMember>(Map);
private static void Map(MemberSave source, IMember target, MapperContext context)
{
target.IsApproved = source.IsApproved;
target.Name = source.Name;
target.Email = source.Email;
target.Key = source.Key;
target.Username = source.Username;
target.Comments = source.Comments;
target.CreateDate = source.CreateDate;
target.UpdateDate = source.UpdateDate;
target.Email = source.Email;
// TODO: ensure all properties are mapped as required
//target.Id = source.Id;
//target.ParentId = -1;
//target.Path = "-1," + source.Id;
//TODO: add groups as required
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Options;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
@@ -19,8 +19,11 @@ namespace Umbraco.Cms.Core.Models
private string _email;
private string _rawPasswordValue;
private string _passwordConfig;
private DateTime? _emailConfirmedDate;
private string _securityStamp;
/// <summary>
/// Initializes a new instance of the <see cref="Member"/> class.
/// Constructor for creating an empty Member object
/// </summary>
/// <param name="contentType">ContentType for the current Content object</param>
@@ -29,13 +32,14 @@ namespace Umbraco.Cms.Core.Models
{
IsApproved = true;
//this cannot be null but can be empty
// this cannot be null but can be empty
_rawPasswordValue = "";
_email = "";
_username = "";
}
/// <summary>
/// Initializes a new instance of the <see cref="Member"/> class.
/// Constructor for creating a Member object
/// </summary>
/// <param name="name">Name of the content</param>
@@ -43,18 +47,21 @@ namespace Umbraco.Cms.Core.Models
public Member(string name, IMemberType contentType)
: base(name, -1, contentType, new PropertyCollection())
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
if (name == null)
throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
IsApproved = true;
//this cannot be null but can be empty
// this cannot be null but can be empty
_rawPasswordValue = "";
_email = "";
_username = "";
}
/// <summary>
/// Initializes a new instance of the <see cref="Member"/> class.
/// Constructor for creating a Member object
/// </summary>
/// <param name="name"></param>
@@ -64,22 +71,29 @@ namespace Umbraco.Cms.Core.Models
public Member(string name, string email, string username, IMemberType contentType, bool isApproved = true)
: base(name, -1, contentType, new PropertyCollection())
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
if (email == null) throw new ArgumentNullException(nameof(email));
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(email));
if (username == null) throw new ArgumentNullException(nameof(username));
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(username));
if (name == null)
throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
if (email == null)
throw new ArgumentNullException(nameof(email));
if (string.IsNullOrWhiteSpace(email))
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(email));
if (username == null)
throw new ArgumentNullException(nameof(username));
if (string.IsNullOrWhiteSpace(username))
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(username));
_email = email;
_username = username;
IsApproved = isApproved;
//this cannot be null but can be empty
// this cannot be null but can be empty
_rawPasswordValue = "";
}
/// <summary>
/// Initializes a new instance of the <see cref="Member"/> class.
/// Constructor for creating a Member object
/// </summary>
/// <param name="name"></param>
@@ -99,6 +113,7 @@ namespace Umbraco.Cms.Core.Models
}
/// <summary>
/// Initializes a new instance of the <see cref="Member"/> class.
/// Constructor for creating a Member object
/// </summary>
/// <param name="name"></param>
@@ -138,6 +153,13 @@ namespace Umbraco.Cms.Core.Models
set => SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email));
}
[DataMember]
public DateTime? EmailConfirmedDate
{
get => _emailConfirmedDate;
set => SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, nameof(EmailConfirmedDate));
}
/// <summary>
/// Gets or sets the raw password value
/// </summary>
@@ -190,7 +212,8 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.Comments, nameof(Comments), default(string));
if (a.Success == false) return a.Result;
if (a.Success == false)
return a.Result;
return Properties[Constants.Conventions.Member.Comments].GetValue() == null
? string.Empty
@@ -200,7 +223,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.Comments,
nameof(Comments)) == false) return;
nameof(Comments)) == false)
return;
Properties[Constants.Conventions.Member.Comments].SetValue(value);
}
@@ -221,8 +245,10 @@ namespace Umbraco.Cms.Core.Models
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsApproved, nameof(IsApproved),
//This is the default value if the prop is not found
true);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsApproved].GetValue() == null) return true;
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.IsApproved].GetValue() == null)
return true;
var tryConvert = Properties[Constants.Conventions.Member.IsApproved].GetValue().TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -235,7 +261,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.IsApproved,
nameof(IsApproved)) == false) return;
nameof(IsApproved)) == false)
return;
Properties[Constants.Conventions.Member.IsApproved].SetValue(value);
}
@@ -254,8 +281,10 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, nameof(IsLockedOut), false);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsLockedOut].GetValue() == null) return false;
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.IsLockedOut].GetValue() == null)
return false;
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].GetValue().TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -268,7 +297,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.IsLockedOut,
nameof(IsLockedOut)) == false) return;
nameof(IsLockedOut)) == false)
return;
Properties[Constants.Conventions.Member.IsLockedOut].SetValue(value);
}
@@ -287,8 +317,10 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, nameof(LastLoginDate), default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLoginDate].GetValue() == null) return default(DateTime);
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.LastLoginDate].GetValue() == null)
return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].GetValue().TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -301,7 +333,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastLoginDate,
nameof(LastLoginDate)) == false) return;
nameof(LastLoginDate)) == false)
return;
Properties[Constants.Conventions.Member.LastLoginDate].SetValue(value);
}
@@ -320,8 +353,10 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, nameof(LastPasswordChangeDate), default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].GetValue() == null) return default(DateTime);
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].GetValue() == null)
return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].GetValue().TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -334,7 +369,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastPasswordChangeDate,
nameof(LastPasswordChangeDate)) == false) return;
nameof(LastPasswordChangeDate)) == false)
return;
Properties[Constants.Conventions.Member.LastPasswordChangeDate].SetValue(value);
}
@@ -353,8 +389,10 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, nameof(LastLockoutDate), default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLockoutDate].GetValue() == null) return default(DateTime);
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.LastLockoutDate].GetValue() == null)
return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].GetValue().TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -367,7 +405,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastLockoutDate,
nameof(LastLockoutDate)) == false) return;
nameof(LastLockoutDate)) == false)
return;
Properties[Constants.Conventions.Member.LastLockoutDate].SetValue(value);
}
@@ -387,8 +426,10 @@ namespace Umbraco.Cms.Core.Models
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, nameof(FailedPasswordAttempts), 0);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].GetValue() == null) return default(int);
if (a.Success == false)
return a.Result;
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].GetValue() == null)
return default(int);
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].GetValue().TryConvertTo<int>();
if (tryConvert.Success)
{
@@ -401,7 +442,8 @@ namespace Umbraco.Cms.Core.Models
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.FailedPasswordAttempts,
nameof(FailedPasswordAttempts)) == false) return;
nameof(FailedPasswordAttempts)) == false)
return;
Properties[Constants.Conventions.Member.FailedPasswordAttempts].SetValue(value);
}
@@ -413,6 +455,17 @@ namespace Umbraco.Cms.Core.Models
[DataMember]
public virtual string ContentTypeAlias => ContentType.Alias;
/// <summary>
/// The security stamp used by ASP.Net identity
/// </summary>
[IgnoreDataMember]
public string SecurityStamp
{
get => _securityStamp;
set => SetPropertyValueAndDetectChanges(value, ref _securityStamp, nameof(SecurityStamp));
}
/// <summary>
/// Internal/Experimental - only used for mapping queries.
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Umbraco.Cms.Core.Models.Entities;
namespace Umbraco.Cms.Core.Models.Membership
@@ -10,6 +10,7 @@ namespace Umbraco.Cms.Core.Models.Membership
{
string Username { get; set; }
string Email { get; set; }
DateTime? EmailConfirmedDate { get; set; }
/// <summary>
/// Gets or sets the raw password value
@@ -38,6 +39,11 @@ namespace Umbraco.Cms.Core.Models.Membership
/// </remarks>
int FailedPasswordAttempts { get; set; }
/// <summary>
/// Gets or sets the security stamp used by ASP.NET Identity
/// </summary>
string SecurityStamp { get; set; }
//object ProfileId { get; set; }
//IEnumerable<object> Groups { get; set; }
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Umbraco.Cms.Core.Models.Entities;
@@ -19,7 +19,6 @@ namespace Umbraco.Cms.Core.Models.Membership
int[] StartMediaIds { get; set; }
string Language { get; set; }
DateTime? EmailConfirmedDate { get; set; }
DateTime? InvitedDate { get; set; }
/// <summary>
@@ -38,11 +37,6 @@ namespace Umbraco.Cms.Core.Models.Membership
/// </summary>
IProfile ProfileData { get; }
/// <summary>
/// The security stamp used by ASP.Net identity
/// </summary>
string SecurityStamp { get; set; }
/// <summary>
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>

View File

@@ -6,7 +6,6 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Security
{
/// <summary>
/// A custom user identity for the Umbraco backoffice
/// </summary>

View File

@@ -1,29 +1,47 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Querying;
namespace Umbraco.Cms.Core.Services
{
public interface IMembershipRoleService<out T>
public interface IMembershipRoleService<out T>
where T : class, IMembershipUser
{
void AddRole(string roleName);
IEnumerable<string> GetAllRoles();
IEnumerable<IMemberGroup> GetAllRoles();
IEnumerable<string> GetAllRoles(int memberId);
IEnumerable<string> GetAllRoles(string username);
IEnumerable<int> GetAllRolesIds();
IEnumerable<int> GetAllRolesIds(int memberId);
IEnumerable<int> GetAllRolesIds(string username);
IEnumerable<T> GetMembersInRole(string roleName);
IEnumerable<T> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
bool DeleteRole(string roleName, bool throwIfBeingUsed);
void AssignRole(string username, string roleName);
void AssignRoles(string[] usernames, string[] roleNames);
void DissociateRole(string username, string roleName);
void DissociateRoles(string[] usernames, string[] roleNames);
void AssignRole(int memberId, string roleName);
void AssignRoles(int[] memberIds, string[] roleNames);
void DissociateRole(int memberId, string roleName);
void DissociateRoles(int[] memberIds, string[] roleNames);
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>