Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/core-cannot-use-system-web
# Conflicts: # src/Umbraco.Core/Runtime/CoreInitialComposer.cs # src/Umbraco.Core/StringExtensions.cs # src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs # src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs # src/Umbraco.Tests/Services/MemberServiceTests.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/BackOfficeUserManager.cs # src/Umbraco.Web/Security/MembershipProviderBase.cs # src/Umbraco.Web/Security/MembershipProviderExtensions.cs # src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs # src/Umbraco.Web/Security/UmbracoMembershipProviderBase.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
This commit is contained in:
@@ -25,6 +25,9 @@ namespace Umbraco.Core
|
||||
public static IUmbracoSettingsSection Settings(this Configs configs)
|
||||
=> configs.GetConfig<IUmbracoSettingsSection>();
|
||||
|
||||
public static IUserPasswordConfiguration UserPasswordConfig(this Configs configs)
|
||||
=> configs.GetConfig<IUserPasswordConfiguration>();
|
||||
|
||||
public static IHealthChecks HealthChecks(this Configs configs)
|
||||
=> configs.GetConfig<IHealthChecks>();
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Password configuration
|
||||
/// </summary>
|
||||
public interface IPasswordConfiguration
|
||||
{
|
||||
int RequiredLength { get; }
|
||||
bool RequireNonLetterOrDigit { get; }
|
||||
bool RequireDigit { get; }
|
||||
bool RequireLowercase { get; }
|
||||
bool RequireUppercase { get; }
|
||||
|
||||
bool UseLegacyEncoding { get; }
|
||||
string HashAlgorithmType { get; }
|
||||
|
||||
// TODO: This doesn't really belong here
|
||||
int MaxFailedAccessAttemptsBeforeLockout { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// The password configuration for back office users
|
||||
/// </summary>
|
||||
public interface IUserPasswordConfiguration : IPasswordConfiguration
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -137,21 +137,7 @@ namespace Umbraco.Core
|
||||
public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
|
||||
|
||||
public static readonly string UmbracoRoleProviderName = "UmbracoRoleProvider";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for a Members Password Question
|
||||
/// </summary>
|
||||
public const string PasswordQuestion = "umbracoMemberPasswordRetrievalQuestion";
|
||||
|
||||
public const string PasswordQuestionLabel = "Password Question";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for Members Password Answer
|
||||
/// </summary>
|
||||
public const string PasswordAnswer = "umbracoMemberPasswordRetrievalAnswer";
|
||||
|
||||
public const string PasswordAnswerLabel = "Password Answer";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Comments on a Member
|
||||
/// </summary>
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -251,7 +251,7 @@ namespace Umbraco.Core
|
||||
var builder = new StringBuilder();
|
||||
foreach (var i in d)
|
||||
{
|
||||
builder.Append(String.Format("{0}={1}&", HttpUtility.UrlEncode(i.Key), i.Value == null ? string.Empty : HttpUtility.UrlEncode(i.Value.ToString())));
|
||||
builder.Append(String.Format("{0}={1}&", WebUtility.UrlEncode(i.Key), i.Value == null ? string.Empty : WebUtility.UrlEncode(i.Value.ToString())));
|
||||
}
|
||||
return builder.ToString().TrimEnd('&');
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models
|
||||
/// <para>A set of cultures can be either all cultures (including the invariant culture), or
|
||||
/// the invariant culture, or a specific culture.</para>
|
||||
/// </remarks>
|
||||
internal class CultureImpact
|
||||
public sealed class CultureImpact
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility method to return the culture used for invariant property errors based on what cultures are being actively saved,
|
||||
@@ -8,7 +8,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// </summary>
|
||||
public interface IMembershipUser : IEntity
|
||||
{
|
||||
object ProviderUserKey { get; set; }
|
||||
string Username { get; set; }
|
||||
string Email { get; set; }
|
||||
|
||||
@@ -17,13 +16,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// </summary>
|
||||
string RawPasswordValue { get; set; }
|
||||
|
||||
string PasswordQuestion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw password answer value
|
||||
/// </summary>
|
||||
string RawPasswordAnswerValue { get; set; }
|
||||
|
||||
string Comments { get; set; }
|
||||
bool IsApproved { get; set; }
|
||||
bool IsLockedOut { get; set; }
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
public enum MemberCountType
|
||||
{
|
||||
All,
|
||||
Online,
|
||||
LockedOut,
|
||||
Approved
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// How membership is implemented in the current install.
|
||||
/// </summary>
|
||||
public enum MembershipScenario
|
||||
{
|
||||
//TODO: This will become obsolete when we get asp.net identity members in place
|
||||
|
||||
/// <summary>
|
||||
/// The member is based on the native Umbraco members (IMember + Umbraco membership provider)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This supports custom member properties
|
||||
/// </remarks>
|
||||
NativeUmbraco,
|
||||
|
||||
/// <summary>
|
||||
/// The member is based on a custom member provider but it is linked to an IMember
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This supports custom member properties (but that is not enabled yet)
|
||||
/// </remarks>
|
||||
CustomProviderWithUmbracoLink,
|
||||
|
||||
/// <summary>
|
||||
/// The member is based purely on a custom member provider and is not linked to umbraco data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not support custom member properties.
|
||||
/// </remarks>
|
||||
StandaloneCustomProvider
|
||||
}
|
||||
}
|
||||
@@ -102,16 +102,15 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
// TODO: this list somehow also exists in constants, see memberTypeRepository => remove duplicate!
|
||||
private static readonly Dictionary<string, int> BuiltinMemberProperties = new Dictionary<string, int>
|
||||
{
|
||||
{ "Email", Constants.DataTypes.Textbox },
|
||||
{ "Username", Constants.DataTypes.Textbox },
|
||||
{ "PasswordQuestion", Constants.DataTypes.Textbox },
|
||||
{ "Comments", Constants.DataTypes.Textbox },
|
||||
{ "IsApproved", Constants.DataTypes.Boolean },
|
||||
{ "IsLockedOut", Constants.DataTypes.Boolean },
|
||||
{ "LastLockoutDate", Constants.DataTypes.DateTime },
|
||||
{ "CreateDate", Constants.DataTypes.DateTime },
|
||||
{ "LastLoginDate", Constants.DataTypes.DateTime },
|
||||
{ "LastPasswordChangeDate", Constants.DataTypes.DateTime },
|
||||
{ nameof(IMember.Email), Constants.DataTypes.Textbox },
|
||||
{ nameof(IMember.Username), Constants.DataTypes.Textbox },
|
||||
{ nameof(IMember.Comments), Constants.DataTypes.Textbox },
|
||||
{ nameof(IMember.IsApproved), Constants.DataTypes.Boolean },
|
||||
{ nameof(IMember.IsLockedOut), Constants.DataTypes.Boolean },
|
||||
{ nameof(IMember.LastLockoutDate), Constants.DataTypes.DateTime },
|
||||
{ nameof(IMember.CreateDate), Constants.DataTypes.DateTime },
|
||||
{ nameof(IMember.LastLoginDate), Constants.DataTypes.DateTime },
|
||||
{ nameof(IMember.LastPasswordChangeDate), Constants.DataTypes.DateTime },
|
||||
};
|
||||
|
||||
#region Content type
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a password
|
||||
/// </summary>
|
||||
public interface IPasswordGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a password
|
||||
/// </summary>
|
||||
/// <param name="passwordConfiguration"></param>
|
||||
/// <returns></returns>
|
||||
string GeneratePassword(IPasswordConfiguration passwordConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a password
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This uses logic copied from the old MembershipProvider.GeneratePassword logic
|
||||
/// </remarks>
|
||||
public class PasswordGenerator : IPasswordGenerator
|
||||
{
|
||||
public string GeneratePassword(IPasswordConfiguration passwordConfiguration)
|
||||
{
|
||||
var password = PasswordStore.GeneratePassword(
|
||||
passwordConfiguration.RequiredLength,
|
||||
passwordConfiguration.RequireNonLetterOrDigit ? 2 : 0);
|
||||
|
||||
var random = new Random();
|
||||
|
||||
var passwordChars = password.ToCharArray();
|
||||
|
||||
if (passwordConfiguration.RequireDigit && passwordChars.ContainsAny(Enumerable.Range(48, 58).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(48, 58)); // 0-9
|
||||
|
||||
if (passwordConfiguration.RequireLowercase && passwordChars.ContainsAny(Enumerable.Range(97, 123).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(97, 123)); // a-z
|
||||
|
||||
if (passwordConfiguration.RequireUppercase && passwordChars.ContainsAny(Enumerable.Range(65, 91).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(65, 91)); // A-Z
|
||||
|
||||
if (passwordConfiguration.RequireNonLetterOrDigit && passwordChars.ContainsAny(Enumerable.Range(33, 48).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(33, 48)); // symbols !"#$%&'()*+,-./
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal class copied from ASP.NET Framework MembershipProvider
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://stackoverflow.com/a/39855417/694494 + https://github.com/Microsoft/referencesource/blob/master/System.Web/Security/Membership.cs
|
||||
/// </remarks>
|
||||
private static class PasswordStore
|
||||
{
|
||||
private static readonly char[] Punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray();
|
||||
private static readonly char[] StartingChars = new char[] { '<', '&' };
|
||||
/// <summary>Generates a random password of the specified length.</summary>
|
||||
/// <returns>A random password of the specified length.</returns>
|
||||
/// <param name="length">The number of characters in the generated password. The length must be between 1 and 128 characters. </param>
|
||||
/// <param name="numberOfNonAlphanumericCharacters">The minimum number of non-alphanumeric characters (such as @, #, !, %, &, and so on) in the generated password.</param>
|
||||
/// <exception cref="T:System.ArgumentException">
|
||||
/// <paramref name="length" /> is less than 1 or greater than 128 -or-<paramref name="numberOfNonAlphanumericCharacters" /> is less than 0 or greater than <paramref name="length" />. </exception>
|
||||
public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
|
||||
{
|
||||
if (length < 1 || length > 128)
|
||||
throw new ArgumentException("password length incorrect", nameof(length));
|
||||
if (numberOfNonAlphanumericCharacters > length || numberOfNonAlphanumericCharacters < 0)
|
||||
throw new ArgumentException("min required non alphanumeric characters incorrect", nameof(numberOfNonAlphanumericCharacters));
|
||||
string s;
|
||||
int matchIndex;
|
||||
do
|
||||
{
|
||||
var data = new byte[length];
|
||||
var chArray = new char[length];
|
||||
var num1 = 0;
|
||||
new RNGCryptoServiceProvider().GetBytes(data);
|
||||
for (var index = 0; index < length; ++index)
|
||||
{
|
||||
var num2 = (int)data[index] % 87;
|
||||
if (num2 < 10)
|
||||
chArray[index] = (char)(48 + num2);
|
||||
else if (num2 < 36)
|
||||
chArray[index] = (char)(65 + num2 - 10);
|
||||
else if (num2 < 62)
|
||||
{
|
||||
chArray[index] = (char)(97 + num2 - 36);
|
||||
}
|
||||
else
|
||||
{
|
||||
chArray[index] = Punctuations[num2 - 62];
|
||||
++num1;
|
||||
}
|
||||
}
|
||||
if (num1 < numberOfNonAlphanumericCharacters)
|
||||
{
|
||||
var random = new Random();
|
||||
for (var index1 = 0; index1 < numberOfNonAlphanumericCharacters - num1; ++index1)
|
||||
{
|
||||
int index2;
|
||||
do
|
||||
{
|
||||
index2 = random.Next(0, length);
|
||||
}
|
||||
while (!char.IsLetterOrDigit(chArray[index2]));
|
||||
chArray[index2] = Punctuations[random.Next(0, Punctuations.Length)];
|
||||
}
|
||||
}
|
||||
s = new string(chArray);
|
||||
}
|
||||
while (IsDangerousString(s, out matchIndex));
|
||||
return s;
|
||||
}
|
||||
|
||||
private static bool IsDangerousString(string s, out int matchIndex)
|
||||
{
|
||||
//bool inComment = false;
|
||||
matchIndex = 0;
|
||||
|
||||
for (var i = 0; ;)
|
||||
{
|
||||
|
||||
// Look for the start of one of our patterns
|
||||
var n = s.IndexOfAny(StartingChars, i);
|
||||
|
||||
// If not found, the string is safe
|
||||
if (n < 0) return false;
|
||||
|
||||
// If it's the last char, it's safe
|
||||
if (n == s.Length - 1) return false;
|
||||
|
||||
matchIndex = n;
|
||||
|
||||
switch (s[n])
|
||||
{
|
||||
case '<':
|
||||
// If the < is followed by a letter or '!', it's unsafe (looks like a tag or HTML comment)
|
||||
if (IsAtoZ(s[n + 1]) || s[n + 1] == '!' || s[n + 1] == '/' || s[n + 1] == '?') return true;
|
||||
break;
|
||||
case '&':
|
||||
// If the & is followed by a #, it's unsafe (e.g. S)
|
||||
if (s[n + 1] == '#') return true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Continue searching
|
||||
i = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAtoZ(char c)
|
||||
{
|
||||
if ((int)c >= 97 && (int)c <= 122)
|
||||
return true;
|
||||
if ((int)c >= 65)
|
||||
return (int)c <= 90;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Services.Changes
|
||||
|
||||
public TItem Item { get; }
|
||||
|
||||
public ContentTypeChangeTypes ChangeTypes { get; internal set; }
|
||||
public ContentTypeChangeTypes ChangeTypes { get; set; }
|
||||
|
||||
public EventArgs ToEventArgs(ContentTypeChange<TItem> change)
|
||||
{
|
||||
-18
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Net.Http;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
@@ -95,20 +91,6 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IMember"/></returns>
|
||||
IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType);
|
||||
|
||||
/// <summary>
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method which can be
|
||||
/// used during Member creation.
|
||||
/// </summary>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// this will not work for updating members in most cases (depends on your membership provider settings)
|
||||
///
|
||||
/// It is preferred to use the membership APIs for working with passwords, in the near future this method will be obsoleted
|
||||
/// and the ASP.NET Identity APIs should be used instead.
|
||||
/// </remarks>
|
||||
/// <param name="member">The Member to save the password for</param>
|
||||
/// <param name="password">The password to encrypt and save</param>
|
||||
void SavePassword(IMember member, string password);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count of Members by an optional MemberType alias
|
||||
/// </summary>
|
||||
@@ -1,11 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines part of the MemberService, which is specific to methods used by the membership provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Idea is to have this as an isolated interface so that it can be easily 'replaced' in the membership provider implementation.
|
||||
/// </remarks>
|
||||
public interface IMembershipMemberService : IMembershipMemberService<IMember>, IMembershipRoleService<IMember>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates and persists a new Member
|
||||
/// </summary>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
/// <param name="memberType"><see cref="IMemberType"/> which the Member should be based on</param>
|
||||
/// <returns><see cref="IMember"/></returns>
|
||||
IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines part of the UserService/MemberService, which is specific to methods used by the membership provider.
|
||||
/// The generic type is restricted to <see cref="IMembershipUser"/>. The implementation of this interface uses
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public interface IPropertyValidationService
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the content item's properties pass validation rules
|
||||
/// </summary>
|
||||
bool IsPropertyDataValid(IContent content, out IProperty[] invalidProperties, CultureImpact impact);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property has valid values.
|
||||
/// </summary>
|
||||
bool IsPropertyValid(IProperty property, string culture = "*", string segment = "*");
|
||||
}
|
||||
}
|
||||
+1
-20
@@ -69,24 +69,7 @@ namespace Umbraco.Core.Services
|
||||
.ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value);
|
||||
}
|
||||
|
||||
private static ICultureDictionary _cultureDictionary;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: We need to refactor how we work with ICultureDictionary - this is supposed to be the 'fast' way to
|
||||
/// do readonly access to the Dictionary without using the ILocalizationService. See TODO Notes in `DefaultCultureDictionary`
|
||||
/// Also NOTE that the ICultureDictionary is based on the ILocalizationService not the ILocalizedTextService (which is used
|
||||
/// only for the localization files - not the dictionary)
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text)
|
||||
{
|
||||
var cultureDictionary = CultureDictionary;
|
||||
return manager.UmbracoDictionaryTranslate(text, cultureDictionary);
|
||||
}
|
||||
|
||||
private static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text, ICultureDictionary cultureDictionary)
|
||||
public static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, ICultureDictionary cultureDictionary, string text)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
@@ -105,7 +88,5 @@ namespace Umbraco.Core.Services
|
||||
return value.StartsWith("[") ? text : value;
|
||||
}
|
||||
|
||||
private static ICultureDictionary CultureDictionary
|
||||
=> _cultureDictionary ?? (_cultureDictionary = Current.CultureDictionaryFactory.CreateDictionary());
|
||||
}
|
||||
}
|
||||
-6
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
@@ -53,11 +52,6 @@ namespace Umbraco.Core.Services
|
||||
return HasAccess(entry, username, currentMemberRoles);
|
||||
}
|
||||
|
||||
public static bool HasAccess(this IPublicAccessService publicAccessService, string path, MembershipUser member, RoleProvider roleProvider)
|
||||
{
|
||||
return publicAccessService.HasAccess(path, member.UserName, roleProvider.GetRolesForUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the member with the specified username has access to the path which is also based on the passed in roles for the member
|
||||
/// </summary>
|
||||
-36
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
@@ -69,40 +68,5 @@ namespace Umbraco.Core.Services
|
||||
userService.ReplaceUserGroupPermissions(groupId, new char[] { });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a custom provider's information to an umbraco user account
|
||||
/// </summary>
|
||||
/// <param name="userService"></param>
|
||||
/// <param name="member"></param>
|
||||
/// <remarks>
|
||||
/// To maintain compatibility we have to check the login name if the provider key lookup fails but otherwise
|
||||
/// we'll store the provider user key in the login column.
|
||||
/// </remarks>
|
||||
internal static IUser CreateUserMappingForCustomProvider(this IUserService userService, MembershipUser member)
|
||||
{
|
||||
if (member == null) throw new ArgumentNullException("member");
|
||||
|
||||
|
||||
var valToLookup = member.ProviderUserKey == null ? member.UserName : member.ProviderUserKey.ToString();
|
||||
var found = userService.GetByUsername(valToLookup);
|
||||
if (found == null && member.ProviderUserKey != null)
|
||||
{
|
||||
//try by username
|
||||
found = userService.GetByUsername(member.UserName);
|
||||
}
|
||||
|
||||
if (found == null)
|
||||
{
|
||||
var user = new User(
|
||||
member.UserName,
|
||||
member.Email ?? Guid.NewGuid().ToString("N") + "@example.com", //email cannot be empty
|
||||
member.ProviderUserKey == null ? member.UserName : member.ProviderUserKey.ToString(),
|
||||
Guid.NewGuid().ToString("N")); //pass cannot be empty
|
||||
userService.Save(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,26 @@ namespace Umbraco.Core.Configuration
|
||||
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
|
||||
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
|
||||
|
||||
configs.Add<IUserPasswordConfiguration>(() => new DefaultUserPasswordConfig());
|
||||
configs.Add<ICoreDebug>(() => new CoreDebug());
|
||||
configs.Add<IConnectionStrings>(() => new ConnectionStrings());
|
||||
configs.AddCoreConfigs(_ioHelper);
|
||||
return configs;
|
||||
}
|
||||
}
|
||||
|
||||
// Default/static user password configs
|
||||
// TODO: Make this configurable somewhere - we've removed membership providers, so could be a section in the umbracosettings.config file?
|
||||
// keeping in mind that we will also be removing the members membership provider so there will be 2x the same/similar configuration
|
||||
internal class DefaultUserPasswordConfig : IUserPasswordConfiguration
|
||||
{
|
||||
public int RequiredLength => 12;
|
||||
public bool RequireNonLetterOrDigit => false;
|
||||
public bool RequireDigit => false;
|
||||
public bool RequireLowercase => false;
|
||||
public bool RequireUppercase => false;
|
||||
public bool UseLegacyEncoding => false;
|
||||
public string HashAlgorithmType => "HMACSHA256";
|
||||
public int MaxFailedAccessAttemptsBeforeLockout => 5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -27,6 +28,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
composition.RegisterUnique<IdkMap>();
|
||||
|
||||
// register the services
|
||||
composition.RegisterUnique<IPropertyValidationService, PropertyValidationService>();
|
||||
composition.RegisterUnique<IKeyValueService, KeyValueService>();
|
||||
composition.RegisterUnique<IPublicAccessService, PublicAccessService>();
|
||||
composition.RegisterUnique<IDomainService, DomainService>();
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core.Packaging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Sync;
|
||||
@@ -127,6 +128,9 @@ namespace Umbraco.Core.Composing
|
||||
public static IRuntimeState RuntimeState
|
||||
=> Factory.GetInstance<IRuntimeState>();
|
||||
|
||||
public static IPasswordGenerator PasswordGenerator
|
||||
=> Factory.GetInstance<IPasswordGenerator>();
|
||||
|
||||
public static TypeLoader TypeLoader
|
||||
=> Factory.GetInstance<TypeLoader>();
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Core
|
||||
public static void SetCultureDictionaryFactory<T>(this Composition composition)
|
||||
where T : ICultureDictionaryFactory
|
||||
{
|
||||
composition.RegisterUnique<ICultureDictionaryFactory, T>();
|
||||
composition.RegisterUnique<ICultureDictionaryFactory, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -67,24 +67,6 @@ namespace Umbraco.Core
|
||||
Name = Constants.Conventions.Member.LastPasswordChangeDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.Conventions.Member.PasswordAnswer,
|
||||
new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true,
|
||||
Constants.Conventions.Member.PasswordAnswer)
|
||||
{
|
||||
Name = Constants.Conventions.Member.PasswordAnswerLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.Conventions.Member.PasswordQuestion,
|
||||
new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true,
|
||||
Constants.Conventions.Member.PasswordQuestion)
|
||||
{
|
||||
Name = Constants.Conventions.Member.PasswordQuestionLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+13
-13
@@ -5,9 +5,8 @@ using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Dictionary
|
||||
namespace Umbraco.Core.Dictionary
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -18,28 +17,29 @@ namespace Umbraco.Web.Dictionary
|
||||
/// The ILocalizationService is the service used for interacting with this data from the database which isn't all that fast
|
||||
/// (even though there is caching involved, if there's lots of dictionary items the caching is not great)
|
||||
/// </remarks>
|
||||
public class DefaultCultureDictionary : Core.Dictionary.ICultureDictionary
|
||||
public class DefaultCultureDictionary : ICultureDictionary
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IAppCache _requestCache;
|
||||
private readonly CultureInfo _specificCulture;
|
||||
|
||||
public DefaultCultureDictionary()
|
||||
: this(Current.Services.LocalizationService, Current.AppCaches.RequestCache)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor which will use the current thread's culture
|
||||
/// </summary>
|
||||
/// <param name="localizationService"></param>
|
||||
/// <param name="requestCache"></param>
|
||||
public DefaultCultureDictionary(ILocalizationService localizationService, IAppCache requestCache)
|
||||
{
|
||||
_localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService));
|
||||
_requestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache));
|
||||
}
|
||||
|
||||
public DefaultCultureDictionary(CultureInfo specificCulture)
|
||||
: this(Current.Services.LocalizationService, Current.AppCaches.RequestCache)
|
||||
{
|
||||
_specificCulture = specificCulture ?? throw new ArgumentNullException(nameof(specificCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for testing to specify a static culture
|
||||
/// </summary>
|
||||
/// <param name="specificCulture"></param>
|
||||
/// <param name="localizationService"></param>
|
||||
/// <param name="requestCache"></param>
|
||||
public DefaultCultureDictionary(CultureInfo specificCulture, ILocalizationService localizationService, IAppCache requestCache)
|
||||
{
|
||||
_localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService));
|
||||
@@ -0,0 +1,28 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Dictionary
|
||||
{
|
||||
/// <summary>
|
||||
/// A culture dictionary factory used to create an Umbraco.Core.Dictionary.ICultureDictionary.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the future this will allow use to potentially store dictionary items elsewhere and allows for maximum flexibility.
|
||||
/// </remarks>
|
||||
internal class DefaultCultureDictionaryFactory : ICultureDictionaryFactory
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly AppCaches _appCaches;
|
||||
|
||||
public DefaultCultureDictionaryFactory(ILocalizationService localizationService, AppCaches appCaches)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
_appCaches = appCaches;
|
||||
}
|
||||
|
||||
public ICultureDictionary CreateDictionary()
|
||||
{
|
||||
return new DefaultCultureDictionary(_localizationService, _appCaches.RequestCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,9 +229,6 @@ namespace Umbraco.Core.Migrations.Install
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
|
||||
|
||||
}
|
||||
|
||||
private void CreateLanguageData()
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Umbraco.Core.Models
|
||||
private string _username;
|
||||
private string _email;
|
||||
private string _rawPasswordValue;
|
||||
private object _providerUserKey;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating an empty Member object
|
||||
@@ -166,66 +165,6 @@ namespace Umbraco.Core.Models
|
||||
// * Check if we are using the umbraco membership provider, if so then we need to use the configured fields - not the explicit fields below
|
||||
// * If any of the fields don't exist, what should we do? Currently it will throw an exception!
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Password Question
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Alias: umbracoMemberPasswordRetrievalQuestion
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public string PasswordQuestion
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordQuestion, "PasswordQuestion", default(string));
|
||||
if (a.Success == false) return a.Result;
|
||||
|
||||
return Properties[Constants.Conventions.Member.PasswordQuestion].GetValue() == null
|
||||
? string.Empty
|
||||
: Properties[Constants.Conventions.Member.PasswordQuestion].GetValue().ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.PasswordQuestion,
|
||||
"PasswordQuestion") == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.PasswordQuestion].SetValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw password answer value
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For security reasons this value should be encrypted, the encryption process is handled by the membership provider
|
||||
/// Alias: umbracoMemberPasswordRetrievalAnswer
|
||||
///
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
public string RawPasswordAnswerValue
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordAnswer, "PasswordAnswer", default(string));
|
||||
if (a.Success == false) return a.Result;
|
||||
|
||||
return Properties[Constants.Conventions.Member.PasswordAnswer].GetValue() == null
|
||||
? string.Empty
|
||||
: Properties[Constants.Conventions.Member.PasswordAnswer].GetValue().ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.PasswordAnswer,
|
||||
"PasswordAnswer") == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.PasswordAnswer].SetValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the comments for the member
|
||||
/// </summary>
|
||||
@@ -238,7 +177,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.Comments, "Comments", default(string));
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.Comments, nameof(Comments), default(string));
|
||||
if (a.Success == false) return a.Result;
|
||||
|
||||
return Properties[Constants.Conventions.Member.Comments].GetValue() == null
|
||||
@@ -249,7 +188,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.Comments,
|
||||
"Comments") == false) return;
|
||||
nameof(Comments)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.Comments].SetValue(value);
|
||||
}
|
||||
@@ -267,7 +206,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsApproved, "IsApproved",
|
||||
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;
|
||||
@@ -284,7 +223,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.IsApproved,
|
||||
"IsApproved") == false) return;
|
||||
nameof(IsApproved)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.IsApproved].SetValue(value);
|
||||
}
|
||||
@@ -302,7 +241,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, "IsLockedOut", false);
|
||||
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;
|
||||
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].GetValue().TryConvertTo<bool>();
|
||||
@@ -317,7 +256,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.IsLockedOut,
|
||||
"IsLockedOut") == false) return;
|
||||
nameof(IsLockedOut)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.IsLockedOut].SetValue(value);
|
||||
}
|
||||
@@ -335,7 +274,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, "LastLoginDate", default(DateTime));
|
||||
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);
|
||||
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].GetValue().TryConvertTo<DateTime>();
|
||||
@@ -350,7 +289,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.LastLoginDate,
|
||||
"LastLoginDate") == false) return;
|
||||
nameof(LastLoginDate)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.LastLoginDate].SetValue(value);
|
||||
}
|
||||
@@ -368,7 +307,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, "LastPasswordChangeDate", default(DateTime));
|
||||
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);
|
||||
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].GetValue().TryConvertTo<DateTime>();
|
||||
@@ -383,7 +322,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.LastPasswordChangeDate,
|
||||
"LastPasswordChangeDate") == false) return;
|
||||
nameof(LastPasswordChangeDate)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.LastPasswordChangeDate].SetValue(value);
|
||||
}
|
||||
@@ -401,7 +340,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, "LastLockoutDate", default(DateTime));
|
||||
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);
|
||||
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].GetValue().TryConvertTo<DateTime>();
|
||||
@@ -416,7 +355,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.LastLockoutDate,
|
||||
"LastLockoutDate") == false) return;
|
||||
nameof(LastLockoutDate)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.LastLockoutDate].SetValue(value);
|
||||
}
|
||||
@@ -435,7 +374,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, "FailedPasswordAttempts", 0);
|
||||
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);
|
||||
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].GetValue().TryConvertTo<int>();
|
||||
@@ -450,7 +389,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (WarnIfPropertyTypeNotFoundOnSet(
|
||||
Constants.Conventions.Member.FailedPasswordAttempts,
|
||||
"FailedPasswordAttempts") == false) return;
|
||||
nameof(FailedPasswordAttempts)) == false) return;
|
||||
|
||||
Properties[Constants.Conventions.Member.FailedPasswordAttempts].SetValue(value);
|
||||
}
|
||||
@@ -462,22 +401,6 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual string ContentTypeAlias => ContentType.Alias;
|
||||
|
||||
/// <summary>
|
||||
/// User key from the Provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When using standard umbraco provider this key will
|
||||
/// correspond to the guid UniqueId/Key.
|
||||
/// Otherwise it will the one available from the asp.net
|
||||
/// membership provider.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public virtual object ProviderUserKey
|
||||
{
|
||||
get => _providerUserKey;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _providerUserKey, nameof(ProviderUserKey));
|
||||
}
|
||||
|
||||
/* Internal experiment - only used for mapping queries.
|
||||
* Adding these to have first level properties instead of the Properties collection.
|
||||
*/
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
internal static class MembershipUserExtensions
|
||||
{
|
||||
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
|
||||
{
|
||||
var membershipMember = new UmbracoMembershipMember(member, providerName, providerKeyAsGuid);
|
||||
return membershipMember;
|
||||
}
|
||||
|
||||
internal static IMembershipUser AsIMember(this UmbracoMembershipMember membershipMember)
|
||||
{
|
||||
var member = membershipMember;
|
||||
if (member != null)
|
||||
{
|
||||
return member.Member;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static MembershipScenario? _scenario = null;
|
||||
/// <summary>
|
||||
/// Returns the currently configured membership scenario for members in umbraco
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
internal static MembershipScenario GetMembershipScenario(this IMemberTypeService memberTypeService)
|
||||
{
|
||||
if (_scenario.HasValue == false)
|
||||
{
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider())
|
||||
{
|
||||
return MembershipScenario.NativeUmbraco;
|
||||
}
|
||||
var memberType = memberTypeService.Get(Constants.Conventions.MemberTypes.DefaultAlias);
|
||||
return memberType != null
|
||||
? MembershipScenario.CustomProviderWithUmbracoLink
|
||||
: MembershipScenario.StandaloneCustomProvider;
|
||||
}
|
||||
return _scenario.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Web.Security;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
internal class UmbracoMembershipUser<T> : MembershipUser where T : IMembershipUser
|
||||
{
|
||||
private T _user;
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoMembershipUser{T}"/> class.
|
||||
/// </summary>
|
||||
public UmbracoMembershipUser(T user)
|
||||
{
|
||||
_user = user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoMembershipUser{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="providerName">Name of the provider.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="providerUserKey">The provider user key.</param>
|
||||
/// <param name="email">The email.</param>
|
||||
/// <param name="passwordQuestion">The password question.</param>
|
||||
/// <param name="comment">The comment.</param>
|
||||
/// <param name="isApproved">if set to <c>true</c> [is approved].</param>
|
||||
/// <param name="isLockedOut">if set to <c>true</c> [is locked out].</param>
|
||||
/// <param name="creationDate">The creation date.</param>
|
||||
/// <param name="lastLoginDate">The last login date.</param>
|
||||
/// <param name="lastActivityDate">The last activity date.</param>
|
||||
/// <param name="lastPasswordChangedDate">The last password changed date.</param>
|
||||
/// <param name="lastLockoutDate">The last lockout date.</param>
|
||||
/// <param name="fullName">The full name.</param>
|
||||
/// <param name="language">The language.</param>
|
||||
/// <param name="user"></param>
|
||||
public UmbracoMembershipUser(string providerName, string name, object providerUserKey, string email,
|
||||
string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
|
||||
DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate,
|
||||
DateTime lastLockoutDate, string fullName, string language, T user)
|
||||
: base(providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut,
|
||||
creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate)
|
||||
{
|
||||
_user = user;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -124,13 +124,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
#region Implementation of IMembershipUser
|
||||
|
||||
[IgnoreDataMember]
|
||||
public object ProviderUserKey
|
||||
{
|
||||
get => Id;
|
||||
set => throw new NotSupportedException("Cannot set the provider user key for a user");
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public DateTime? EmailConfirmedDate
|
||||
{
|
||||
@@ -204,13 +197,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _failedLoginAttempts, nameof(FailedPasswordAttempts));
|
||||
}
|
||||
|
||||
// TODO: Figure out how to support all of this! - we cannot have NotImplementedExceptions because these get used by the IMembershipMemberService<IUser> service so
|
||||
// we'll just have them as generic get/set which don't interact with the db.
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string PasswordQuestion { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string RawPasswordAnswerValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string Comments { get; set; }
|
||||
|
||||
|
||||
@@ -143,8 +143,6 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
content.CreateDate = nodeDto.CreateDate;
|
||||
content.UpdateDate = contentVersionDto.VersionDate;
|
||||
|
||||
content.ProviderUserKey = content.Key; // The `ProviderUserKey` is a membership provider thing
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
content.ResetDirtyProperties(false);
|
||||
return content;
|
||||
|
||||
@@ -41,8 +41,6 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.IsApproved), nameof(PropertyDataDto.IntegerValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.IsLockedOut), nameof(PropertyDataDto.IntegerValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.Comments), nameof(PropertyDataDto.TextValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.RawPasswordAnswerValue), nameof(PropertyDataDto.VarcharValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.PasswordQuestion), nameof(PropertyDataDto.VarcharValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.FailedPasswordAttempts), nameof(PropertyDataDto.IntegerValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLockoutDate), nameof(PropertyDataDto.DateValue));
|
||||
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLoginDate), nameof(PropertyDataDto.DateValue));
|
||||
|
||||
@@ -233,10 +233,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IMember entity)
|
||||
{
|
||||
if (entity.ProviderUserKey == null)
|
||||
{
|
||||
entity.ProviderUserKey = entity.Key;
|
||||
}
|
||||
entity.AddingEntity();
|
||||
|
||||
var member = (Member) entity;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Web.Security;
|
||||
using Newtonsoft.Json;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -11,13 +10,11 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
@@ -28,6 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
private readonly IMapperCollection _mapperCollection;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IUserPasswordConfiguration _passwordConfiguration;
|
||||
private string _passwordConfigJson;
|
||||
private bool _passwordConfigInitialized;
|
||||
|
||||
@@ -41,23 +39,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// A dictionary specifying the configuration for user passwords. If this is null then no password configuration will be persisted or read.
|
||||
/// </param>
|
||||
/// <param name="globalSettings"></param>
|
||||
public UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings)
|
||||
public UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings, IUserPasswordConfiguration passwordConfiguration)
|
||||
: base(scopeAccessor, appCaches, logger)
|
||||
{
|
||||
_mapperCollection = mapperCollection;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IDictionary<string, string> passwordConfig, IGlobalSettings globalSettings)
|
||||
: base(scopeAccessor, appCaches, logger)
|
||||
{
|
||||
_mapperCollection = mapperCollection;
|
||||
_globalSettings = globalSettings;
|
||||
_passwordConfigJson = JsonConvert.SerializeObject(passwordConfig);
|
||||
_passwordConfigInitialized = true;
|
||||
}
|
||||
_mapperCollection = mapperCollection ?? throw new ArgumentNullException(nameof(mapperCollection));
|
||||
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
|
||||
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a serialized dictionary of the password configuration that is stored against the user in the database
|
||||
/// </summary>
|
||||
private string PasswordConfigJson
|
||||
{
|
||||
get
|
||||
@@ -65,14 +57,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (_passwordConfigInitialized)
|
||||
return _passwordConfigJson;
|
||||
|
||||
// TODO: this is bad
|
||||
// because the membership provider we're trying to get has a dependency on the user service
|
||||
// and we should not depend on services in repositories - need a way better way to do this
|
||||
|
||||
var userMembershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider();
|
||||
var passwordConfig = userMembershipProvider == null || userMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed
|
||||
? null
|
||||
: new Dictionary<string, string> { { "hashAlgorithm", Membership.HashAlgorithmType } };
|
||||
var passwordConfig = new Dictionary<string, string> { { "hashAlgorithm", _passwordConfiguration.HashAlgorithmType } };
|
||||
_passwordConfigJson = passwordConfig == null ? null : JsonConvert.SerializeObject(passwordConfig);
|
||||
_passwordConfigInitialized = true;
|
||||
return _passwordConfigJson;
|
||||
@@ -507,6 +492,7 @@ ORDER BY colName";
|
||||
// list the columns to save, NOTE: would be nice to not have hard coded strings here but no real good way around that
|
||||
var colsToSave = new Dictionary<string, string>
|
||||
{
|
||||
//TODO: Change these to constants + nameof
|
||||
{"userDisabled", "IsApproved"},
|
||||
{"userNoConsole", "IsLockedOut"},
|
||||
{"startStructureID", "StartContentId"},
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Core.Composing.CompositionExtensions;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
@@ -18,6 +19,7 @@ using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.Validators;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Serialization;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
@@ -131,6 +133,10 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
// by default, register a noop rebuilder
|
||||
composition.RegisterUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
|
||||
|
||||
composition.SetCultureDictionaryFactory<DefaultCultureDictionaryFactory>();
|
||||
composition.Register(f => f.GetInstance<ICultureDictionaryFactory>().CreateDictionary(), Lifetime.Singleton);
|
||||
composition.RegisterUnique<IPasswordGenerator, PasswordGenerator>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
@@ -34,32 +33,24 @@ namespace Umbraco.Core.Security
|
||||
//IQueryableUserStore<BackOfficeIdentityUser, int>
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IExternalLoginService _externalLoginService;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly UmbracoMapper _mapper;
|
||||
private bool _disposed = false;
|
||||
|
||||
public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider, UmbracoMapper mapper)
|
||||
public BackOfficeUserStore(IUserService userService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, UmbracoMapper mapper)
|
||||
{
|
||||
_userService = userService;
|
||||
_memberTypeService = memberTypeService;
|
||||
_entityService = entityService;
|
||||
_externalLoginService = externalLoginService;
|
||||
_globalSettings = globalSettings;
|
||||
if (userService == null) throw new ArgumentNullException("userService");
|
||||
if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider");
|
||||
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
|
||||
_mapper = mapper;
|
||||
|
||||
_userService = userService;
|
||||
_externalLoginService = externalLoginService;
|
||||
|
||||
if (usersMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use ASP.Net Identity with UmbracoMembersUserStore when the password format is not Hashed");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensure that both the normal password validator rules are processed along with the underlying membership provider rules
|
||||
/// </summary>
|
||||
public class ConfiguredPasswordValidator : PasswordValidator
|
||||
{
|
||||
public ConfiguredPasswordValidator(IPasswordConfiguration config)
|
||||
{
|
||||
RequiredLength = config.RequiredLength;
|
||||
RequireNonLetterOrDigit = config.RequireNonLetterOrDigit;
|
||||
RequireDigit = config.RequireDigit;
|
||||
RequireLowercase = config.RequireLowercase;
|
||||
RequireUppercase = config.RequireUppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A password hasher that is based on the rules configured for a membership provider
|
||||
/// </summary>
|
||||
public interface IMembershipProviderPasswordHasher : IPasswordHasher
|
||||
{
|
||||
MembershipProviderBase MembershipProvider { get; }
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@ namespace Umbraco.Core.Security
|
||||
string CommentPropertyTypeAlias { get; }
|
||||
string LastLoginPropertyTypeAlias { get; }
|
||||
string LastPasswordChangedPropertyTypeAlias { get; }
|
||||
string PasswordRetrievalQuestionPropertyTypeAlias { get; }
|
||||
string PasswordRetrievalAnswerPropertyTypeAlias { get; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Security
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TUser"></typeparam>
|
||||
public interface IUserAwarePasswordHasher<in TUser, TKey>
|
||||
public interface IUserAwarePasswordHasher<in TUser, TKey> : IPasswordHasher
|
||||
where TUser : class, IUser<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A marker interface used internally to identify Umbraco built-in Users membership providers
|
||||
/// </summary>
|
||||
internal interface IUsersMembershipProvider
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A password hasher that conforms to the password hashing done with membership providers
|
||||
/// </summary>
|
||||
public class MembershipProviderPasswordHasher : IMembershipProviderPasswordHasher
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes the underlying MembershipProvider
|
||||
/// </summary>
|
||||
public MembershipProviderBase MembershipProvider { get; private set; }
|
||||
|
||||
public MembershipProviderPasswordHasher(MembershipProviderBase provider)
|
||||
{
|
||||
MembershipProvider = provider;
|
||||
}
|
||||
|
||||
public string HashPassword(string password)
|
||||
{
|
||||
return MembershipProvider.HashPasswordForStorage(password);
|
||||
}
|
||||
|
||||
public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
|
||||
{
|
||||
return MembershipProvider.VerifyPassword(providedPassword, hashedPassword)
|
||||
? PasswordVerificationResult.Success
|
||||
: PasswordVerificationResult.Failed;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensure that both the normal password validator rules are processed along with the underlying membership provider rules
|
||||
/// </summary>
|
||||
public class MembershipProviderPasswordValidator : PasswordValidator
|
||||
{
|
||||
public MembershipProvider Provider { get; private set; }
|
||||
|
||||
public MembershipProviderPasswordValidator(MembershipProvider provider)
|
||||
{
|
||||
Provider = provider;
|
||||
|
||||
RequiredLength = Provider.MinRequiredPasswordLength;
|
||||
RequireNonLetterOrDigit = Provider.MinRequiredNonAlphanumericCharacters > 0;
|
||||
RequireDigit = false;
|
||||
RequireLowercase = false;
|
||||
RequireUppercase = false;
|
||||
}
|
||||
|
||||
public override async Task<IdentityResult> ValidateAsync(string item)
|
||||
{
|
||||
var result = await base.ValidateAsync(item);
|
||||
if (result.Succeeded == false)
|
||||
return result;
|
||||
var providerValidate = MembershipProviderBase.IsPasswordValid(item, Provider.MinRequiredNonAlphanumericCharacters, Provider.PasswordStrengthRegularExpression, Provider.MinRequiredPasswordLength);
|
||||
if (providerValidate.Success == false)
|
||||
{
|
||||
return IdentityResult.Failed("Could not set password, password rules violated: " + providerValidate.Result);
|
||||
}
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
public class PasswordSecurity
|
||||
{
|
||||
private readonly IPasswordConfiguration _passwordConfiguration;
|
||||
|
||||
public PasswordSecurity(IPasswordConfiguration passwordConfiguration)
|
||||
{
|
||||
_passwordConfiguration = passwordConfiguration;
|
||||
}
|
||||
|
||||
public string HashPasswordForStorage(string password)
|
||||
{
|
||||
string salt;
|
||||
var hashed = EncryptOrHashNewPassword(password, out salt);
|
||||
return FormatPasswordForStorage(hashed, salt);
|
||||
}
|
||||
|
||||
public bool VerifyPassword(string password, string hashedPassword)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(hashedPassword)) throw new ArgumentException("Value cannot be null or whitespace.", "hashedPassword");
|
||||
return CheckPassword(password, hashedPassword);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the password format is a hashed keyed algorithm then we will pre-pend the salt used to hash the password
|
||||
/// to the hashed password itself.
|
||||
/// </summary>
|
||||
/// <param name="pass"></param>
|
||||
/// <param name="salt"></param>
|
||||
/// <returns></returns>
|
||||
public string FormatPasswordForStorage(string pass, string salt)
|
||||
{
|
||||
if (_passwordConfiguration.UseLegacyEncoding)
|
||||
{
|
||||
return pass;
|
||||
}
|
||||
|
||||
return salt + pass;
|
||||
}
|
||||
|
||||
public string EncryptOrHashPassword(string pass, string salt)
|
||||
{
|
||||
//if we are doing it the old way
|
||||
|
||||
if (_passwordConfiguration.UseLegacyEncoding)
|
||||
{
|
||||
return LegacyEncodePassword(pass);
|
||||
}
|
||||
|
||||
//This is the correct way to implement this (as per the sql membership provider)
|
||||
|
||||
var bytes = Encoding.Unicode.GetBytes(pass);
|
||||
var saltBytes = Convert.FromBase64String(salt);
|
||||
byte[] inArray;
|
||||
|
||||
var hashAlgorithm = GetHashAlgorithm(pass);
|
||||
var algorithm = hashAlgorithm as KeyedHashAlgorithm;
|
||||
if (algorithm != null)
|
||||
{
|
||||
var keyedHashAlgorithm = algorithm;
|
||||
if (keyedHashAlgorithm.Key.Length == saltBytes.Length)
|
||||
{
|
||||
//if the salt bytes is the required key length for the algorithm, use it as-is
|
||||
keyedHashAlgorithm.Key = saltBytes;
|
||||
}
|
||||
else if (keyedHashAlgorithm.Key.Length < saltBytes.Length)
|
||||
{
|
||||
//if the salt bytes is too long for the required key length for the algorithm, reduce it
|
||||
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
|
||||
Buffer.BlockCopy(saltBytes, 0, numArray2, 0, numArray2.Length);
|
||||
keyedHashAlgorithm.Key = numArray2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if the salt bytes is too short for the required key length for the algorithm, extend it
|
||||
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
|
||||
var dstOffset = 0;
|
||||
while (dstOffset < numArray2.Length)
|
||||
{
|
||||
var count = Math.Min(saltBytes.Length, numArray2.Length - dstOffset);
|
||||
Buffer.BlockCopy(saltBytes, 0, numArray2, dstOffset, count);
|
||||
dstOffset += count;
|
||||
}
|
||||
keyedHashAlgorithm.Key = numArray2;
|
||||
}
|
||||
inArray = keyedHashAlgorithm.ComputeHash(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
var buffer = new byte[saltBytes.Length + bytes.Length];
|
||||
Buffer.BlockCopy(saltBytes, 0, buffer, 0, saltBytes.Length);
|
||||
Buffer.BlockCopy(bytes, 0, buffer, saltBytes.Length, bytes.Length);
|
||||
inArray = hashAlgorithm.ComputeHash(buffer);
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(inArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the password.
|
||||
/// </summary>
|
||||
/// <param name="password">The password.</param>
|
||||
/// <param name="dbPassword">The dbPassword.</param>
|
||||
/// <returns></returns>
|
||||
public bool CheckPassword(string password, string dbPassword)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dbPassword)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(dbPassword));
|
||||
var storedHashedPass = StoredPassword(dbPassword, out var salt);
|
||||
var hashed = EncryptOrHashPassword(password, salt);
|
||||
return storedHashedPass == hashed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt/hash a new password with a new salt
|
||||
/// </summary>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <param name="salt"></param>
|
||||
/// <returns></returns>
|
||||
public string EncryptOrHashNewPassword(string newPassword, out string salt)
|
||||
{
|
||||
salt = GenerateSalt();
|
||||
return EncryptOrHashPassword(newPassword, salt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hashed password without the salt if it is hashed
|
||||
/// </summary>
|
||||
/// <param name="storedString"></param>
|
||||
/// <param name="salt">returns the salt</param>
|
||||
/// <returns></returns>
|
||||
public string StoredPassword(string storedString, out string salt)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(storedString)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(storedString));
|
||||
if (_passwordConfiguration.UseLegacyEncoding)
|
||||
{
|
||||
salt = string.Empty;
|
||||
return storedString;
|
||||
}
|
||||
|
||||
var saltLen = GenerateSalt();
|
||||
salt = storedString.Substring(0, saltLen.Length);
|
||||
return storedString.Substring(saltLen.Length);
|
||||
}
|
||||
|
||||
public static string GenerateSalt()
|
||||
{
|
||||
var numArray = new byte[16];
|
||||
new RNGCryptoServiceProvider().GetBytes(numArray);
|
||||
return Convert.ToBase64String(numArray);
|
||||
}
|
||||
|
||||
public HashAlgorithm GetHashAlgorithm(string password)
|
||||
{
|
||||
if (_passwordConfiguration.UseLegacyEncoding)
|
||||
{
|
||||
return new HMACSHA1
|
||||
{
|
||||
//the legacy salt was actually the password :(
|
||||
Key = Encoding.Unicode.GetBytes(password)
|
||||
};
|
||||
}
|
||||
|
||||
if (_passwordConfiguration.HashAlgorithmType.IsNullOrWhiteSpace())
|
||||
throw new InvalidOperationException("No hash algorithm type specified");
|
||||
|
||||
var alg = HashAlgorithm.Create(_passwordConfiguration.HashAlgorithmType);
|
||||
if (alg == null)
|
||||
throw new InvalidOperationException($"The hash algorithm specified {_passwordConfiguration.HashAlgorithmType} cannot be resolved");
|
||||
|
||||
return alg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the password.
|
||||
/// </summary>
|
||||
/// <param name="password">The password.</param>
|
||||
/// <returns>The encoded password.</returns>
|
||||
private string LegacyEncodePassword(string password)
|
||||
{
|
||||
string encodedPassword = password;
|
||||
var hashAlgorith = GetHashAlgorithm(password);
|
||||
encodedPassword = Convert.ToBase64String(hashAlgorith.ComputeHash(Encoding.Unicode.GetBytes(password)));
|
||||
return encodedPassword;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Owin.Security;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
|
||||
+21
-4
@@ -7,24 +7,41 @@ namespace Umbraco.Core.Security
|
||||
/// <summary>
|
||||
/// The default password hasher that is User aware so that it can process the hashing based on the user's settings
|
||||
/// </summary>
|
||||
public class UserAwareMembershipProviderPasswordHasher : MembershipProviderPasswordHasher, IUserAwarePasswordHasher<BackOfficeIdentityUser, int>
|
||||
public class UserAwarePasswordHasher : IUserAwarePasswordHasher<BackOfficeIdentityUser, int>
|
||||
{
|
||||
public UserAwareMembershipProviderPasswordHasher(MembershipProviderBase provider) : base(provider)
|
||||
private readonly PasswordSecurity _passwordSecurity;
|
||||
|
||||
public UserAwarePasswordHasher(PasswordSecurity passwordSecurity)
|
||||
{
|
||||
_passwordSecurity = passwordSecurity;
|
||||
}
|
||||
|
||||
public string HashPassword(string password)
|
||||
{
|
||||
return _passwordSecurity.HashPasswordForStorage(password);
|
||||
}
|
||||
|
||||
public string HashPassword(BackOfficeIdentityUser user, string password)
|
||||
{
|
||||
// TODO: Implement the logic for this, we need to lookup the password format for the user and hash accordingly: http://issues.umbraco.org/issue/U4-10089
|
||||
//NOTE: For now this just falls back to the hashing we are currently using
|
||||
return base.HashPassword(password);
|
||||
|
||||
return HashPassword(password);
|
||||
}
|
||||
|
||||
public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
|
||||
{
|
||||
return _passwordSecurity.VerifyPassword(providedPassword, hashedPassword)
|
||||
? PasswordVerificationResult.Success
|
||||
: PasswordVerificationResult.Failed;
|
||||
}
|
||||
|
||||
public PasswordVerificationResult VerifyHashedPassword(BackOfficeIdentityUser user, string hashedPassword, string providedPassword)
|
||||
{
|
||||
// TODO: Implement the logic for this, we need to lookup the password format for the user and hash accordingly: http://issues.umbraco.org/issue/U4-10089
|
||||
//NOTE: For now this just falls back to the hashing we are currently using
|
||||
return base.VerifyHashedPassword(hashedPassword, providedPassword);
|
||||
|
||||
return VerifyHashedPassword(hashedPassword, providedPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines part of the MemberService, which is specific to methods used by the membership provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Idea is to have this as an isolated interface so that it can be easily 'replaced' in the membership provider implementation.
|
||||
/// </remarks>
|
||||
public interface IMembershipMemberService : IMembershipMemberService<IMember>, IMembershipRoleService<IMember>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates and persists a new Member
|
||||
/// </summary>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
/// <param name="memberType"><see cref="IMemberType"/> which the Member should be based on</param>
|
||||
/// <returns><see cref="IMember"/></returns>
|
||||
IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Scoping;
|
||||
@@ -27,17 +26,16 @@ namespace Umbraco.Core.Services.Implement
|
||||
private readonly IContentTypeRepository _contentTypeRepository;
|
||||
private readonly IDocumentBlueprintRepository _documentBlueprintRepository;
|
||||
private readonly ILanguageRepository _languageRepository;
|
||||
private readonly Lazy<IPropertyValidationService> _propertyValidationService;
|
||||
private IQuery<IContent> _queryNotTrashed;
|
||||
//TODO: The non-lazy object should be injected
|
||||
private readonly Lazy<PropertyValidationService> _propertyValidationService = new Lazy<PropertyValidationService>(() => new PropertyValidationService());
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ContentService(IScopeProvider provider, ILogger logger,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IDocumentRepository documentRepository, IEntityRepository entityRepository, IAuditRepository auditRepository,
|
||||
IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository)
|
||||
IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository,
|
||||
Lazy<IPropertyValidationService> propertyValidationService)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_documentRepository = documentRepository;
|
||||
@@ -46,6 +44,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
_contentTypeRepository = contentTypeRepository;
|
||||
_documentBlueprintRepository = documentBlueprintRepository;
|
||||
_languageRepository = languageRepository;
|
||||
_propertyValidationService = propertyValidationService;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
@@ -29,9 +25,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
private readonly IMemberGroupService _memberGroupService;
|
||||
|
||||
//only for unit tests!
|
||||
internal MembershipProviderBase MembershipProvider { get; set; }
|
||||
|
||||
#region Constructor
|
||||
|
||||
public MemberService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService,
|
||||
@@ -71,11 +64,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
case MemberCountType.All:
|
||||
query = Query<IMember>();
|
||||
break;
|
||||
case MemberCountType.Online:
|
||||
var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
|
||||
query = Query<IMember>().Where(x => ((Member) x).PropertyTypeAlias == Constants.Conventions.Member.LastLoginDate && ((Member) x).DateTimePropertyValue > fromDate);
|
||||
break;
|
||||
break;
|
||||
case MemberCountType.LockedOut:
|
||||
query = Query<IMember>().Where(x => ((Member) x).PropertyTypeAlias == Constants.Conventions.Member.IsLockedOut && ((Member) x).BoolPropertyValue);
|
||||
break;
|
||||
@@ -1130,39 +1119,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
#region Membership
|
||||
|
||||
/// <summary>
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
|
||||
/// </summary>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// Members if they choose to. </remarks>
|
||||
/// <param name="member">The Member to save the password for</param>
|
||||
/// <param name="password">The password to encrypt and save</param>
|
||||
public void SavePassword(IMember member, string password)
|
||||
{
|
||||
if (member == null) throw new ArgumentNullException(nameof(member));
|
||||
|
||||
var provider = MembershipProvider ?? MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider())
|
||||
provider.ChangePassword(member.Username, "", password); // this is actually updating the password
|
||||
else
|
||||
throw new NotSupportedException("When using a non-Umbraco membership provider you must change the member password by using the MembershipProvider.ChangePassword method");
|
||||
|
||||
// go re-fetch the member to update the properties that may have changed
|
||||
// check that it still exists (optimistic concurrency somehow)
|
||||
|
||||
// re-fetch and ensure it exists
|
||||
var m = GetByUsername(member.Username);
|
||||
if (m == null) return; // gone
|
||||
|
||||
// update properties that have changed
|
||||
member.RawPasswordValue = m.RawPasswordValue;
|
||||
member.LastPasswordChangeDate = m.LastPasswordChangeDate;
|
||||
member.UpdateDate = m.UpdateDate;
|
||||
|
||||
// no need to save anything - provider.ChangePassword has done the updates,
|
||||
// and then all we do is re-fetch to get the updated values, and update the
|
||||
// in-memory member accordingly
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper method that will create a basic/generic member for use with a generic membership provider
|
||||
@@ -1279,13 +1235,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
foreach (var property in member.Properties)
|
||||
{
|
||||
//ignore list
|
||||
switch (property.Alias)
|
||||
{
|
||||
case Constants.Conventions.Member.PasswordQuestion:
|
||||
continue;
|
||||
}
|
||||
|
||||
var propertyExportModel = new MemberExportProperty
|
||||
{
|
||||
Id = property.Id,
|
||||
|
||||
+4
-21
@@ -1,17 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Composing;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
//TODO: We should make this an interface and inject it into the ContentService
|
||||
internal class PropertyValidationService
|
||||
internal class PropertyValidationService : IPropertyValidationService
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
@@ -22,15 +15,7 @@ namespace Umbraco.Core.Services
|
||||
_dataTypeService = dataTypeService;
|
||||
}
|
||||
|
||||
//TODO: Remove this method in favor of the overload specifying all dependencies
|
||||
public PropertyValidationService()
|
||||
: this(Current.PropertyEditors, Current.Services.DataTypeService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the content item's properties pass validation rules
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool IsPropertyDataValid(IContent content, out IProperty[] invalidProperties, CultureImpact impact)
|
||||
{
|
||||
// select invalid properties
|
||||
@@ -63,9 +48,7 @@ namespace Umbraco.Core.Services
|
||||
return invalidProperties.Length == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property has valid values.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool IsPropertyValid(IProperty property, string culture = "*", string segment = "*")
|
||||
{
|
||||
//NOTE - the pvalue and vvalues logic in here is borrowed directly from the Property.Values setter so if you are wondering what that's all about, look there.
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
@@ -12,12 +9,10 @@ using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
@@ -479,23 +474,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
case MemberCountType.All:
|
||||
query = Query<IUser>();
|
||||
break;
|
||||
case MemberCountType.Online:
|
||||
throw new NotImplementedException();
|
||||
//var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
|
||||
//query =
|
||||
// Query<IMember>.Builder.Where(
|
||||
// x =>
|
||||
// ((Member)x).PropertyTypeAlias == Constants.Conventions.Member.LastLoginDate &&
|
||||
// ((Member)x).DateTimePropertyValue > fromDate);
|
||||
//return repository.GetCountByQuery(query);
|
||||
//var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
|
||||
//query =
|
||||
// Query<IMember>.Builder.Where(
|
||||
// x =>
|
||||
// ((Member)x).PropertyTypeAlias == Constants.Conventions.Member.LastLoginDate &&
|
||||
// ((Member)x).DateTimePropertyValue > fromDate);
|
||||
//return repository.GetCountByQuery(query);
|
||||
break;
|
||||
case MemberCountType.LockedOut:
|
||||
query = Query<IUser>().Where(x => x.IsLockedOut);
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -146,6 +146,8 @@
|
||||
<Compile Include="CompositionExtensions_FileSystems.cs" />
|
||||
<Compile Include="ConventionsHelper.cs" />
|
||||
<Compile Include="Deploy\IGridCellValueConnector.cs" />
|
||||
<Compile Include="Dictionary\UmbracoCultureDictionary.cs" />
|
||||
<Compile Include="Dictionary\UmbracoCultureDictionaryFactory.cs" />
|
||||
<Compile Include="Events\ContentPublishedEventArgs.cs" />
|
||||
<Compile Include="Events\ContentPublishingEventArgs.cs" />
|
||||
<Compile Include="Events\ContentSavedEventArgs.cs" />
|
||||
@@ -201,7 +203,6 @@
|
||||
<Compile Include="Models\PropertyCollection.cs" />
|
||||
<Compile Include="Models\PropertyType.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\FixLanguageIsoCodeLength.cs" />
|
||||
<Compile Include="Models\CultureImpact.cs" />
|
||||
<Compile Include="Models\PublishedContent\IndexedArrayItem.cs" />
|
||||
<Compile Include="Models\PublishedContent\VariationContextAccessorExtensions.cs" />
|
||||
<Compile Include="Models\Template.cs" />
|
||||
@@ -231,13 +232,9 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
|
||||
<Compile Include="PropertyEditors\VoidEditor.cs" />
|
||||
<Compile Include="PublishedContentExtensions.cs" />
|
||||
<Compile Include="Security\PasswordSecurity.cs" />
|
||||
<Compile Include="Serialization\JsonNetSerializer.cs" />
|
||||
<Compile Include="Services\Changes\ContentTypeChange.cs" />
|
||||
<Compile Include="Services\Changes\ContentTypeChangeExtensions.cs" />
|
||||
<Compile Include="Services\IMemberService.cs" />
|
||||
<Compile Include="Services\IMembershipMemberService.cs" />
|
||||
<Compile Include="Services\LocalizedTextServiceExtensions.cs" />
|
||||
<Compile Include="Services\PropertyValidationService.cs" />
|
||||
<Compile Include="Services\Implement\PropertyValidationService.cs" />
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
<Compile Include="Strings\DefaultUrlSegmentProvider.cs" />
|
||||
<Compile Include="Strings\IUrlSegmentProvider.cs" />
|
||||
@@ -372,9 +369,6 @@
|
||||
<Compile Include="Models\MediaExtensions.cs" />
|
||||
<Compile Include="Models\MediaType.cs" />
|
||||
<Compile Include="Models\Member.cs" />
|
||||
<Compile Include="Models\Membership\MembershipUserExtensions.cs" />
|
||||
<Compile Include="Models\Membership\UmbracoMembershipMember.cs" />
|
||||
<Compile Include="Models\Membership\UmbracoMembershipUser.cs" />
|
||||
<Compile Include="Models\Membership\User.cs" />
|
||||
<Compile Include="Models\MemberType.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentTypeFactory.cs" />
|
||||
@@ -649,7 +643,6 @@
|
||||
<Compile Include="Persistence\Querying\SqlExpressionExtensions.cs" />
|
||||
<Compile Include="Persistence\Querying\SqlTranslator.cs" />
|
||||
<Compile Include="Persistence\Querying\TextColumnType.cs" />
|
||||
<Compile Include="Persistence\Querying\ValuePropertyMatchType.cs" />
|
||||
<Compile Include="Persistence\RecordPersistenceType.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\AuditRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\DocumentBlueprintRepository.cs" />
|
||||
@@ -743,20 +736,14 @@
|
||||
<Compile Include="Security\BackOfficeUserValidator.cs" />
|
||||
<Compile Include="Security\ContentPermissionsHelper.cs" />
|
||||
<Compile Include="Security\EmailService.cs" />
|
||||
<Compile Include="Security\IMembershipProviderPasswordHasher.cs" />
|
||||
<Compile Include="Security\IUmbracoMemberTypeMembershipProvider.cs" />
|
||||
<Compile Include="Security\IUserAwarePasswordHasher.cs" />
|
||||
<Compile Include="Security\IUserSessionStore.cs" />
|
||||
<Compile Include="Security\IUsersMembershipProvider.cs" />
|
||||
<Compile Include="Security\MachineKeyGenerator.cs" />
|
||||
<Compile Include="Security\MembershipProviderBase.cs" />
|
||||
<Compile Include="Security\MembershipProviderExtensions.cs" />
|
||||
<Compile Include="Security\MembershipProviderPasswordHasher.cs" />
|
||||
<Compile Include="Security\MembershipProviderPasswordValidator.cs" />
|
||||
<Compile Include="Security\ConfiguredPasswordValidator.cs" />
|
||||
<Compile Include="Security\UmbracoBackOfficeIdentity.cs" />
|
||||
<Compile Include="Security\UmbracoEmailMessage.cs" />
|
||||
<Compile Include="Security\UmbracoMembershipProviderBase.cs" />
|
||||
<Compile Include="Security\UserAwareMembershipProviderPasswordHasher.cs" />
|
||||
<Compile Include="Security\UserAwarePasswordHasher.cs" />
|
||||
<Compile Include="Serialization\CaseInsensitiveDictionaryConverter.cs" />
|
||||
<Compile Include="Serialization\ForceInt32Converter.cs" />
|
||||
<Compile Include="Serialization\JsonReadConverter.cs" />
|
||||
@@ -796,16 +783,13 @@
|
||||
<Compile Include="Services\Implement\NotificationService.cs" />
|
||||
<Compile Include="Services\Implement\PackagingService.cs" />
|
||||
<Compile Include="Services\Implement\PublicAccessService.cs" />
|
||||
<Compile Include="Services\PublicAccessServiceExtensions.cs" />
|
||||
<Compile Include="Services\Implement\RedirectUrlService.cs" />
|
||||
<Compile Include="Services\Implement\RelationService.cs" />
|
||||
<Compile Include="Services\Implement\RepositoryService.cs" />
|
||||
<Compile Include="Services\Implement\ScopeRepositoryService.cs" />
|
||||
<Compile Include="Services\Implement\ServerRegistrationService.cs" />
|
||||
<Compile Include="Services\ServiceContext.cs" />
|
||||
<Compile Include="Services\Implement\TagService.cs" />
|
||||
<Compile Include="Services\Implement\UserService.cs" />
|
||||
<Compile Include="Services\UserServiceExtensions.cs" />
|
||||
<Compile Include="Compose\ManifestWatcherComponent.cs" />
|
||||
<Compile Include="Compose\RelateOnCopyComponent.cs" />
|
||||
<Compile Include="Compose\RelateOnTrashComponent.cs" />
|
||||
@@ -833,5 +817,6 @@
|
||||
<Name>Umbraco.Abstractions</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -43,7 +43,6 @@
|
||||
<providers>
|
||||
<clear/>
|
||||
<add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco.Web" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="false" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed"/>
|
||||
<add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="false" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" passwordFormat="Hashed" allowManuallyChangingPassword="false"/>
|
||||
</providers>
|
||||
</membership>
|
||||
</system.web>
|
||||
|
||||
@@ -31,11 +31,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
return _requestCache.GetCacheItem<IPublishedContent>(
|
||||
GetCacheKey("GetByProviderKey", key), () =>
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("Cannot access this method unless the Umbraco membership provider is active");
|
||||
}
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
var result = _memberService.GetByProviderKey(key);
|
||||
if (result == null) return null;
|
||||
@@ -49,11 +45,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
return _requestCache.GetCacheItem<IPublishedContent>(
|
||||
GetCacheKey("GetById", memberId), () =>
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("Cannot access this method unless the Umbraco membership provider is active");
|
||||
}
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
var result = _memberService.GetById(memberId);
|
||||
if (result == null) return null;
|
||||
@@ -67,11 +59,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
return _requestCache.GetCacheItem<IPublishedContent>(
|
||||
GetCacheKey("GetByUsername", username), () =>
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("Cannot access this method unless the Umbraco membership provider is active");
|
||||
}
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
var result = _memberService.GetByUsername(username);
|
||||
if (result == null) return null;
|
||||
@@ -85,11 +73,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
return _requestCache.GetCacheItem<IPublishedContent>(
|
||||
GetCacheKey("GetByEmail", email), () =>
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("Cannot access this method unless the Umbraco membership provider is active");
|
||||
}
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
var result = _memberService.GetByEmail(email);
|
||||
if (result == null) return null;
|
||||
|
||||
@@ -6,8 +6,8 @@ using System.Web.Security;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Tests.Membership
|
||||
{
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void Change_Password_Without_AllowManuallyChangingPassword_And_No_Pass_Validation()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void Change_Password_With_AllowManuallyChangingPassword_And_Invalid_Creds()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
|
||||
providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false);
|
||||
var provider = providerMock.Object;
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void ChangePasswordQuestionAndAnswer_Without_RequiresQuestionAndAnswer()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(false);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void ChangePasswordQuestionAndAnswer_Without_AllowManuallyChangingPassword_And_Invalid_Creds()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
|
||||
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
|
||||
providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false);
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void CreateUser_Not_Whitespace()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) {CallBase = true};
|
||||
var providerMock = new Mock<MembershipProviderBase>() {CallBase = true};
|
||||
var provider = providerMock.Object;
|
||||
|
||||
MembershipCreateStatus status;
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void CreateUser_Invalid_Question()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void CreateUser_Invalid_Answer()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void GetPassword_Without_EnablePasswordRetrieval()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(false);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void GetPassword_With_Hashed()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(true);
|
||||
providerMock.Setup(@base => @base.PasswordFormat).Returns(MembershipPasswordFormat.Hashed);
|
||||
var provider = providerMock.Object;
|
||||
@@ -128,7 +128,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Ignore("makes no sense?")]
|
||||
public void ResetPassword_Without_EnablePasswordReset()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
providerMock.Setup(@base => @base.EnablePasswordReset).Returns(false);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
@@ -138,12 +138,12 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void Sets_Defaults()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection());
|
||||
|
||||
Assert.AreEqual("test", provider.Name);
|
||||
Assert.AreEqual(MembershipProviderBase.GetDefaultAppName(TestHelper.GetHostingEnvironment()), provider.ApplicationName);
|
||||
Assert.AreEqual(MembershipProviderBase.GetDefaultAppName(), provider.ApplicationName);
|
||||
Assert.AreEqual(false, provider.EnablePasswordRetrieval);
|
||||
Assert.AreEqual(true, provider.EnablePasswordReset);
|
||||
Assert.AreEqual(false, provider.RequiresQuestionAndAnswer);
|
||||
@@ -160,7 +160,7 @@ namespace Umbraco.Tests.Membership
|
||||
[Test]
|
||||
public void Throws_Exception_With_Hashed_Password_And_Password_Retrieval()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
|
||||
Assert.Throws<ProviderException>(() => provider.Initialize("test", new NameValueCollection()
|
||||
@@ -189,223 +189,9 @@ namespace Umbraco.Tests.Membership
|
||||
Assert.AreEqual(pass, result.Success);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The salt generated is always the same length
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Check_Salt_Length()
|
||||
{
|
||||
var lastLength = 0;
|
||||
for (var i = 0; i < 10000; i++)
|
||||
{
|
||||
var result = MembershipProviderBase.GenerateSalt();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
Assert.AreEqual(lastLength, result.Length);
|
||||
}
|
||||
|
||||
lastLength = result.Length;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Stored_Password_Hashed()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
var salt = MembershipProviderBase.GenerateSalt();
|
||||
var stored = salt + "ThisIsAHashedPassword";
|
||||
|
||||
string initSalt;
|
||||
var result = provider.StoredPassword(stored, out initSalt);
|
||||
|
||||
Assert.AreEqual("ThisIsAHashedPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Stored_Password_Encrypted()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
|
||||
|
||||
var stored = "ThisIsAnEncryptedPassword";
|
||||
|
||||
string initSalt;
|
||||
var result = provider.StoredPassword(stored, out initSalt);
|
||||
|
||||
Assert.AreEqual("ThisIsAnEncryptedPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Stored_Password_Clear()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Clear" } });
|
||||
|
||||
var salt = MembershipProviderBase.GenerateSalt();
|
||||
var stored = "ThisIsAClearPassword";
|
||||
|
||||
string initSalt;
|
||||
var result = provider.StoredPassword(stored, out initSalt);
|
||||
|
||||
Assert.AreEqual("ThisIsAClearPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_Pass_For_Storage_Hashed()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
var salt = MembershipProviderBase.GenerateSalt();
|
||||
var stored = "ThisIsAHashedPassword";
|
||||
|
||||
var result = provider.FormatPasswordForStorage(stored, salt);
|
||||
|
||||
Assert.AreEqual(salt + "ThisIsAHashedPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_Pass_For_Storage_Encrypted()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
|
||||
|
||||
var salt = MembershipProviderBase.GenerateSalt();
|
||||
var stored = "ThisIsAnEncryptedPassword";
|
||||
|
||||
var result = provider.FormatPasswordForStorage(stored, salt);
|
||||
|
||||
Assert.AreEqual("ThisIsAnEncryptedPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_Pass_For_Storage_Clear()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Clear" } });
|
||||
|
||||
var salt = MembershipProviderBase.GenerateSalt();
|
||||
var stored = "ThisIsAClearPassword";
|
||||
|
||||
var result = provider.FormatPasswordForStorage(stored, salt);
|
||||
|
||||
Assert.AreEqual("ThisIsAClearPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Hashed_KeyedHashAlgorithm()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAHashedPassword";
|
||||
var hashed = provider.EncryptOrHashNewPassword(pass, out salt);
|
||||
var storedPassword = provider.FormatPasswordForStorage(hashed, salt);
|
||||
|
||||
var result = provider.CheckPassword("ThisIsAHashedPassword", storedPassword);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Hashed_Non_KeyedHashAlgorithm()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" } });
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAHashedPassword";
|
||||
var hashed = provider.EncryptOrHashNewPassword(pass, out salt);
|
||||
var storedPassword = provider.FormatPasswordForStorage(hashed, salt);
|
||||
|
||||
var result = provider.CheckPassword("ThisIsAHashedPassword", storedPassword);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Encrypted()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAnEncryptedPassword";
|
||||
var encrypted = provider.EncryptOrHashNewPassword(pass, out salt);
|
||||
|
||||
var result = provider.CheckPassword("ThisIsAnEncryptedPassword", encrypted);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Clear()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Clear" } });
|
||||
|
||||
var pass = "ThisIsAClearPassword";
|
||||
|
||||
var result = provider.CheckPassword("ThisIsAClearPassword", pass);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Decrypt_Password()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAnEncryptedPassword";
|
||||
var encrypted = provider.EncryptOrHashNewPassword(pass, out salt);
|
||||
|
||||
var result = provider.DecryptPassword(encrypted);
|
||||
|
||||
Assert.AreEqual(pass, result);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Hash_Algorithm_Legacy()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { {"useLegacyEncoding", "true"}, { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
var alg = provider.GetHashAlgorithm("blah");
|
||||
|
||||
Assert.IsTrue(alg is HMACSHA1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Hash_Algorithm()
|
||||
{
|
||||
var providerMock = new Mock<MembershipProviderBase>(TestHelper.GetHostingEnvironment()) { CallBase = true };
|
||||
var provider = providerMock.Object;
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
var alg = provider.GetHashAlgorithm("blah");
|
||||
|
||||
Assert.IsTrue(alg is HMACSHA256);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Tests.Membership
|
||||
{
|
||||
var memberTypeServiceMock = new Mock<IMemberTypeService>();
|
||||
memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Blah");
|
||||
var provider = new MembersMembershipProvider(Mock.Of<IMembershipMemberService>(), memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
var provider = new MembersMembershipProvider(Mock.Of<IMembershipMemberService>(), memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
|
||||
provider.Initialize("test", new NameValueCollection());
|
||||
|
||||
Assert.AreEqual("Blah", provider.DefaultMemberTypeAlias);
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Tests.Membership
|
||||
{
|
||||
var memberTypeServiceMock = new Mock<IMemberTypeService>();
|
||||
memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Blah");
|
||||
var provider = new MembersMembershipProvider(Mock.Of<IMembershipMemberService>(), memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
var provider = new MembersMembershipProvider(Mock.Of<IMembershipMemberService>(), memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
|
||||
provider.Initialize("test", new NameValueCollection { { "defaultMemberTypeAlias", "Hello" } });
|
||||
|
||||
Assert.AreEqual("Hello", provider.DefaultMemberTypeAlias);
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Tests.Membership
|
||||
var membershipServiceMock = new Mock<IMembershipMemberService>();
|
||||
membershipServiceMock.Setup(service => service.Exists("test")).Returns(true);
|
||||
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
|
||||
provider.Initialize("test", new NameValueCollection());
|
||||
|
||||
MembershipCreateStatus status;
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Tests.Membership
|
||||
var membershipServiceMock = new Mock<IMembershipMemberService>();
|
||||
membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => new Member("test", MockedContentTypes.CreateSimpleMemberType()));
|
||||
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
|
||||
provider.Initialize("test", new NameValueCollection { { "requiresUniqueEmail", "true" } });
|
||||
|
||||
MembershipCreateStatus status;
|
||||
@@ -73,73 +73,7 @@ namespace Umbraco.Tests.Membership
|
||||
|
||||
Assert.IsNull(user);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Answer_Is_Encrypted()
|
||||
{
|
||||
IMember createdMember = null;
|
||||
var memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
foreach (var p in ConventionsHelper.GetStandardPropertyTypeStubs())
|
||||
{
|
||||
memberType.AddPropertyType(p.Value);
|
||||
}
|
||||
var memberTypeServiceMock = new Mock<IMemberTypeService>();
|
||||
memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member");
|
||||
var membershipServiceMock = new Mock<IMembershipMemberService>();
|
||||
membershipServiceMock.Setup(service => service.Exists("test")).Returns(false);
|
||||
membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
|
||||
membershipServiceMock.Setup(
|
||||
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Callback((string u, string e, string p, string m, bool isApproved) =>
|
||||
{
|
||||
createdMember = new Member("test", e, u, p, memberType, isApproved);
|
||||
})
|
||||
.Returns(() => createdMember);
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
provider.Initialize("test", new NameValueCollection());
|
||||
|
||||
|
||||
MembershipCreateStatus status;
|
||||
provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status);
|
||||
|
||||
Assert.AreNotEqual("test", createdMember.RawPasswordAnswerValue);
|
||||
Assert.AreEqual(provider.EncryptString("test"), createdMember.RawPasswordAnswerValue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Password_Encrypted()
|
||||
{
|
||||
IMember createdMember = null;
|
||||
var memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
foreach (var p in ConventionsHelper.GetStandardPropertyTypeStubs())
|
||||
{
|
||||
memberType.AddPropertyType(p.Value);
|
||||
}
|
||||
var memberTypeServiceMock = new Mock<IMemberTypeService>();
|
||||
memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member");
|
||||
var membershipServiceMock = new Mock<IMembershipMemberService>();
|
||||
membershipServiceMock.Setup(service => service.Exists("test")).Returns(false);
|
||||
membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
|
||||
membershipServiceMock.Setup(
|
||||
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Callback((string u, string e, string p, string m, bool isApproved) =>
|
||||
{
|
||||
createdMember = new Member("test", e, u, p, memberType, isApproved);
|
||||
})
|
||||
.Returns(() => createdMember);
|
||||
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
|
||||
|
||||
|
||||
MembershipCreateStatus status;
|
||||
provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status);
|
||||
|
||||
Assert.AreNotEqual("test", createdMember.RawPasswordValue);
|
||||
var decrypted = provider.DecryptPassword(createdMember.RawPasswordValue);
|
||||
Assert.AreEqual("testtest$1", decrypted);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Password_Hashed_With_Salt()
|
||||
{
|
||||
@@ -162,7 +96,7 @@ namespace Umbraco.Tests.Membership
|
||||
})
|
||||
.Returns(() => createdMember);
|
||||
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, UmbracoVersion, HostingEnvironment, IpResolver);
|
||||
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
|
||||
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", "HMACSHA256" } });
|
||||
|
||||
|
||||
@@ -172,8 +106,8 @@ namespace Umbraco.Tests.Membership
|
||||
Assert.AreNotEqual("test", createdMember.RawPasswordValue);
|
||||
|
||||
string salt;
|
||||
var storedPassword = provider.StoredPassword(createdMember.RawPasswordValue, out salt);
|
||||
var hashedPassword = provider.EncryptOrHashPassword("testtest$1", salt);
|
||||
var storedPassword = provider.PasswordSecurity.StoredPassword(createdMember.RawPasswordValue, out salt);
|
||||
var hashedPassword = provider.PasswordSecurity.EncryptOrHashPassword("testtest$1", salt);
|
||||
Assert.AreEqual(hashedPassword, storedPassword);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@ namespace Umbraco.Tests.Models.Mapping
|
||||
{
|
||||
base.Compose();
|
||||
|
||||
Composition.RegisterUnique(f => Mock.Of<ICultureDictionaryFactory>());
|
||||
|
||||
Composition.Register(_ => Mock.Of<ILogger>());
|
||||
Composition.ComposeFileSystems();
|
||||
|
||||
Composition.Register(_ => Mock.Of<IDataTypeService>());
|
||||
|
||||
@@ -50,9 +50,6 @@ namespace Umbraco.Tests.Models
|
||||
member.LastLockoutDate = DateTime.Now;
|
||||
member.LastLoginDate = DateTime.Now;
|
||||
member.LastPasswordChangeDate = DateTime.Now;
|
||||
member.PasswordQuestion = "question";
|
||||
member.ProviderUserKey = Guid.NewGuid();
|
||||
member.RawPasswordAnswerValue = "raw answer";
|
||||
member.RawPasswordValue = "raw pass";
|
||||
member.SortOrder = 5;
|
||||
member.Trashed = false;
|
||||
@@ -89,9 +86,6 @@ namespace Umbraco.Tests.Models
|
||||
Assert.AreEqual(clone.Trashed, member.Trashed);
|
||||
Assert.AreEqual(clone.UpdateDate, member.UpdateDate);
|
||||
Assert.AreEqual(clone.VersionId, member.VersionId);
|
||||
Assert.AreEqual(clone.PasswordQuestion, member.PasswordQuestion);
|
||||
Assert.AreEqual(clone.ProviderUserKey, member.ProviderUserKey);
|
||||
Assert.AreEqual(clone.RawPasswordAnswerValue, member.RawPasswordAnswerValue);
|
||||
Assert.AreEqual(clone.RawPasswordValue, member.RawPasswordValue);
|
||||
Assert.AreNotSame(clone.Properties, member.Properties);
|
||||
Assert.AreEqual(clone.Properties.Count(), member.Properties.Count());
|
||||
@@ -137,9 +131,6 @@ namespace Umbraco.Tests.Models
|
||||
member.LastLockoutDate = DateTime.Now;
|
||||
member.LastLoginDate = DateTime.Now;
|
||||
member.LastPasswordChangeDate = DateTime.Now;
|
||||
member.PasswordQuestion = "question";
|
||||
member.ProviderUserKey = Guid.NewGuid();
|
||||
member.RawPasswordAnswerValue = "raw answer";
|
||||
member.RawPasswordValue = "raw pass";
|
||||
member.SortOrder = 5;
|
||||
member.Trashed = false;
|
||||
|
||||
@@ -43,9 +43,6 @@ namespace Umbraco.Tests.Models
|
||||
LastLoginDate = DateTime.Now,
|
||||
LastPasswordChangeDate = DateTime.Now,
|
||||
//Password = "test pass",
|
||||
//PasswordAnswer = "answer",
|
||||
PasswordQuestion = "question",
|
||||
//ProviderUserKey = "user key",
|
||||
SessionTimeout = 5,
|
||||
StartContentIds = new[] { 3 },
|
||||
StartMediaIds = new[] { 8 },
|
||||
@@ -88,9 +85,6 @@ namespace Umbraco.Tests.Models
|
||||
LastLoginDate = DateTime.Now,
|
||||
LastPasswordChangeDate = DateTime.Now,
|
||||
//Password = "test pass",
|
||||
//PasswordAnswer = "answer",
|
||||
PasswordQuestion = "question",
|
||||
//ProviderUserKey = "user key",
|
||||
SessionTimeout = 5,
|
||||
StartContentIds = new[] { 3 },
|
||||
StartMediaIds = new[] { 8 },
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
@@ -54,7 +55,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
private UserRepository CreateRepository(IScopeProvider provider)
|
||||
{
|
||||
var accessor = (IScopeAccessor) provider;
|
||||
var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, TestObjects.GetGlobalSettings());
|
||||
var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, TestObjects.GetGlobalSettings(), Mock.Of<IUserPasswordConfiguration>());
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -208,7 +209,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
var id = user.Id;
|
||||
|
||||
var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of<IMapperCollection>(),TestObjects.GetGlobalSettings());
|
||||
var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of<IMapperCollection>(),TestObjects.GetGlobalSettings(), Mock.Of<IUserPasswordConfiguration>());
|
||||
|
||||
repository2.Delete(user);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Runtime;
|
||||
using Umbraco.Web.Security;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
|
||||
namespace Umbraco.Tests.Routing
|
||||
{
|
||||
@@ -147,7 +148,7 @@ namespace Umbraco.Tests.Routing
|
||||
var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of<ILogger>(), context =>
|
||||
{
|
||||
var membershipHelper = new MembershipHelper(
|
||||
umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
return new CustomDocumentController(Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
Factory.GetInstance<ServiceContext>(),
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Tests.Security
|
||||
{
|
||||
[TestFixture]
|
||||
public class PasswordSecurityTests
|
||||
{
|
||||
[Test]
|
||||
public void Get_Hash_Algorithm_Legacy()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.UseLegacyEncoding == true && x.HashAlgorithmType == "HMACSHA256"));
|
||||
var alg = passwordSecurity.GetHashAlgorithm("blah");
|
||||
Assert.IsTrue(alg is HMACSHA1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Hash_Algorithm_Default()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.HashAlgorithmType == "HMACSHA256"));
|
||||
var alg = passwordSecurity.GetHashAlgorithm("blah"); // not resolved
|
||||
Assert.IsTrue(alg is HMACSHA256);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Hashed_Non_KeyedHashAlgorithm()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.HashAlgorithmType == "SHA256"));
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAHashedPassword";
|
||||
var hashed = passwordSecurity.EncryptOrHashNewPassword(pass, out salt);
|
||||
var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt);
|
||||
|
||||
var result = passwordSecurity.CheckPassword("ThisIsAHashedPassword", storedPassword);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Check_Password_Hashed_KeyedHashAlgorithm()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.HashAlgorithmType == "HMACSHA256"));
|
||||
|
||||
string salt;
|
||||
var pass = "ThisIsAHashedPassword";
|
||||
var hashed = passwordSecurity.EncryptOrHashNewPassword(pass, out salt);
|
||||
var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt);
|
||||
|
||||
var result = passwordSecurity.CheckPassword("ThisIsAHashedPassword", storedPassword);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_Pass_For_Storage_Hashed()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.HashAlgorithmType == "HMACSHA256"));
|
||||
|
||||
var salt = PasswordSecurity.GenerateSalt();
|
||||
var stored = "ThisIsAHashedPassword";
|
||||
|
||||
var result = passwordSecurity.FormatPasswordForStorage(stored, salt);
|
||||
|
||||
Assert.AreEqual(salt + "ThisIsAHashedPassword", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Stored_Password_Hashed()
|
||||
{
|
||||
var passwordSecurity = new PasswordSecurity(Mock.Of<IPasswordConfiguration>(x => x.HashAlgorithmType == "HMACSHA256"));
|
||||
|
||||
var salt = PasswordSecurity.GenerateSalt();
|
||||
var stored = salt + "ThisIsAHashedPassword";
|
||||
|
||||
string initSalt;
|
||||
var result = passwordSecurity.StoredPassword(stored, out initSalt);
|
||||
|
||||
Assert.AreEqual("ThisIsAHashedPassword", result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The salt generated is always the same length
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Check_Salt_Length()
|
||||
{
|
||||
var lastLength = 0;
|
||||
for (var i = 0; i < 10000; i++)
|
||||
{
|
||||
var result = PasswordSecurity.GenerateSalt();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
Assert.AreEqual(lastLength, result.Length);
|
||||
}
|
||||
|
||||
lastLength = result.Length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -39,14 +39,6 @@ namespace Umbraco.Tests.Services
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
// HACK: but we have no choice until we remove the SavePassword method from IMemberService
|
||||
var providerMock = new Mock<MembersMembershipProvider>(ServiceContext.MemberService, ServiceContext.MemberTypeService, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), new AspNetIpResolver()) { CallBase = true };
|
||||
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
|
||||
providerMock.Setup(@base => @base.PasswordFormat).Returns(MembershipPasswordFormat.Hashed);
|
||||
var provider = providerMock.Object;
|
||||
|
||||
((MemberService)ServiceContext.MemberService).MembershipProvider = provider;
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -73,69 +65,33 @@ namespace Umbraco.Tests.Services
|
||||
// TODO: see TODO in PublishedContentType, this list contains duplicates
|
||||
|
||||
var aliases = new[]
|
||||
{
|
||||
"umbracoMemberPasswordRetrievalQuestion",
|
||||
"umbracoMemberPasswordRetrievalAnswer",
|
||||
"umbracoMemberComments",
|
||||
"umbracoMemberFailedPasswordAttempts",
|
||||
"umbracoMemberApproved",
|
||||
"umbracoMemberLockedOut",
|
||||
"umbracoMemberLastLockoutDate",
|
||||
"umbracoMemberLastLogin",
|
||||
"umbracoMemberLastPasswordChangeDate",
|
||||
"Email",
|
||||
"Username",
|
||||
"PasswordQuestion",
|
||||
"Comments",
|
||||
"IsApproved",
|
||||
"IsLockedOut",
|
||||
"LastLockoutDate",
|
||||
"CreateDate",
|
||||
"LastLoginDate",
|
||||
"LastPasswordChangeDate"
|
||||
{
|
||||
Constants.Conventions.Member.Comments,
|
||||
Constants.Conventions.Member.FailedPasswordAttempts,
|
||||
Constants.Conventions.Member.IsApproved,
|
||||
Constants.Conventions.Member.IsLockedOut,
|
||||
Constants.Conventions.Member.LastLockoutDate,
|
||||
Constants.Conventions.Member.LastLoginDate,
|
||||
Constants.Conventions.Member.LastPasswordChangeDate,
|
||||
nameof(IMember.Email),
|
||||
nameof(IMember.Username),
|
||||
nameof(IMember.Comments),
|
||||
nameof(IMember.IsApproved),
|
||||
nameof(IMember.IsLockedOut),
|
||||
nameof(IMember.LastLockoutDate),
|
||||
nameof(IMember.CreateDate),
|
||||
nameof(IMember.LastLoginDate),
|
||||
nameof(IMember.LastPasswordChangeDate)
|
||||
};
|
||||
|
||||
var properties = pmember.Properties.ToList();
|
||||
|
||||
Assert.IsTrue(properties.Select(x => x.Alias).ContainsAll(aliases));
|
||||
|
||||
var email = properties[aliases.IndexOf("Email")];
|
||||
var email = properties[aliases.IndexOf(nameof(IMember.Email))];
|
||||
Assert.AreEqual("xemail", email.GetSourceValue());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Set_Password_On_New_Member()
|
||||
{
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
//this will construct a member without a password
|
||||
var member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "test");
|
||||
ServiceContext.MemberService.Save(member);
|
||||
|
||||
Assert.IsTrue(member.RawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix));
|
||||
|
||||
ServiceContext.MemberService.SavePassword(member, "hello123456$!");
|
||||
|
||||
var foundMember = ServiceContext.MemberService.GetById(member.Id);
|
||||
Assert.IsNotNull(foundMember);
|
||||
Assert.AreNotEqual("hello123456$!", foundMember.RawPasswordValue);
|
||||
Assert.IsFalse(member.RawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Not_Set_Password_On_Existing_Member()
|
||||
{
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
//this will construct a member with a password
|
||||
var member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "hello123456$!", "test");
|
||||
ServiceContext.MemberService.Save(member);
|
||||
|
||||
Assert.IsFalse(member.RawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix));
|
||||
|
||||
Assert.Throws<NotSupportedException>(() => ServiceContext.MemberService.SavePassword(member, "HELLO123456$!"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Member()
|
||||
{
|
||||
@@ -1118,23 +1074,6 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual(11, found);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Count_All_Online_Members()
|
||||
{
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2));
|
||||
ServiceContext.MemberService.Save(members);
|
||||
|
||||
var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello");
|
||||
customMember.SetValue(Constants.Conventions.Member.LastLoginDate, DateTime.Now);
|
||||
ServiceContext.MemberService.Save(customMember);
|
||||
|
||||
var found = ServiceContext.MemberService.GetCount(MemberCountType.Online);
|
||||
|
||||
Assert.AreEqual(9, found);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Count_All_Locked_Members()
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Umbraco.Tests.Strings
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
{
|
||||
@@ -150,7 +151,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
urlHelper.Setup(provider => provider.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
.Returns(UrlInfo.Url("/hello/world/1234"));
|
||||
|
||||
var membershipHelper = new MembershipHelper(umbCtx.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
var membershipHelper = new MembershipHelper(umbCtx.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
|
||||
var umbHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(),
|
||||
Mock.Of<ITagQuery>(),
|
||||
|
||||
@@ -152,10 +152,13 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var runtimeState = Mock.Of<IRuntimeState>();
|
||||
var idkMap = new IdkMap(scopeProvider);
|
||||
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
|
||||
var localizationService = GetLazyService<ILocalizationService>(factory, c => new LocalizationService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDictionaryRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<ILanguageRepository>(c)));
|
||||
var userService = GetLazyService<IUserService>(factory, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo<IUserRepository>(c), GetRepo<IUserGroupRepository>(c),globalSettings));
|
||||
var dataTypeService = GetLazyService<IDataTypeService>(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDataTypeRepository>(c), GetRepo<IDataTypeContainerRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<IEntityRepository>(c), GetRepo<IContentTypeRepository>(c)));
|
||||
var contentService = GetLazyService<IContentService>(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDocumentRepository>(c), GetRepo<IEntityRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<IContentTypeRepository>(c), GetRepo<IDocumentBlueprintRepository>(c), GetRepo<ILanguageRepository>(c)));
|
||||
var propertyValidationService = new Lazy<IPropertyValidationService>(() => new PropertyValidationService(propertyEditorCollection, dataTypeService.Value));
|
||||
var contentService = GetLazyService<IContentService>(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDocumentRepository>(c), GetRepo<IEntityRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<IContentTypeRepository>(c), GetRepo<IDocumentBlueprintRepository>(c), GetRepo<ILanguageRepository>(c), propertyValidationService));
|
||||
var notificationService = GetLazyService<INotificationService>(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo<INotificationsRepository>(c), globalSettings, umbracoSettings.Content));
|
||||
var serverRegistrationService = GetLazyService<IServerRegistrationService>(factory, c => new ServerRegistrationService(scopeProvider, logger, eventMessagesFactory, GetRepo<IServerRegistrationRepository>(c)));
|
||||
var memberGroupService = GetLazyService<IMemberGroupService>(factory, c => new MemberGroupService(scopeProvider, logger, eventMessagesFactory, GetRepo<IMemberGroupRepository>(c)));
|
||||
@@ -170,8 +173,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
var macroService = GetLazyService<IMacroService>(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo<IMacroRepository>(c), GetRepo<IAuditRepository>(c)));
|
||||
var packagingService = GetLazyService<IPackagingService>(factory, c =>
|
||||
{
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
{
|
||||
var compiledPackageXmlParser = new CompiledPackageXmlParser(new ConflictingPackageData(macroService.Value, fileService.Value), globalSettings);
|
||||
return new PackagingService(
|
||||
auditService.Value,
|
||||
|
||||
@@ -22,6 +22,7 @@ using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
@@ -70,7 +71,7 @@ namespace Umbraco.Tests.Testing.TestingTests
|
||||
Mock.Of<ICultureDictionaryFactory>(),
|
||||
Mock.Of<IUmbracoComponentRenderer>(),
|
||||
Mock.Of<IPublishedContentQuery>(),
|
||||
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>()));
|
||||
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>()));
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
@@ -98,12 +99,15 @@ namespace Umbraco.Tests.Testing.TestingTests
|
||||
{
|
||||
var umbracoContext = TestObjects.GetUmbracoContextMock();
|
||||
|
||||
var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
var logger = Mock.Of<IProfilingLogger>();
|
||||
var memberService = Mock.Of<IMemberService>();
|
||||
var memberTypeService = Mock.Of<IMemberTypeService>();
|
||||
var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of<IUmbracoVersion>());
|
||||
var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), membershipProvider, Mock.Of<RoleProvider>(), memberService, memberTypeService, Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, logger);
|
||||
var umbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper);
|
||||
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }));
|
||||
|
||||
// ReSharper disable once UnusedVariable
|
||||
var umbracoApiController = new FakeUmbracoApiController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), Mock.Of<ISqlContext>(), ServiceContext.CreatePartial(), AppCaches.NoCache, Mock.Of<IProfilingLogger>(), Mock.Of<IRuntimeState>(), umbracoHelper, umbracoMapper);
|
||||
|
||||
var umbracoApiController = new FakeUmbracoApiController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), Mock.Of<ISqlContext>(), ServiceContext.CreatePartial(), AppCaches.NoCache, logger, Mock.Of<IRuntimeState>(), umbracoHelper, umbracoMapper);
|
||||
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ using Umbraco.Web.Hosting;
|
||||
using Umbraco.Web.Sections;
|
||||
using Current = Umbraco.Core.Composing.Current;
|
||||
using FileSystems = Umbraco.Core.IO.FileSystems;
|
||||
using Umbraco.Core.Dictionary;
|
||||
|
||||
namespace Umbraco.Tests.Testing
|
||||
{
|
||||
@@ -136,7 +137,7 @@ namespace Umbraco.Tests.Testing
|
||||
// get/merge the attributes marking the method and/or the classes
|
||||
Options = TestOptionAttributeBase.GetTestOptions<UmbracoTestAttribute>();
|
||||
|
||||
// FIXME: align to runtimes & components - don't redo everything here
|
||||
// FIXME: align to runtimes & components - don't redo everything here !!!! Yes this is getting painful
|
||||
|
||||
var (logger, profiler) = GetLoggers(Options.Logger);
|
||||
var proflogger = new ProfilingLogger(logger, profiler);
|
||||
@@ -245,7 +246,8 @@ namespace Umbraco.Tests.Testing
|
||||
Composition.RegisterUnique<IContentLastChanceFinder, TestLastChanceFinder>();
|
||||
Composition.RegisterUnique<IVariationContextAccessor, TestVariationContextAccessor>();
|
||||
Composition.RegisterUnique<IPublishedSnapshotAccessor, TestPublishedSnapshotAccessor>();
|
||||
|
||||
Composition.SetCultureDictionaryFactory<DefaultCultureDictionaryFactory>();
|
||||
Composition.Register(f => f.GetInstance<ICultureDictionaryFactory>().CreateDictionary(), Lifetime.Singleton);
|
||||
// register back office sections in the order we want them rendered
|
||||
Composition.WithCollectionBuilder<SectionCollectionBuilder>().Append<ContentSection>()
|
||||
.Append<MediaSection>()
|
||||
@@ -334,6 +336,7 @@ namespace Umbraco.Tests.Testing
|
||||
{
|
||||
Composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings);
|
||||
Composition.Configs.Add(SettingsForTests.GetDefaultGlobalSettings);
|
||||
//Composition.Configs.Add<IUserPasswordConfiguration>(() => new DefaultUserPasswordConfig());
|
||||
}
|
||||
|
||||
protected virtual void ComposeApplication(bool withApplication)
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
<Compile Include="Routing\RoutableDocumentFilterTests.cs" />
|
||||
<Compile Include="Runtimes\StandaloneTests.cs" />
|
||||
<Compile Include="Routing\GetContentUrlsTests.cs" />
|
||||
<Compile Include="Security\PasswordSecurityTests.cs" />
|
||||
<Compile Include="Services\AmbiguousEventTests.cs" />
|
||||
<Compile Include="Services\ContentServiceEventTests.cs" />
|
||||
<Compile Include="Services\ContentServicePublishBranchTests.cs" />
|
||||
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -75,6 +76,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
}
|
||||
IOHelper.ForceNotHosted = true;
|
||||
var usersController = new AuthenticationController(
|
||||
new DefaultUserPasswordConfig(),
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
Factory.GetInstance<ISqlContext>(),
|
||||
@@ -82,7 +84,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<AppCaches>(),
|
||||
Factory.GetInstance<IProfilingLogger>(),
|
||||
Factory.GetInstance<IRuntimeState>(),
|
||||
helper);
|
||||
helper,
|
||||
Factory.GetInstance<UmbracoMapper>());
|
||||
return usersController;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
@@ -260,6 +258,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
@@ -293,6 +292,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
{
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
@@ -334,6 +334,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
@@ -380,6 +381,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
@@ -418,6 +420,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
@@ -462,6 +465,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
|
||||
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
|
||||
var controller = new ContentController(
|
||||
Factory.GetInstance<ICultureDictionary>(),
|
||||
propertyEditorCollection,
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
|
||||
@@ -20,6 +20,7 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
namespace Umbraco.Tests.Web.Mvc
|
||||
@@ -120,7 +121,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
Mock.Of<ICultureDictionaryFactory>(),
|
||||
Mock.Of<IUmbracoComponentRenderer>(),
|
||||
Mock.Of<IPublishedContentQuery>(query => query.Content(2) == content.Object),
|
||||
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>()));
|
||||
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>()));
|
||||
|
||||
var ctrl = new TestSurfaceController(umbracoContextAccessor, helper);
|
||||
var result = ctrl.GetContent(2) as PublishedContentResult;
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@
|
||||
$location.search('invite', null);
|
||||
}),
|
||||
//get the membership provider config for password policies
|
||||
authResource.getMembershipProviderConfig().then(function (data) {
|
||||
authResource.getPasswordConfig().then(function (data) {
|
||||
vm.invitedUserPasswordModel.passwordPolicies = data;
|
||||
|
||||
//localize the text
|
||||
|
||||
@@ -198,18 +198,18 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.currentUserResource#getMembershipProviderConfig
|
||||
* @name umbraco.resources.currentUserResource#getPasswordConfig
|
||||
* @methodOf umbraco.resources.currentUserResource
|
||||
*
|
||||
* @description
|
||||
* Gets the configuration of the user membership provider which is used to configure the change password form
|
||||
*/
|
||||
getMembershipProviderConfig: function () {
|
||||
getPasswordConfig: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"authenticationApiBaseUrl",
|
||||
"GetMembershipProviderConfig")),
|
||||
"GetPasswordConfig")),
|
||||
'Failed to retrieve membership provider config');
|
||||
},
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ angular.module("umbraco")
|
||||
};
|
||||
|
||||
//go get the config for the membership provider and add it to the model
|
||||
authResource.getMembershipProviderConfig().then(function(data) {
|
||||
authResource.getPasswordConfig().then(function(data) {
|
||||
$scope.changePasswordModel.config = data;
|
||||
//ensure the hasPassword config option is set to true (the user of course has a password already assigned)
|
||||
//this will ensure the oldPassword is shown so they can change it
|
||||
|
||||
@@ -122,10 +122,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
}
|
||||
|
||||
function setHeaderNameState(content) {
|
||||
|
||||
if(content.membershipScenario === 0) {
|
||||
$scope.page.nameLocked = true;
|
||||
}
|
||||
$scope.page.nameLocked = true;
|
||||
}
|
||||
|
||||
/** Just shows a simple notification that there are client side validation issues to be fixed */
|
||||
@@ -151,7 +148,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
//anytime a user is changing a member's password without the oldPassword, we are in effect resetting it so we need to set that flag here
|
||||
var passwordProp = _.find(contentEditingHelper.getAllProps($scope.content), function (e) { return e.alias === '_umb_password' });
|
||||
if (passwordProp && passwordProp.value && (typeof passwordProp.value.reset !== 'undefined') && !passwordProp.value.reset) {
|
||||
//so if the admin is not explicitly resetting the password, flag it for resetting if a new password is being entered
|
||||
// if the admin is not explicitly resetting the password, flag it for resetting if a new password is being entered
|
||||
passwordProp.value.reset = !passwordProp.value.oldPassword && passwordProp.config.allowManuallyChangingPassword;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
vm.usernameIsEmail = Umbraco.Sys.ServerVariables.umbracoSettings.usernameIsEmail && user.email === user.username;
|
||||
|
||||
//go get the config for the membership provider and add it to the model
|
||||
authResource.getMembershipProviderConfig().then(function (data) {
|
||||
authResource.getPasswordConfig().then(function (data) {
|
||||
vm.changePasswordModel.config = data;
|
||||
|
||||
//the user has a password if they are not states: Invited, NoCredentials
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
|
||||
<system.web>
|
||||
<compilation debug="true" xdt:Transform="SetAttributes(debug)" />
|
||||
|
||||
<membership>
|
||||
<providers>
|
||||
<add name="UsersMembershipProvider" xdt:Transform="Remove" xdt:Locator="Match(name)" />
|
||||
</providers>
|
||||
</membership>
|
||||
</system.web>
|
||||
|
||||
<runtime>
|
||||
|
||||
@@ -121,7 +121,6 @@
|
||||
<providers>
|
||||
<clear />
|
||||
<add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco.Web" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="10" useLegacyEncoding="false" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" allowManuallyChangingPassword="false" />
|
||||
<add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web" />
|
||||
</providers>
|
||||
</membership>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Controllers
|
||||
{
|
||||
@@ -26,12 +27,6 @@ namespace Umbraco.Web.Controllers
|
||||
[ValidateUmbracoFormRouteString]
|
||||
public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model)
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("Profile editing with the " + typeof(UmbProfileController) + " is not supported when not using the default Umbraco membership provider");
|
||||
}
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return CurrentUmbracoPage();
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Umbraco.Web.Dictionary
|
||||
{
|
||||
/// <summary>
|
||||
/// A culture dictionary factory used to create an Umbraco.Core.Dictionary.ICultureDictionary.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the future this will allow use to potentially store dictionary items elsewhere and allows for maximum flexibility.
|
||||
/// </remarks>
|
||||
internal class DefaultCultureDictionaryFactory : Umbraco.Core.Dictionary.ICultureDictionaryFactory
|
||||
{
|
||||
public Umbraco.Core.Dictionary.ICultureDictionary CreateDictionary()
|
||||
{
|
||||
return new DefaultCultureDictionary();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Web.Composing;
|
||||
using IUser = Umbraco.Core.Models.Membership.IUser;
|
||||
using Umbraco.Core.Mapping;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -40,10 +41,12 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
|
||||
private BackOfficeSignInManager _signInManager;
|
||||
private readonly IUserPasswordConfiguration _passwordConfiguration;
|
||||
|
||||
public AuthenticationController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public AuthenticationController(IUserPasswordConfiguration passwordConfiguration, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, UmbracoMapper umbracoMapper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, umbracoMapper)
|
||||
{
|
||||
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
|
||||
}
|
||||
|
||||
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager => _userManager
|
||||
@@ -57,12 +60,9 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[WebApi.UmbracoAuthorize(requireApproval: false)]
|
||||
public IDictionary<string, object> GetMembershipProviderConfig()
|
||||
public IDictionary<string, object> GetPasswordConfig()
|
||||
{
|
||||
// TODO: Check if the current PasswordValidator is an IMembershipProviderPasswordValidator, if
|
||||
// it's not than we should return some generic defaults
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider();
|
||||
return provider.GetConfiguration(Services.UserService);
|
||||
return _passwordConfiguration.GetConfiguration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.Linq;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Editors.Binders
|
||||
{
|
||||
@@ -66,49 +67,7 @@ namespace Umbraco.Web.Editors.Binders
|
||||
/// <returns></returns>
|
||||
private IMember GetExisting(MemberSave model)
|
||||
{
|
||||
var scenario = _services.MemberTypeService.GetMembershipScenario();
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
switch (scenario)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
return GetExisting(model.Key);
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
default:
|
||||
var membershipUser = provider.GetUser(model.Key, false);
|
||||
if (membershipUser == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find member with key " + model.Key);
|
||||
}
|
||||
|
||||
// TODO: Support this scenario!
|
||||
//if (scenario == MembershipScenario.CustomProviderWithUmbracoLink)
|
||||
//{
|
||||
// //if there's a 'Member' type then we should be able to just go get it from the db since it was created with a link
|
||||
// // to our data.
|
||||
// var memberType = ApplicationContext.Services.MemberTypeService.GetMemberType(Constants.Conventions.MemberTypes.Member);
|
||||
// if (memberType != null)
|
||||
// {
|
||||
// var existing = GetExisting(model.Key);
|
||||
// FilterContentTypeProperties(existing.ContentType, existing.ContentType.PropertyTypes.Select(x => x.Alias).ToArray());
|
||||
// }
|
||||
//}
|
||||
|
||||
//generate a member for a generic membership provider
|
||||
//NOTE: We don't care about the password here, so just generate something
|
||||
//var member = MemberService.CreateGenericMembershipProviderMember(model.Name, model.Email, model.Username, Guid.NewGuid().ToString("N"));
|
||||
|
||||
//var convertResult = membershipUser.ProviderUserKey.TryConvertTo<Guid>();
|
||||
//if (convertResult.Success == false)
|
||||
//{
|
||||
// throw new InvalidOperationException("Only membership providers that store a GUID as their ProviderUserKey are supported" + model.Key);
|
||||
//}
|
||||
//member.Key = convertResult.Result;
|
||||
|
||||
var member = Current.Mapper.Map<MembershipUser, IMember>(membershipUser);
|
||||
|
||||
return member;
|
||||
}
|
||||
return GetExisting(model.Key);
|
||||
}
|
||||
|
||||
private IMember GetExisting(Guid key)
|
||||
@@ -132,46 +91,17 @@ namespace Umbraco.Web.Editors.Binders
|
||||
/// </remarks>
|
||||
private IMember CreateNew(MemberSave model)
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
if (provider.IsUmbracoMembershipProvider())
|
||||
var contentType = _services.MemberTypeService.Get(model.ContentTypeAlias);
|
||||
if (contentType == null)
|
||||
{
|
||||
var contentType = _services.MemberTypeService.Get(model.ContentTypeAlias);
|
||||
if (contentType == null)
|
||||
{
|
||||
throw new InvalidOperationException("No member type found with alias " + model.ContentTypeAlias);
|
||||
}
|
||||
|
||||
//remove all membership properties, these values are set with the membership provider.
|
||||
FilterMembershipProviderProperties(contentType);
|
||||
|
||||
//return the new member with the details filled in
|
||||
return new Member(model.Name, model.Email, model.Username, model.Password.NewPassword, contentType);
|
||||
throw new InvalidOperationException("No member type found with alias " + model.ContentTypeAlias);
|
||||
}
|
||||
else
|
||||
{
|
||||
//A custom membership provider is configured
|
||||
|
||||
//NOTE: Below we are assigning the password to just a new GUID because we are not actually storing the password, however that
|
||||
// field is mandatory in the database so we need to put something there.
|
||||
//remove all membership properties, these values are set with the membership provider.
|
||||
FilterMembershipProviderProperties(contentType);
|
||||
|
||||
//If the default Member type exists, we'll use that to create the IMember - that way we can associate the custom membership
|
||||
// provider to our data - eventually we can support editing custom properties with a custom provider.
|
||||
var memberType = _services.MemberTypeService.Get(Constants.Conventions.MemberTypes.DefaultAlias);
|
||||
if (memberType != null)
|
||||
{
|
||||
FilterContentTypeProperties(memberType, memberType.PropertyTypes.Select(x => x.Alias).ToArray());
|
||||
return new Member(model.Name, model.Email, model.Username, Guid.NewGuid().ToString("N"), memberType);
|
||||
}
|
||||
|
||||
//generate a member for a generic membership provider
|
||||
var member = MemberService.CreateGenericMembershipProviderMember(model.Name, model.Email, model.Username, Guid.NewGuid().ToString("N"));
|
||||
//we'll just remove all properties here otherwise we'll end up with validation errors, we don't want to persist any property data anyways
|
||||
// in this case.
|
||||
memberType = _services.MemberTypeService.Get(member.ContentTypeId);
|
||||
FilterContentTypeProperties(memberType, memberType.PropertyTypes.Select(x => x.Alias).ToArray());
|
||||
return member;
|
||||
}
|
||||
//return the new member with the details filled in
|
||||
return new Member(model.Name, model.Email, model.Username, model.Password.NewPassword, contentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,7 +15,6 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
@@ -37,6 +36,7 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Routing;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Core.Dictionary;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -57,8 +57,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public object Domains { get; private set; }
|
||||
|
||||
public ContentController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public ContentController(ICultureDictionary cultureDictionary, PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
|
||||
_allLangs = new Lazy<IDictionary<string, ILanguage>>(() => Services.LocalizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase));
|
||||
@@ -357,10 +357,10 @@ namespace Umbraco.Web.Editors
|
||||
var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0));
|
||||
var mapped = MapToDisplay(emptyContent);
|
||||
// translate the content type name if applicable
|
||||
mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(mapped.ContentTypeName);
|
||||
mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.ContentTypeName);
|
||||
// if your user type doesn't have access to the Settings section it would not get this property mapped
|
||||
if (mapped.DocumentType != null)
|
||||
mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(mapped.DocumentType.Name);
|
||||
mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.DocumentType.Name);
|
||||
|
||||
//remove the listview app if it exists
|
||||
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();
|
||||
@@ -2309,28 +2309,11 @@ namespace Umbraco.Web.Editors
|
||||
.Where(rule => rule.RuleType == Constants.Conventions.PublicAccess.MemberUsernameRuleType)
|
||||
.Select(rule => rule.RuleValue).ToArray();
|
||||
|
||||
MemberDisplay[] members;
|
||||
switch (Services.MemberTypeService.GetMembershipScenario())
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
members = usernames
|
||||
.Select(username => Services.MemberService.GetByUsername(username))
|
||||
.Where(member => member != null)
|
||||
.Select(Mapper.Map<MemberDisplay>)
|
||||
.ToArray();
|
||||
break;
|
||||
// TODO: test support custom membership providers
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
default:
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
members = usernames
|
||||
.Select(username => provider.GetUser(username, false))
|
||||
.Where(membershipUser => membershipUser != null)
|
||||
.Select(Mapper.Map<MembershipUser, MemberDisplay>)
|
||||
.ToArray();
|
||||
break;
|
||||
}
|
||||
var members = usernames
|
||||
.Select(username => Services.MemberService.GetByUsername(username))
|
||||
.Where(member => member != null)
|
||||
.Select(Mapper.Map<MemberDisplay>)
|
||||
.ToArray();
|
||||
|
||||
var allGroups = Services.MemberGroupService.GetAll().ToArray();
|
||||
var groups = entry.Rules
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Web.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
@@ -26,9 +27,12 @@ namespace Umbraco.Web.Editors
|
||||
[JsonDateTimeFormatAttribute]
|
||||
public abstract class ContentControllerBase : BackOfficeNotificationsController
|
||||
{
|
||||
protected ContentControllerBase(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
protected ICultureDictionary CultureDictionary { get; }
|
||||
|
||||
protected ContentControllerBase(ICultureDictionary cultureDictionary, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
CultureDictionary = cultureDictionary;
|
||||
}
|
||||
|
||||
protected HttpResponseMessage HandleContentNotFound(object id, bool throwException = true)
|
||||
|
||||
@@ -52,14 +52,14 @@ namespace Umbraco.Web.Editors
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
|
||||
public ContentTypeController(IEntityXmlSerializer serializer,
|
||||
ICultureDictionaryFactory cultureDictionaryFactory,
|
||||
ICultureDictionary cultureDictionary,
|
||||
IGlobalSettings globalSettings,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ISqlContext sqlContext, PropertyEditorCollection propertyEditors,
|
||||
ServiceContext services, AppCaches appCaches,
|
||||
IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper,
|
||||
IScopeProvider scopeProvider)
|
||||
: base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
_serializer = serializer;
|
||||
_propertyEditors = propertyEditors;
|
||||
@@ -438,8 +438,8 @@ namespace Umbraco.Web.Editors
|
||||
var localizedTextService = Services.TextService;
|
||||
foreach (var basic in basics)
|
||||
{
|
||||
basic.Name = localizedTextService.UmbracoDictionaryTranslate(basic.Name);
|
||||
basic.Description = localizedTextService.UmbracoDictionaryTranslate(basic.Description);
|
||||
basic.Name = localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, basic.Name);
|
||||
basic.Description = localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, basic.Description);
|
||||
}
|
||||
|
||||
//map the blueprints
|
||||
|
||||
@@ -28,16 +28,13 @@ namespace Umbraco.Web.Editors
|
||||
public abstract class ContentTypeControllerBase<TContentType> : UmbracoAuthorizedJsonController
|
||||
where TContentType : class, IContentTypeComposition
|
||||
{
|
||||
private readonly ICultureDictionaryFactory _cultureDictionaryFactory;
|
||||
private ICultureDictionary _cultureDictionary;
|
||||
|
||||
protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
protected ContentTypeControllerBase(ICultureDictionary cultureDictionary, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
_cultureDictionaryFactory = cultureDictionaryFactory;
|
||||
CultureDictionary = cultureDictionary;
|
||||
}
|
||||
|
||||
|
||||
protected ICultureDictionary CultureDictionary { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the available composite content types for a given content type
|
||||
@@ -551,9 +548,6 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
forDisplay.Errors = ModelState.ToErrorDictionary();
|
||||
return new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
|
||||
}
|
||||
|
||||
private ICultureDictionary CultureDictionary
|
||||
=> _cultureDictionary ?? (_cultureDictionary = _cultureDictionaryFactory.CreateDictionary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Editors.Filters
|
||||
{
|
||||
@@ -52,7 +53,7 @@ namespace Umbraco.Web.Editors.Filters
|
||||
}
|
||||
|
||||
//default provider!
|
||||
var membershipProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
var membershipProvider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
var validEmail = ValidateUniqueEmail(model, membershipProvider);
|
||||
if (validEmail == false)
|
||||
|
||||
@@ -36,6 +36,7 @@ using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Editors.Binders;
|
||||
using Umbraco.Web.Editors.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Core.Dictionary;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -48,8 +49,8 @@ namespace Umbraco.Web.Editors
|
||||
[MediaControllerControllerConfiguration]
|
||||
public class MediaController : ContentControllerBase
|
||||
{
|
||||
public MediaController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public MediaController(ICultureDictionary cultureDictionary, PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace Umbraco.Web.Editors
|
||||
[MediaTypeControllerControllerConfiguration]
|
||||
public class MediaTypeController : ContentTypeControllerBase<IMediaType>
|
||||
{
|
||||
public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public MediaTypeController(ICultureDictionary cultureDictionary, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Editors.Binders;
|
||||
using Umbraco.Web.Editors.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -38,27 +40,19 @@ namespace Umbraco.Web.Editors
|
||||
/// access to ALL of the methods on this controller will need access to the member application.
|
||||
/// </remarks>
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Members)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Members)]
|
||||
[OutgoingNoHyphenGuidFormat]
|
||||
public class MemberController : ContentControllerBase
|
||||
{
|
||||
public MemberController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public MemberController(ICultureDictionary cultureDictionary, PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
|
||||
}
|
||||
|
||||
private readonly MembershipProvider _provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
private readonly MembershipProvider _provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the currently configured membership scenario for members in umbraco
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
protected MembershipScenario MembershipScenario
|
||||
{
|
||||
get { return Services.MemberTypeService.GetMembershipScenario(); }
|
||||
}
|
||||
|
||||
public PagedResult<MemberBasic> GetPagedResults(
|
||||
int pageNumber = 1,
|
||||
@@ -75,57 +69,19 @@ namespace Umbraco.Web.Editors
|
||||
throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
if (MembershipScenario == MembershipScenario.NativeUmbraco)
|
||||
{
|
||||
var members = Services.MemberService
|
||||
var members = Services.MemberService
|
||||
.GetAll((pageNumber - 1), pageSize, out var totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<MemberBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = members
|
||||
.Select(x => Mapper.Map<MemberBasic>(x))
|
||||
};
|
||||
return pagedResult;
|
||||
}
|
||||
else
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
int totalRecords;
|
||||
|
||||
MembershipUserCollection members;
|
||||
if (filter.IsNullOrWhiteSpace())
|
||||
{
|
||||
members = _provider.GetAllUsers((pageNumber - 1), pageSize, out totalRecords);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we need to search!
|
||||
|
||||
//try by name first
|
||||
members = _provider.FindUsersByName(filter, (pageNumber - 1), pageSize, out totalRecords);
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
//try by email then
|
||||
members = _provider.FindUsersByEmail(filter, (pageNumber - 1), pageSize, out totalRecords);
|
||||
}
|
||||
}
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<MemberBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = members
|
||||
.Cast<MembershipUser>()
|
||||
.Select(Mapper.Map<MembershipUser, MemberBasic>)
|
||||
};
|
||||
return pagedResult;
|
||||
return new PagedResult<MemberBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = members
|
||||
.Select(x => Mapper.Map<MemberBasic>(x))
|
||||
};
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -165,48 +121,12 @@ namespace Umbraco.Web.Editors
|
||||
[OutgoingEditorModelEvent]
|
||||
public MemberDisplay GetByKey(Guid key)
|
||||
{
|
||||
MembershipUser foundMembershipMember;
|
||||
MemberDisplay display;
|
||||
IMember foundMember;
|
||||
switch (MembershipScenario)
|
||||
var foundMember = Services.MemberService.GetByKey(key);
|
||||
if (foundMember == null)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
foundMember = Services.MemberService.GetByKey(key);
|
||||
if (foundMember == null)
|
||||
{
|
||||
HandleContentNotFound(key);
|
||||
}
|
||||
return Mapper.Map<MemberDisplay>(foundMember);
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
|
||||
// TODO: Support editing custom properties for members with a custom membership provider here.
|
||||
|
||||
//foundMember = Services.MemberService.GetByKey(key);
|
||||
//if (foundMember == null)
|
||||
//{
|
||||
// HandleContentNotFound(key);
|
||||
//}
|
||||
//foundMembershipMember = Membership.GetUser(key, false);
|
||||
//if (foundMembershipMember == null)
|
||||
//{
|
||||
// HandleContentNotFound(key);
|
||||
//}
|
||||
|
||||
//display = Mapper.Map<MembershipUser, MemberDisplay>(foundMembershipMember);
|
||||
////map the name over
|
||||
//display.Name = foundMember.Name;
|
||||
//return display;
|
||||
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
default:
|
||||
foundMembershipMember = _provider.GetUser(key, false);
|
||||
if (foundMembershipMember == null)
|
||||
{
|
||||
HandleContentNotFound(key);
|
||||
}
|
||||
display = Mapper.Map<MembershipUser, MemberDisplay>(foundMembershipMember);
|
||||
return display;
|
||||
HandleContentNotFound(key);
|
||||
}
|
||||
return Mapper.Map<MemberDisplay>(foundMember);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -218,35 +138,22 @@ namespace Umbraco.Web.Editors
|
||||
public MemberDisplay GetEmpty(string contentTypeAlias = null)
|
||||
{
|
||||
IMember emptyContent;
|
||||
switch (MembershipScenario)
|
||||
if (contentTypeAlias == null)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
if (contentTypeAlias == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var contentType = Services.MemberTypeService.Get(contentTypeAlias);
|
||||
if (contentType == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
emptyContent = new Member(contentType);
|
||||
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(provider.MinRequiredPasswordLength, provider.MinRequiredNonAlphanumericCharacters);
|
||||
return Mapper.Map<MemberDisplay>(emptyContent);
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
// TODO: Support editing custom properties for members with a custom membership provider here.
|
||||
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
default:
|
||||
//we need to return a scaffold of a 'simple' member - basically just what a membership provider can edit
|
||||
emptyContent = MemberService.CreateGenericMembershipProviderMember("", "", "", "");
|
||||
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters);
|
||||
return Mapper.Map<MemberDisplay>(emptyContent);
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var contentType = Services.MemberTypeService.Get(contentTypeAlias);
|
||||
if (contentType == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
emptyContent = new Member(contentType);
|
||||
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(provider.MinRequiredPasswordLength, provider.MinRequiredNonAlphanumericCharacters);
|
||||
return Mapper.Map<MemberDisplay>(emptyContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -268,18 +175,6 @@ namespace Umbraco.Web.Editors
|
||||
// * we have a reference to the DTO object and the persisted object
|
||||
// * Permissions are valid
|
||||
|
||||
//This is a special case for when we're not using the umbraco membership provider - when this is the case
|
||||
// we will not have a ContentTypeAlias set which means the model state will be invalid but we don't care about that
|
||||
// so we'll remove that model state value
|
||||
if (MembershipScenario != MembershipScenario.NativeUmbraco)
|
||||
{
|
||||
ModelState.Remove("ContentTypeAlias");
|
||||
|
||||
// TODO: We're removing this because we are not displaying it but when we support the CustomProviderWithUmbracoLink scenario
|
||||
// we will be able to have a real name associated so do not remove this state once that is implemented!
|
||||
ModelState.Remove("Name");
|
||||
}
|
||||
|
||||
//map the properties to the persisted entity
|
||||
MapPropertyValues(contentItem);
|
||||
|
||||
@@ -334,17 +229,13 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
//save the IMember -
|
||||
// TODO: When we support the CustomProviderWithUmbracoLink scenario, we'll need to save the custom properties for that here too
|
||||
if (MembershipScenario == MembershipScenario.NativeUmbraco)
|
||||
{
|
||||
//save the item
|
||||
//NOTE: We are setting the password to NULL - this indicates to the system to not actually save the password
|
||||
// so it will not get overwritten!
|
||||
contentItem.PersistedContent.RawPasswordValue = null;
|
||||
//save the item
|
||||
//NOTE: We are setting the password to NULL - this indicates to the system to not actually save the password
|
||||
// so it will not get overwritten!
|
||||
contentItem.PersistedContent.RawPasswordValue = null;
|
||||
|
||||
//create/save the IMember
|
||||
Services.MemberService.Save(contentItem.PersistedContent);
|
||||
}
|
||||
//create/save the IMember
|
||||
Services.MemberService.Save(contentItem.PersistedContent);
|
||||
|
||||
//Now let's do the role provider stuff - now that we've saved the content item (that is important since
|
||||
// if we are changing the username, it must be persisted before looking up the member roles).
|
||||
@@ -560,26 +451,14 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var currProps = contentItem.PersistedContent.Properties.ToArray();
|
||||
|
||||
switch (MembershipScenario)
|
||||
switch (lookup)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
switch (lookup)
|
||||
{
|
||||
case LookupType.ByKey:
|
||||
//Go and re-fetch the persisted item
|
||||
contentItem.PersistedContent = Services.MemberService.GetByKey(contentItem.Key);
|
||||
break;
|
||||
case LookupType.ByUserName:
|
||||
contentItem.PersistedContent = Services.MemberService.GetByUsername(contentItem.Username.Trim());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
default:
|
||||
var membershipUser = _provider.GetUser(contentItem.Key, false);
|
||||
case LookupType.ByKey:
|
||||
//Go and re-fetch the persisted item
|
||||
contentItem.PersistedContent = Mapper.Map<MembershipUser, IMember>(membershipUser);
|
||||
contentItem.PersistedContent = Services.MemberService.GetByKey(contentItem.Key);
|
||||
break;
|
||||
case LookupType.ByUserName:
|
||||
contentItem.PersistedContent = Services.MemberService.GetByUsername(contentItem.Username.Trim());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -643,59 +522,16 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
MembershipUser membershipUser;
|
||||
|
||||
switch (MembershipScenario)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
//We are using the umbraco membership provider, create the member using the membership provider first.
|
||||
var umbracoMembershipProvider = (UmbracoMembershipProviderBase)_provider;
|
||||
// TODO: We are not supporting q/a - passing in empty here
|
||||
membershipUser = umbracoMembershipProvider.CreateUser(
|
||||
contentItem.ContentTypeAlias, contentItem.Username,
|
||||
contentItem.Password.NewPassword,
|
||||
contentItem.Email, "", "",
|
||||
contentItem.IsApproved,
|
||||
Guid.NewGuid(), //since it's the umbraco provider, the user key here doesn't make any difference
|
||||
out status);
|
||||
|
||||
break;
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
//We are using a custom membership provider, we'll create an empty IMember first to get the unique id to use
|
||||
// as the provider user key.
|
||||
//create it - this persisted item has already been set in the MemberBinder based on the 'Member' member type:
|
||||
Services.MemberService.Save(contentItem.PersistedContent);
|
||||
|
||||
// TODO: We are not supporting q/a - passing in empty here
|
||||
membershipUser = _provider.CreateUser(
|
||||
contentItem.Username,
|
||||
contentItem.Password.NewPassword,
|
||||
contentItem.Email,
|
||||
"TEMP", //some membership provider's require something here even if q/a is disabled!
|
||||
"TEMP", //some membership provider's require something here even if q/a is disabled!
|
||||
contentItem.IsApproved,
|
||||
contentItem.PersistedContent.Key, //custom membership provider, we'll link that based on the IMember unique id (GUID)
|
||||
out status);
|
||||
|
||||
break;
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
// we don't have a member type to use so we will just create the basic membership user with the provider with no
|
||||
// link back to the umbraco data
|
||||
|
||||
var newKey = Guid.NewGuid();
|
||||
// TODO: We are not supporting q/a - passing in empty here
|
||||
membershipUser = _provider.CreateUser(
|
||||
contentItem.Username,
|
||||
contentItem.Password.NewPassword,
|
||||
contentItem.Email,
|
||||
"TEMP", //some membership provider's require something here even if q/a is disabled!
|
||||
"TEMP", //some membership provider's require something here even if q/a is disabled!
|
||||
contentItem.IsApproved,
|
||||
newKey,
|
||||
out status);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
//We are using the umbraco membership provider, create the member using the membership provider first.
|
||||
var umbracoMembershipProvider = (UmbracoMembershipProviderBase)_provider;
|
||||
// TODO: We are not supporting q/a - passing in empty here
|
||||
membershipUser = umbracoMembershipProvider.CreateUser(
|
||||
contentItem.ContentTypeAlias, contentItem.Username,
|
||||
contentItem.Password.NewPassword,
|
||||
contentItem.Email, "", "",
|
||||
contentItem.IsApproved,
|
||||
Guid.NewGuid(), //since it's the umbraco provider, the user key here doesn't make any difference
|
||||
out status);
|
||||
|
||||
// TODO: Localize these!
|
||||
switch (status)
|
||||
@@ -776,40 +612,12 @@ namespace Umbraco.Web.Editors
|
||||
[HttpPost]
|
||||
public HttpResponseMessage DeleteByKey(Guid key)
|
||||
{
|
||||
IMember foundMember;
|
||||
MembershipUser foundMembershipUser;
|
||||
switch (MembershipScenario)
|
||||
var foundMember = Services.MemberService.GetByKey(key);
|
||||
if (foundMember == null)
|
||||
{
|
||||
case MembershipScenario.NativeUmbraco:
|
||||
foundMember = Services.MemberService.GetByKey(key);
|
||||
if (foundMember == null)
|
||||
{
|
||||
return HandleContentNotFound(key, false);
|
||||
}
|
||||
Services.MemberService.Delete(foundMember);
|
||||
break;
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
foundMember = Services.MemberService.GetByKey(key);
|
||||
if (foundMember != null)
|
||||
{
|
||||
Services.MemberService.Delete(foundMember);
|
||||
}
|
||||
foundMembershipUser = _provider.GetUser(key, false);
|
||||
if (foundMembershipUser != null)
|
||||
{
|
||||
_provider.DeleteUser(foundMembershipUser.UserName, true);
|
||||
}
|
||||
break;
|
||||
case MembershipScenario.StandaloneCustomProvider:
|
||||
foundMembershipUser = _provider.GetUser(key, false);
|
||||
if (foundMembershipUser != null)
|
||||
{
|
||||
_provider.DeleteUser(foundMembershipUser.UserName, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
return HandleContentNotFound(key, false);
|
||||
}
|
||||
Services.MemberService.Delete(foundMember);
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
@@ -22,8 +23,6 @@ namespace Umbraco.Web.Editors
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MemberGroups)]
|
||||
public class MemberGroupController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly MembershipProvider _provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
public MemberGroupDisplay GetById(int id)
|
||||
{
|
||||
var memberGroup = Services.MemberGroupService.GetById(id);
|
||||
@@ -38,13 +37,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public IEnumerable<MemberGroupDisplay> GetByIds([FromUri]int[] ids)
|
||||
{
|
||||
if (_provider.IsUmbracoMembershipProvider())
|
||||
{
|
||||
return Services.MemberGroupService.GetByIds(ids)
|
||||
return Services.MemberGroupService.GetByIds(ids)
|
||||
.Select(Mapper.Map<IMemberGroup, MemberGroupDisplay>);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<MemberGroupDisplay>();
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
@@ -63,13 +57,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public IEnumerable<MemberGroupDisplay> GetAllGroups()
|
||||
{
|
||||
if (_provider.IsUmbracoMembershipProvider())
|
||||
{
|
||||
return Services.MemberGroupService.GetAll()
|
||||
return Services.MemberGroupService.GetAll()
|
||||
.Select(Mapper.Map<IMemberGroup, MemberGroupDisplay>);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<MemberGroupDisplay>();
|
||||
}
|
||||
|
||||
public MemberGroupDisplay GetEmpty()
|
||||
|
||||
@@ -16,6 +16,7 @@ using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
@@ -29,13 +30,11 @@ namespace Umbraco.Web.Editors
|
||||
[UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})]
|
||||
public class MemberTypeController : ContentTypeControllerBase<IMemberType>
|
||||
{
|
||||
public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
public MemberTypeController(ICultureDictionary cultureDictionary, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
|
||||
{
|
||||
}
|
||||
|
||||
private readonly MembershipProvider _provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MemberTypes)]
|
||||
public MemberTypeDisplay GetById(int id)
|
||||
{
|
||||
@@ -114,12 +113,8 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
public IEnumerable<ContentTypeBasic> GetAllTypes()
|
||||
{
|
||||
if (_provider.IsUmbracoMembershipProvider())
|
||||
{
|
||||
return Services.MemberTypeService.GetAll()
|
||||
return Services.MemberTypeService.GetAll()
|
||||
.Select(Mapper.Map<IMemberType, ContentTypeBasic>);
|
||||
}
|
||||
return Enumerable.Empty<ContentTypeBasic>();
|
||||
}
|
||||
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MemberTypes)]
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -46,27 +45,6 @@ namespace Umbraco.Web.Editors
|
||||
if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel));
|
||||
if (userMgr == null) throw new ArgumentNullException(nameof(userMgr));
|
||||
|
||||
//check if this identity implementation is powered by an underlying membership provider (it will be in most cases)
|
||||
var membershipPasswordHasher = userMgr.PasswordHasher as IMembershipProviderPasswordHasher;
|
||||
|
||||
//check if this identity implementation is powered by an IUserAwarePasswordHasher (it will be by default in 7.7+ but not for upgrades)
|
||||
|
||||
if (membershipPasswordHasher != null && !(userMgr.PasswordHasher is IUserAwarePasswordHasher<BackOfficeIdentityUser, int>))
|
||||
{
|
||||
//if this isn't using an IUserAwarePasswordHasher, then fallback to the old way
|
||||
if (membershipPasswordHasher.MembershipProvider.RequiresQuestionAndAnswer)
|
||||
throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified");
|
||||
return ChangePasswordWithMembershipProvider(savingUser.Username, passwordModel, membershipPasswordHasher.MembershipProvider);
|
||||
}
|
||||
|
||||
//if we are here, then a IUserAwarePasswordHasher is available, however we cannot proceed in that case if for some odd reason
|
||||
//the user has configured the membership provider to not be hashed. This will actually never occur because the BackOfficeUserManager
|
||||
//will throw if it's not hashed, but we should make sure to check anyways (i.e. in case we want to unit test!)
|
||||
if (membershipPasswordHasher != null && membershipPasswordHasher.MembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed)
|
||||
{
|
||||
throw new InvalidOperationException("The membership provider cannot have a password format of " + membershipPasswordHasher.MembershipProvider.PasswordFormat + " and be configured with secured hashed passwords");
|
||||
}
|
||||
|
||||
//Are we resetting the password?
|
||||
//This flag indicates that either an admin user is changing another user's password without knowing the original password
|
||||
// or that the password needs to be reset to an auto-generated one.
|
||||
@@ -125,7 +103,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
//is the old password correct?
|
||||
var validateResult = await userMgr.CheckPasswordAsync(backOfficeIdentityUser, passwordModel.OldPassword);
|
||||
if(validateResult == false)
|
||||
if (validateResult == false)
|
||||
{
|
||||
//no, fail with an error message for "oldPassword"
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Incorrect password", new[] { "oldPassword" }) });
|
||||
@@ -149,7 +127,10 @@ namespace Umbraco.Web.Editors
|
||||
/// <param name="passwordModel"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <returns></returns>
|
||||
public Attempt<PasswordChangedModel> ChangePasswordWithMembershipProvider(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider)
|
||||
public Attempt<PasswordChangedModel> ChangePasswordWithMembershipProvider(
|
||||
string username,
|
||||
ChangingPasswordModel passwordModel,
|
||||
MembershipProvider membershipProvider)
|
||||
{
|
||||
var umbracoBaseProvider = membershipProvider as MembershipProviderBase;
|
||||
|
||||
@@ -158,20 +139,19 @@ namespace Umbraco.Web.Editors
|
||||
if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel));
|
||||
if (membershipProvider == null) throw new ArgumentNullException(nameof(membershipProvider));
|
||||
|
||||
BackOfficeUserManager<BackOfficeIdentityUser> backofficeUserManager = null;
|
||||
var backofficeUserManager = _httpContext.GetOwinContext().GetBackOfficeUserManager();
|
||||
var userId = -1;
|
||||
|
||||
if (membershipProvider.IsUmbracoUsersProvider())
|
||||
if (backofficeUserManager == null)
|
||||
{
|
||||
backofficeUserManager = _httpContext.GetOwinContext().GetBackOfficeUserManager();
|
||||
if (backofficeUserManager != null)
|
||||
{
|
||||
var profile = _userService.GetProfileByUserName(username);
|
||||
if (profile != null)
|
||||
int.TryParse(profile.Id.ToString(), out userId);
|
||||
}
|
||||
// should never happen
|
||||
throw new InvalidOperationException("Could not resolve the back office user manager");
|
||||
}
|
||||
|
||||
var profile = _userService.GetProfileByUserName(username);
|
||||
if (profile != null)
|
||||
int.TryParse(profile.Id.ToString(), out userId);
|
||||
|
||||
//Are we resetting the password?
|
||||
//This flag indicates that either an admin user is changing another user's password without knowing the original password
|
||||
// or that the password needs to be reset to an auto-generated one.
|
||||
@@ -181,7 +161,7 @@ namespace Umbraco.Web.Editors
|
||||
//this is only possible when using a membership provider if the membership provider supports AllowManuallyChangingPassword
|
||||
if (passwordModel.NewPassword.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
if (umbracoBaseProvider !=null && umbracoBaseProvider.AllowManuallyChangingPassword)
|
||||
if (umbracoBaseProvider != null && umbracoBaseProvider.AllowManuallyChangingPassword)
|
||||
{
|
||||
//this provider allows manually changing the password without the old password, so we can just do it
|
||||
try
|
||||
@@ -209,7 +189,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
//we've made it here which means we need to generate a new password
|
||||
|
||||
var canReset = membershipProvider.CanResetPassword(_userService);
|
||||
var canReset = true; // TODO: Remove this! This is legacy, all of this will be gone when we get membership providers entirely gone
|
||||
if (canReset == false)
|
||||
{
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset is not enabled", new[] { "resetPassword" }) });
|
||||
@@ -226,7 +206,7 @@ namespace Umbraco.Web.Editors
|
||||
username,
|
||||
membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null);
|
||||
|
||||
if (membershipProvider.IsUmbracoUsersProvider() && backofficeUserManager != null && userId >= 0)
|
||||
if (userId >= 0)
|
||||
backofficeUserManager.RaisePasswordResetEvent(userId);
|
||||
|
||||
//return the generated pword
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user