diff --git a/src/Umbraco.Core/Models/Membership/IProfile.cs b/src/Umbraco.Core/Models/Membership/IProfile.cs index fbbff85e7d..749c3371b8 100644 --- a/src/Umbraco.Core/Models/Membership/IProfile.cs +++ b/src/Umbraco.Core/Models/Membership/IProfile.cs @@ -3,6 +3,10 @@ /// /// Defines the the Profile interface /// + /// + /// This interface is pretty useless but has been exposed publicly from 6.x so we're stuck with it. It would make more sense + /// if the Id was an int but since it's not people have to cast it to int all of the time! + /// public interface IProfile { object Id { get; set; } diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index b15e5845e5..ab9c02b1b2 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Membership /// Will be left internal until a proper Membership implementation is part of the roadmap public interface IUser : IMembershipUser, IProfile { - new object Id { get; set; } + new int Id { get; set; } int SessionTimeout { get; set; } int StartContentId { get; set; } diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 52350b3748..b35fd04bba 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Models.Membership /// [Serializable] [DataContract(IsReference = true)] - internal class User : TracksChangesEntityBase, IUser + public class User : TracksChangesEntityBase, IUser { public User(IUserType userType) { @@ -45,7 +45,7 @@ namespace Umbraco.Core.Models.Membership private readonly IUserType _userType; private bool _hasIdentity; - private object _id; + private int _id; private string _name; private Type _userTypeKey; private readonly List _addedSections; @@ -242,6 +242,12 @@ namespace Umbraco.Core.Models.Membership #region Implementation of IProfile + object IProfile.Id + { + get { return Id; } + set { Id = (int)value; } + } + [DataMember] public string Name { @@ -355,7 +361,7 @@ namespace Umbraco.Core.Models.Membership } [DataMember] - public object Id + public int Id { get { return _id; } set diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index 840cd9a685..a55bd4b771 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Services /// /// Defines the UserService, which is an easy access to operations involving and eventually Users. /// - internal interface IUserService : IMembershipUserService + public interface IUserService : IMembershipUserService { /// /// Gets an IProfile by User Id. diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index 5ac259cafb..8939101ac8 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Web.Security; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -16,7 +15,7 @@ namespace Umbraco.Core.Services /// /// Represents the UserService, which is an easy access to operations involving , and eventually Backoffice Users. /// - internal class UserService : IUserService + public class UserService : IUserService { private readonly RepositoryFactory _repositoryFactory; private readonly IDatabaseUnitOfWorkProvider _uowProvider; diff --git a/src/Umbraco.Core/Services/UserServiceExtensions.cs b/src/Umbraco.Core/Services/UserServiceExtensions.cs new file mode 100644 index 0000000000..b97a40ace8 --- /dev/null +++ b/src/Umbraco.Core/Services/UserServiceExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Web.Security; +using Umbraco.Core.Models.Membership; + +namespace Umbraco.Core.Services +{ + internal static class UserServiceExtensions + { + /// + /// Maps a custom provider's information to an umbraco user account + /// + /// + /// + /// + /// 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. + /// + public 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 writer = userService.GetUserTypeByAlias("writer"); + if (writer == null) + { + throw new InvalidOperationException("Could not map the custom user to an Umbraco user, no 'writer' user type could be found"); + } + 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 + writer); + user.AddAllowedSection(Constants.Applications.Content); + userService.Save(user); + return user; + } + + return found; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0c7025fe00..c31a353390 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -787,6 +787,7 @@ + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/login.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/login.aspx.cs index 36008e7fac..3773e1ffab 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/login.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/login.aspx.cs @@ -11,14 +11,17 @@ using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using Umbraco.Core.Logging; -using umbraco.BusinessLogic; using System.Web.Security; using umbraco.businesslogic.Exceptions; using Umbraco.Core.IO; using umbraco.cms.businesslogic.web; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Web; +using User = umbraco.BusinessLogic.User; namespace umbraco.cms.presentation { @@ -83,40 +86,51 @@ namespace umbraco.cms.presentation // Authenticate users by using the provider specified in umbracoSettings.config if (BackOfficeProvider.ValidateUser(lname.Text, passw.Text)) { + IUser user; if (BackOfficeProvider.IsUmbracoUsersProvider() == false) { - CustomProviderMapping(lname.Text, BackOfficeProvider.GetUser(lname.Text, false).Email); + user = ApplicationContext.Services.UserService.CreateUserMappingForCustomProvider( + BackOfficeProvider.GetUser(lname.Text, false)); } - - - var u = new User(lname.Text); - doLogin(u); + else + { + user = ApplicationContext.Services.UserService.GetByUsername(lname.Text); + if (user == null) + { + throw new InvalidOperationException("No IUser found with username " + lname.Text); + } + } + + //do the login + UmbracoContext.Current.Security.PerformLogin(user.Id); // Check if the user should be redirected to live editing - if (UmbracoSettings.EnableCanvasEditing && u.DefaultToLiveEditing) + if (UmbracoSettings.EnableCanvasEditing) { - int startNode = u.StartNodeId; - // If the startnode is -1 (access to all content), we'll redirect to the top root node - if (startNode == -1) + //if live editing is enabled, we have to check if we need to redirect there but it is not supported + // on the new IUser so we need to get the legacy user object to check + var u = new User(user.Id); + if (u.DefaultToLiveEditing) { - if (Document.CountLeafNodes(-1, Document._objectType) > 0) + var startNode = u.StartNodeId; + // If the startnode is -1 (access to all content), we'll redirect to the top root node + if (startNode == -1) { - //get the first document - var firstNodeId = Document.TopMostNodeIds(Document._objectType).First(); - startNode = new Document(firstNodeId).Id; - } - else - { - throw new Exception("There's currently no content to edit. Please contact your system administrator"); + if (Document.CountLeafNodes(-1, Document._objectType) > 0) + { + //get the first document + var firstNodeId = Document.TopMostNodeIds(Document._objectType).First(); + startNode = new Document(firstNodeId).Id; + } + else + { + throw new Exception("There's currently no content to edit. Please contact your system administrator"); + } } + var redir = String.Format("{0}/canvas.aspx?redir=/{1}.aspx", SystemDirectories.Umbraco, startNode); + Response.Redirect(redir, true); } - string redir = String.Format("{0}/canvas.aspx?redir=/{1}.aspx", SystemDirectories.Umbraco, startNode); - Response.Redirect(redir, true); - } - else if (u.DefaultToLiveEditing) - { - throw new UserAuthorizationException("Canvas editing isn't enabled. It can be enabled via the UmbracoSettings.config"); - } + } if (hf_height.Value != "undefined") { @@ -173,24 +187,7 @@ namespace umbraco.cms.presentation && Uri.IsWellFormedUriString(url, UriKind.Relative); return isLocal; } - - /// - /// Maps a custom provider's information to an umbraco user account - /// - /// Name of the login. - /// Email address of the user - private static void CustomProviderMapping(string loginName, string email) - { - // Password is not copied over because it is stored in active directory for security! - // The user is create with default access to content and as a writer user type - if (BusinessLogic.User.getUserId(loginName) == -1) - { - BusinessLogic.User.MakeNew(loginName, loginName, string.Empty, email ?? "", UserType.GetUserType(2)); - var u = new User(loginName); - u.addApplication(Constants.Applications.Content); - } - } - + /// /// ClientLoader control. ///