Skip to content

Commit

Permalink
Merge pull request #2 from umbraco/dev-v7
Browse files Browse the repository at this point in the history
merge from umbraco/
  • Loading branch information
danieland committed Nov 2, 2015
2 parents 71b3810 + 30f0c96 commit 9cd64a9
Show file tree
Hide file tree
Showing 50 changed files with 721 additions and 370 deletions.
13 changes: 12 additions & 1 deletion build/NuSpecs/build/UmbracoCms.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyUmbracoFilesToWebRootForDeploy" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
<ItemGroup>
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
</ItemGroup>
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="$(_PackageTempDir)\%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
<!-- This copies the files listed in `AddUmbracoFilesToOutput` to the webroot during NuGet install and should -->
<!-- not be altered to support automated builds, use `CopyUmbracoFilesToWebRootForDeploy` for that instead -->
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
Expand Down Expand Up @@ -47,4 +58,4 @@
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
</Project>
4 changes: 2 additions & 2 deletions src/SolutionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@

[assembly: AssemblyVersion("1.0.*")]

[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyInformationalVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.1")]
[assembly: AssemblyInformationalVersion("7.3.1")]
38 changes: 28 additions & 10 deletions src/Umbraco.Core/AsyncLock.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -117,38 +118,55 @@ public IDisposable Lock(int millisecondsTimeout)
private class NamedSemaphoreReleaser : CriticalFinalizerObject, IDisposable
{
private readonly Semaphore _semaphore;
private GCHandle _handle;

internal NamedSemaphoreReleaser(Semaphore semaphore)
{
_semaphore = semaphore;
_handle = GCHandle.Alloc(_semaphore);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
GC.SuppressFinalize(this); // finalize will not run
}

private void Dispose(bool disposing)
{
// critical
_handle.Free();
_semaphore.Release();
_semaphore.Dispose();
}

// we WANT to release the semaphore because it's a system object
// ie a critical non-managed resource - so we inherit from CriticalFinalizerObject
// which means that the finalizer "should" run in all situations
// we WANT to release the semaphore because it's a system object, ie a critical
// non-managed resource - and if it is not released then noone else can acquire
// the lock - so we inherit from CriticalFinalizerObject which means that the
// finalizer "should" run in all situations - there is always a chance that it
// does not run and the semaphore remains "acquired" but then chances are the
// whole process (w3wp.exe...) is going down, at which point the semaphore will
// be destroyed by Windows.

// however... that can fail with System.ObjectDisposedException because the
// underlying handle was closed... because we cannot guarantee that the semaphore
// is not gone already... unless we get a GCHandle = GCHandle.Alloc(_semaphore);
// which should keep it around and then we free the handle?
// however, the semaphore is a managed object, and so when the finalizer runs it
// might have been finalized already, and then we get a, ObjectDisposedException
// in the finalizer - which is bad.

// so... I'm not sure this is safe really...
// in order to prevent this we do two things
// - use a GCHandler to ensure the semaphore is still there when the finalizer
// runs, so we can actually release it
// - wrap the finalizer code in a try...catch to make sure it never throws

~NamedSemaphoreReleaser()
{
Dispose(false);
try
{
Dispose(false);
}
catch
{
// we do NOT want the finalizer to throw - never ever
}
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/Umbraco.Core/Models/Member.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public bool IsApproved
//This is the default value if the prop is not found
true);
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.IsApproved].Value == null) return true;
var tryConvert = Properties[Constants.Conventions.Member.IsApproved].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
Expand Down Expand Up @@ -313,7 +313,7 @@ public bool IsLockedOut
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, "IsLockedOut", false);
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.IsLockedOut].Value == null) return false;
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
Expand Down Expand Up @@ -346,7 +346,7 @@ public DateTime LastLoginDate
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, "LastLoginDate", default(DateTime));
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.LastLoginDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
Expand Down Expand Up @@ -379,7 +379,7 @@ public DateTime LastPasswordChangeDate
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, "LastPasswordChangeDate", default(DateTime));
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
Expand Down Expand Up @@ -412,7 +412,7 @@ public DateTime LastLockoutDate
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, "LastLockoutDate", default(DateTime));
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.LastLockoutDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
Expand Down Expand Up @@ -446,7 +446,7 @@ public int FailedPasswordAttempts
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, "FailedPasswordAttempts", 0);
if (a.Success == false) return a.Result;

if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value == null) return default(int);
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value.TryConvertTo<int>();
if (tryConvert.Success)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;

namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeOne
{
/// <summary>
/// This fixes the storage of user languages from the old format like en_us to en-US
/// </summary>
[Migration("7.3.1", 0, GlobalSettings.UmbracoMigrationName)]
public class UpdateUserLanguagesToIsoCode : MigrationBase
{
public UpdateUserLanguagesToIsoCode(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}

public override void Up()
{
var userData = Context.Database.Fetch<UserDto>(new Sql().Select("*").From<UserDto>(SqlSyntax));
foreach (var user in userData.Where(x => x.UserLanguage.Contains("_")))
{
var languageParts = user.UserLanguage.Split('_');
if (languageParts.Length == 2)
{
Update.Table("umbracoUser")
.Set(new {userLanguage = languageParts[0] + "-" + languageParts[1].ToUpperInvariant()})
.Where(new {id = user.Id});
}
}
}

public override void Down()
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Maps a property source value to a data object.
/// </summary>
// todo: drop IPropertyEditorValueConverter support (when?).
Expand Down
77 changes: 62 additions & 15 deletions src/Umbraco.Core/Security/BackOfficeUserManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Security;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
Expand All @@ -9,8 +10,6 @@

namespace Umbraco.Core.Security
{


/// <summary>
/// Default back office user manager
/// </summary>
Expand All @@ -21,6 +20,18 @@ public BackOfficeUserManager(IUserStore<BackOfficeIdentityUser, int> store)
{
}

public BackOfficeUserManager(
IUserStore<BackOfficeIdentityUser, int> store,
IdentityFactoryOptions<BackOfficeUserManager> options,
MembershipProviderBase membershipProvider)
: base(store)
{
if (options == null) throw new ArgumentNullException("options");
var manager = new BackOfficeUserManager(store);
InitUserManager(manager, membershipProvider, options);
}

#region Static Create methods
/// <summary>
/// Creates a BackOfficeUserManager instance with all default options and the default BackOfficeUserManager
/// </summary>
Expand All @@ -40,8 +51,8 @@ public static BackOfficeUserManager Create(
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");

var manager = new BackOfficeUserManager(new BackOfficeUserStore(userService, externalLoginService, membershipProvider));

return InitUserManager(manager, membershipProvider, options);
manager.InitUserManager(manager, membershipProvider, options);
return manager;
}

/// <summary>
Expand All @@ -56,13 +67,10 @@ public static BackOfficeUserManager Create(
BackOfficeUserStore customUserStore,
MembershipProviderBase membershipProvider)
{
if (options == null) throw new ArgumentNullException("options");
if (customUserStore == null) throw new ArgumentNullException("customUserStore");

var manager = new BackOfficeUserManager(customUserStore);

return InitUserManager(manager, membershipProvider, options);
}
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider);
return manager;
}
#endregion

/// <summary>
/// Initializes the user manager with the correct options
Expand All @@ -71,7 +79,7 @@ public static BackOfficeUserManager Create(
/// <param name="membershipProvider"></param>
/// <param name="options"></param>
/// <returns></returns>
private static BackOfficeUserManager InitUserManager(BackOfficeUserManager manager, MembershipProviderBase membershipProvider, IdentityFactoryOptions<BackOfficeUserManager> options)
protected void InitUserManager(BackOfficeUserManager manager, MembershipProviderBase membershipProvider, IdentityFactoryOptions<BackOfficeUserManager> options)
{
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<BackOfficeIdentityUser, int>(manager)
Expand Down Expand Up @@ -125,10 +133,10 @@ private static BackOfficeUserManager InitUserManager(BackOfficeUserManager manag
//});

//manager.EmailService = new EmailService();
//manager.SmsService = new SmsService();

return manager;
//manager.SmsService = new SmsService();
}


}

/// <summary>
Expand Down Expand Up @@ -171,5 +179,44 @@ public override bool SupportsUserPhoneNumber
}
#endregion

/// <summary>
/// Logic used to validate a username and password
/// </summary>
/// <param name="user"></param>
/// <param name="password"></param>
/// <returns></returns>
/// <remarks>
/// By default this uses the standard ASP.Net Identity approach which is:
/// * Get password store
/// * Call VerifyPasswordAsync with the password store + user + password
/// * Uses the PasswordHasher.VerifyHashedPassword to compare the stored password
///
/// In some cases people want simple custom control over the username/password check, for simplicity
/// sake, developers would like the users to simply validate against an LDAP directory but the user
/// data remains stored inside of Umbraco.
/// See: http://issues.umbraco.org/issue/U4-7032 for the use cases.
///
/// We've allowed this check to be overridden with a simple callback so that developers don't actually
/// have to implement/override this class.
/// </remarks>
public async override Task<bool> CheckPasswordAsync(T user, string password)
{
if (BackOfficeUserPasswordChecker != null)
{
var result = await BackOfficeUserPasswordChecker.CheckPasswordAsync(user, password);
//if the result indicates to not fallback to the default, then return true if the credentials are valid
if (result != BackOfficeUserPasswordCheckerResult.FallbackToDefaultChecker)
{
return result == BackOfficeUserPasswordCheckerResult.ValidCredentials;
}
}
//use the default behavior
return await base.CheckPasswordAsync(user, password);
}

/// <summary>
/// Gets/sets the default back office user password checker
/// </summary>
public IBackOfficeUserPasswordChecker BackOfficeUserPasswordChecker { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/Umbraco.Core/Security/BackOfficeUserPasswordCheckerResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Umbraco.Core.Security
{
/// <summary>
/// The result returned from the IBackOfficeUserPasswordChecker
/// </summary>
public enum BackOfficeUserPasswordCheckerResult
{
ValidCredentials,
InvalidCredentials,
FallbackToDefaultChecker
}
}
14 changes: 14 additions & 0 deletions src/Umbraco.Core/Security/IBackOfficeUserPasswordChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Threading.Tasks;
using Umbraco.Core.Models.Identity;

namespace Umbraco.Core.Security
{
/// <summary>
/// Used by the BackOfficeUserManager to check the username/password which allows for developers to more easily
/// set the logic for this procedure.
/// </summary>
public interface IBackOfficeUserPasswordChecker
{
Task<BackOfficeUserPasswordCheckerResult> CheckPasswordAsync(BackOfficeIdentityUser user, string password);
}
}
3 changes: 3 additions & 0 deletions src/Umbraco.Core/Services/ContentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,9 @@ public IEnumerable<IContent> GetAncestors(int id)
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetAncestors(IContent content)
{
//null check otherwise we get exceptions
if (content.Path.IsNullOrWhiteSpace()) return Enumerable.Empty<IContent>();

var ids = content.Path.Split(',').Where(x => x != Constants.System.Root.ToInvariantString() && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
if (ids.Any() == false)
return new List<IContent>();
Expand Down
Loading

0 comments on commit 9cd64a9

Please sign in to comment.