From 2869f17eff320910b67e125fa6caa467581c3b1a Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 17 Feb 2014 18:02:29 +1100 Subject: [PATCH 1/6] ensures the default property aliases are set during ctor --- .../Security/Providers/MembersMembershipProvider.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs index bdbca3fa40..0eea8b52e3 100644 --- a/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs +++ b/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs @@ -28,6 +28,15 @@ namespace Umbraco.Web.Security.Providers public MembersMembershipProvider(IMembershipMemberService memberService) : base(memberService) { + LockPropertyTypeAlias = Constants.Conventions.Member.IsLockedOut; + LastLockedOutPropertyTypeAlias = Constants.Conventions.Member.LastLockoutDate; + FailedPasswordAttemptsPropertyTypeAlias = Constants.Conventions.Member.FailedPasswordAttempts; + ApprovedPropertyTypeAlias = Constants.Conventions.Member.IsApproved; + CommentPropertyTypeAlias = Constants.Conventions.Member.Comments; + LastLoginPropertyTypeAlias = Constants.Conventions.Member.LastLoginDate; + LastPasswordChangedPropertyTypeAlias = Constants.Conventions.Member.LastPasswordChangeDate; + PasswordRetrievalQuestionPropertyTypeAlias = Constants.Conventions.Member.PasswordQuestion; + PasswordRetrievalAnswerPropertyTypeAlias = Constants.Conventions.Member.PasswordAnswer; } private string _defaultMemberTypeAlias = "Member"; From 846f4b5b6c6deab1ea0bf03b76e899d4596c58a5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 17 Feb 2014 19:32:04 +1100 Subject: [PATCH 2/6] Removes the various old hacks for the legacy user's membership provider, now that we have the AllowManuallyChangingPassword flag, these hacks are not required. --- .../config/metablogConfig.config | 2 +- .../install/steps/DefaultUser.ascx.cs | 3 +- .../umbraco/controls/passwordChanger.ascx.cs | 7 ++-- .../umbraco/users/EditUser.aspx.cs | 34 ------------------- .../UsersMembershipProvider.cs | 13 ------- 5 files changed, 8 insertions(+), 51 deletions(-) diff --git a/src/Umbraco.Web.UI/config/metablogConfig.config b/src/Umbraco.Web.UI/config/metablogConfig.config index 82502df5e3..5621dbee75 100644 --- a/src/Umbraco.Web.UI/config/metablogConfig.config +++ b/src/Umbraco.Web.UI/config/metablogConfig.config @@ -5,7 +5,7 @@ 0 1080 False - umbBlog + Base diff --git a/src/Umbraco.Web.UI/install/steps/DefaultUser.ascx.cs b/src/Umbraco.Web.UI/install/steps/DefaultUser.ascx.cs index 897bb9ad85..1114ebd89a 100644 --- a/src/Umbraco.Web.UI/install/steps/DefaultUser.ascx.cs +++ b/src/Umbraco.Web.UI/install/steps/DefaultUser.ascx.cs @@ -1,6 +1,7 @@ using System; using System.Web.Security; using Umbraco.Core.Configuration; +using Umbraco.Core.Security; using Umbraco.Web.Install; using Umbraco.Web.Security; using umbraco.BusinessLogic; @@ -60,7 +61,7 @@ namespace Umbraco.Web.UI.Install.Steps } // Is it using the default membership provider - if (CurrentProvider is UsersMembershipProvider) + if (CurrentProvider.IsUmbracoUsersProvider()) { // Save user in membership provider var umbracoUser = user as UsersMembershipUser; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/passwordChanger.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/passwordChanger.ascx.cs index 6691a025e4..3582e873a4 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/passwordChanger.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/passwordChanger.ascx.cs @@ -38,9 +38,12 @@ namespace umbraco.controls var umbProvider = Provider as MembershipProviderBase; if (umbProvider != null && umbProvider.AllowManuallyChangingPassword) { - return false; + _showOldPassword = false; + } + else + { + _showOldPassword = Provider.EnablePasswordRetrieval == false; } - _showOldPassword = Provider.EnablePasswordRetrieval == false; } return _showOldPassword.Value; } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs index efc7e525fc..1df2c849a0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs @@ -167,14 +167,6 @@ namespace umbraco.cms.presentation.user var passwordChanger = (passwordChanger) LoadControl(SystemDirectories.Umbraco + "/controls/passwordChanger.ascx"); passwordChanger.MembershipProviderName = UmbracoSettings.DefaultBackofficeProvider; - //This is a hack to allow the admin to change a user's password to whatever they want - this will only work if we are using the - // default umbraco membership provider. - // See the notes below in the ChangePassword method. - if (BackOfficeProvider.IsUmbracoUsersProvider()) - { - passwordChanger.ShowOldPassword = false; - } - //Add a custom validation message for the password changer var passwordValidation = new CustomValidator { @@ -368,18 +360,6 @@ namespace umbraco.cms.presentation.user lname.Text = (user == null) ? u.LoginName : user.UserName; email.Text = (user == null) ? u.Email : user.Email; - //// Prevent users from changing information if logged in through a custom provider - //// custom provider mapped accounts have empty passwords by default... so set update user fields to read only - //// this will not be a security issue because empty passwords are not allowed in membership provider. - //// This might change in version 4.0 - //if (string.IsNullOrEmpty(u.GetPassword())) - //{ - // uname.ReadOnly = true; - // lname.ReadOnly = true; - // email.ReadOnly = true; - // passw.Visible = false; - //} - contentPicker.Value = u.StartNodeId.ToString(CultureInfo.InvariantCulture); mediaPicker.Value = u.StartMediaId.ToString(CultureInfo.InvariantCulture); @@ -438,20 +418,6 @@ namespace umbraco.cms.presentation.user var changePasswordModel = passwordChangerControl.ChangingPasswordModel; - // Is it using the default membership provider - if (BackOfficeProvider.IsUmbracoUsersProvider()) - { - //This is a total hack so that an admin can change the password without knowing the previous one - // we do this by simply passing in the already stored hashed/encrypted password in the database - - // this shouldn't be allowed but to maintain backwards compatibility we need to do this because - // this logic was previously allowed. - - //For this editor, we set the passwordChanger.ShowOldPassword = false so that the old password - // field doesn't appear because we know we are going to manually set it here. - // We'll change the model to have the already encrypted password stored in the db and that will continue to validate. - changePasswordModel.OldPassword = u.Password; - } - //now do the actual change var changePassResult = _membershipHelper.ChangePassword( membershipUser.UserName, changePasswordModel, BackOfficeProvider); diff --git a/src/umbraco.providers/UsersMembershipProvider.cs b/src/umbraco.providers/UsersMembershipProvider.cs index 6561482b89..1561b991bc 100644 --- a/src/umbraco.providers/UsersMembershipProvider.cs +++ b/src/umbraco.providers/UsersMembershipProvider.cs @@ -494,19 +494,6 @@ namespace umbraco.providers return false; } - //Due to the way this legacy provider worked, when it 'validated' a password passed in, it would allow - // having the already hashed/encrypted password checked directly - this is bad but hey, we gotta support legacy - // don't we. - - //So, first we'll check if the user object's db stored password (already hashed/encrypted in the db) matches the password that - // has been passed in, if so then we will confirm that it is valid. If it doesn't we'll attempt to hash/encrypt the passed in - // password and then validate it - the way it is supposed to be done. - - if (user.Password == password) - { - return true; - } - return CheckPassword(password, user.Password); } } From 3634a77d613b9d26d286d11f9b42e7e432d061c7 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 17 Feb 2014 08:40:30 +0100 Subject: [PATCH 3/6] U4-4241 - UrlAbsolute() returns relative urls --- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 4ff5b93898..484e7697b8 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -83,7 +83,7 @@ namespace Umbraco.Web throw new InvalidOperationException("Cannot resolve a Url for a content item when UmbracoContext.Current is null."); if (UmbracoContext.Current.UrlProvider == null) throw new InvalidOperationException("Cannot resolve a Url for a content item when UmbracoContext.Current.UrlProvider is null."); - return UmbracoContext.Current.UrlProvider.GetUrl(content.Id); + return UmbracoContext.Current.UrlProvider.GetUrl(content.Id, true); case PublishedItemType.Media: throw new NotSupportedException("AbsoluteUrl is not supported for media types."); default: From e0dcc3afbc719c3b017bff3837a677c7684bed42 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 17 Feb 2014 21:38:13 +1100 Subject: [PATCH 4/6] Streamlines how strings are escaped with the sql expression helpers and syntax providers. Fixes: U4-4232 Umbraco.Core.Persistence.Querying issue with backslashes --- .../Querying/BaseExpressionHelper.cs | 20 +++++++++---------- .../Querying/ModelToSqlExpressionHelper.cs | 15 +++++++------- .../Querying/PocoToSqlExpressionHelper.cs | 6 +++--- .../SqlSyntax/ISqlSyntaxProvider.cs | 2 ++ .../SqlSyntax/MySqlSyntaxProvider.cs | 5 +++++ .../SqlSyntax/SqlSyntaxProviderBase.cs | 5 +++++ src/Umbraco.Core/Umbraco.Core.csproj | 4 ++++ src/Umbraco.Core/packages.config | 1 + 8 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs index 73fa98b275..08a08e49d3 100644 --- a/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Querying { @@ -25,7 +26,7 @@ namespace Umbraco.Core.Persistence.Querying { //if (TypeSerializer.CanCreateFromString(fieldType)) //{ - // return "'" + EscapeParam(TypeSerializer.SerializeToString(value)) + "'"; + // return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'"; //} throw new NotSupportedException( @@ -46,27 +47,24 @@ namespace Umbraco.Core.Persistence.Querying if (fieldType == typeof(DateTime)) { - return "'" + EscapeParam(((DateTime)value).ToIsoString()) + "'"; + return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'"; } if (fieldType == typeof(bool)) return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture); - return ShouldQuoteValue(fieldType) - ? "'" + EscapeParam(value) + "'" + return shouldQuoteCallback(fieldType) + ? "'" + escapeCallback(value) + "'" : value.ToString(); } public virtual string EscapeParam(object paramValue) { - return paramValue.ToString().Replace("'", "''"); + return paramValue == null + ? string.Empty + : SqlSyntaxContext.SqlSyntaxProvider.EscapeString(paramValue.ToString()); } - - public virtual string EscapeAtArgument(string exp) - { - return PetaPocoExtensions.EscapeAtSymbols(exp); - } - + public virtual bool ShouldQuoteValue(Type fieldType) { return true; diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs index 4dba620ab0..c7797d1a20 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs @@ -205,13 +205,12 @@ namespace Umbraco.Core.Persistence.Querying { if (c.Value == null) return "null"; - else if (c.Value.GetType() == typeof(bool)) + if (c.Value is bool) { object o = GetQuotedValue(c.Value, c.Value.GetType()); return string.Format("({0}={1})", GetQuotedTrueValue(), o); } - else - return GetQuotedValue(c.Value, c.Value.GetType()); + return GetQuotedValue(c.Value, c.Value.GetType()); } protected virtual string VisitUnary(UnaryExpression u) @@ -233,15 +232,15 @@ namespace Umbraco.Core.Persistence.Querying switch (verb) { case "SqlWildcard": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, EscapeParam(RemoveQuote(val)), columnType); case "Equals": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeParam(RemoveQuote(val)), columnType); case "StartsWith": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeParam(RemoveQuote(val)), columnType); case "EndsWith": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeParam(RemoveQuote(val)), columnType); case "Contains": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeParam(RemoveQuote(val)), columnType); case "InvariantEquals": case "SqlEquals": //recurse diff --git a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs index 6c2f7e6727..22bfed1e82 100644 --- a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs @@ -254,11 +254,11 @@ namespace Umbraco.Core.Persistence.Querying case "ToLower": return string.Format("lower({0})", r); case "StartsWith": - return string.Format("upper({0}) like '{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString().ToUpper()))); + return string.Format("upper({0}) like '{1}%'", r, EscapeParam(RemoveQuote(args[0].ToString().ToUpper()))); case "EndsWith": - return string.Format("upper({0}) like '%{1}'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper())); + return string.Format("upper({0}) like '%{1}'", r, EscapeParam(RemoveQuote(args[0].ToString()).ToUpper())); case "Contains": - return string.Format("upper({0}) like '%{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper())); + return string.Format("upper({0}) like '%{1}%'", r, EscapeParam(RemoveQuote(args[0].ToString()).ToUpper())); case "Substring": var startIndex = Int32.Parse(args[0].ToString()) + 1; if (args.Count == 2) diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index 2b31fb2032..c62fa1a923 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -11,6 +11,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax /// public interface ISqlSyntaxProvider { + string EscapeString(string val); + string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType); string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType); string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType); diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index 5f5d412ab3..0b8d80a21f 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -327,5 +327,10 @@ namespace Umbraco.Core.Persistence.SqlSyntax // add message to check with their hosting provider return supportsCaseInsensitiveQueries; } + + public override string EscapeString(string val) + { + return PetaPocoExtensions.EscapeAtSymbols(MySql.Data.MySqlClient.MySqlHelper.EscapeString(val)); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 8f9a84437c..004aabfc70 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -103,6 +103,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax DbTypeMap.Set(DbType.Binary, BlobColumnDefinition); } + public virtual string EscapeString(string val) + { + return PetaPocoExtensions.EscapeAtSymbols(val.Replace("'", "''")); + } + public virtual string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType) { //use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting. diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b96e6db308..b9e13a86fd 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -45,6 +45,10 @@ ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + False + ..\packages\MySql.Data.6.8.3\lib\net40\MySql.Data.dll + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config index f1d5aa83c6..3b2d7e5ca2 100644 --- a/src/Umbraco.Core/packages.config +++ b/src/Umbraco.Core/packages.config @@ -6,6 +6,7 @@ + \ No newline at end of file From f1a439e8512b655728ea71d82ffdceabbddcf950 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 18 Feb 2014 14:57:03 +1100 Subject: [PATCH 5/6] removes version specific references to mysql in the proj files and web.config ensures that escaping in the sql expression classes is done correctly without any double escaping. Also ensures that escaping is happening using the equals operator, not just the Equals() method and adds unit tests for them. Fixes: U4-4232 Umbraco.Core.Persistence.Querying issue with backslashes --- .../Querying/ModelToSqlExpressionHelper.cs | 10 ++-- .../Querying/PocoToSqlExpressionHelper.cs | 6 +- src/Umbraco.Core/Umbraco.Core.csproj | 4 +- src/Umbraco.Core/packages.config | 2 +- .../Persistence/Querying/ExpressionTests.cs | 58 +++++++++++++++++++ src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- .../config/ClientDependency.config | 2 +- src/Umbraco.Web.UI/web.Template.config | 4 +- .../umbraco.datalayer.csproj | 2 +- 9 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs index c7797d1a20..6ab3fcc592 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs @@ -232,15 +232,15 @@ namespace Umbraco.Core.Persistence.Querying switch (verb) { case "SqlWildcard": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, EscapeParam(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, RemoveQuote(val), columnType); case "Equals": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeParam(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, RemoveQuote(val), columnType); case "StartsWith": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeParam(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, RemoveQuote(val), columnType); case "EndsWith": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeParam(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, RemoveQuote(val), columnType); case "Contains": - return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeParam(RemoveQuote(val)), columnType); + return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, RemoveQuote(val), columnType); case "InvariantEquals": case "SqlEquals": //recurse diff --git a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs index 22bfed1e82..ecd5bb0087 100644 --- a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs @@ -254,11 +254,11 @@ namespace Umbraco.Core.Persistence.Querying case "ToLower": return string.Format("lower({0})", r); case "StartsWith": - return string.Format("upper({0}) like '{1}%'", r, EscapeParam(RemoveQuote(args[0].ToString().ToUpper()))); + return string.Format("upper({0}) like '{1}%'", r, RemoveQuote(args[0].ToString().ToUpper())); case "EndsWith": - return string.Format("upper({0}) like '%{1}'", r, EscapeParam(RemoveQuote(args[0].ToString()).ToUpper())); + return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper()); case "Contains": - return string.Format("upper({0}) like '%{1}%'", r, EscapeParam(RemoveQuote(args[0].ToString()).ToUpper())); + return string.Format("upper({0}) like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper()); case "Substring": var startIndex = Int32.Parse(args[0].ToString()) + 1; if (args.Count == 2) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b9e13a86fd..d4f6d29c27 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -45,9 +45,9 @@ ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - + False - ..\packages\MySql.Data.6.8.3\lib\net40\MySql.Data.dll + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config index 3b2d7e5ca2..3b24cc962d 100644 --- a/src/Umbraco.Core/packages.config +++ b/src/Umbraco.Core/packages.config @@ -6,7 +6,7 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs index c0316e979e..ba1592635f 100644 --- a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs @@ -2,7 +2,10 @@ using System.Linq.Expressions; using NUnit.Framework; using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Persistence.Querying @@ -35,5 +38,60 @@ namespace Umbraco.Tests.Persistence.Querying Assert.AreEqual("[umbracoNode].[parentID] = -1", result); } + + [Test] + public void Equals_Operator_For_Value_Gets_Escaped() + { + Expression> predicate = user => user.Username == "hello@world.com"; + var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper(); + var result = modelToSqlExpressionHelper.Visit(predicate); + + Console.WriteLine("Model to Sql ExpressionHelper: \n" + result); + + Assert.AreEqual("[umbracoUser].[userLogin] = 'hello@@world.com'", result); + } + + [Test] + public void Equals_Method_For_Value_Gets_Escaped() + { + Expression> predicate = user => user.Username.Equals("hello@world.com"); + var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper(); + var result = modelToSqlExpressionHelper.Visit(predicate); + + Console.WriteLine("Model to Sql ExpressionHelper: \n" + result); + + Assert.AreEqual("upper([umbracoUser].[userLogin]) = 'HELLO@@WORLD.COM'", result); + } + + [Test] + public void Model_Expression_Value_Does_Not_Get_Double_Escaped() + { + //mysql escapes backslashes, so we'll test with that + SqlSyntaxContext.SqlSyntaxProvider = MySqlSyntax.Provider; + + Expression> predicate = user => user.Username.Equals("mydomain\\myuser"); + var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper(); + var result = modelToSqlExpressionHelper.Visit(predicate); + + Console.WriteLine("Model to Sql ExpressionHelper: \n" + result); + + Assert.AreEqual("upper(`umbracoUser`.`userLogin`) = 'MYDOMAIN\\\\MYUSER'", result); + } + + [Test] + public void Poco_Expression_Value_Does_Not_Get_Double_Escaped() + { + //mysql escapes backslashes, so we'll test with that + SqlSyntaxContext.SqlSyntaxProvider = MySqlSyntax.Provider; + + Expression> predicate = user => user.Login.StartsWith("mydomain\\myuser"); + var modelToSqlExpressionHelper = new PocoToSqlExpressionHelper(); + var result = modelToSqlExpressionHelper.Visit(predicate); + + Console.WriteLine("Poco to Sql ExpressionHelper: \n" + result); + + Assert.AreEqual("upper(`umbracoUser`.`userLogin`) like 'MYDOMAIN\\\\MYUSER%'", result); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 63ebcd4e16..4045d404a9 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -132,7 +132,7 @@ False ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - + False ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll diff --git a/src/Umbraco.Web.UI/config/ClientDependency.config b/src/Umbraco.Web.UI/config/ClientDependency.config index 6c1ff881cf..f2f058cd14 100644 --- a/src/Umbraco.Web.UI/config/ClientDependency.config +++ b/src/Umbraco.Web.UI/config/ClientDependency.config @@ -10,7 +10,7 @@ NOTES: * Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config * A new version will invalidate both client and server cache and create new persisted files --> - +