From 5f5f535f05d29c2a742d47c6af5c8cae0011c577 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Nov 2013 18:07:10 +1100 Subject: [PATCH] Changes UserController to be CurrentUserController - and removes the other methods in there since that was an overlooked security issue. This controller is responsible solely for dealing with the currently logged in user. Changes over to be currentuser.resource as well. --- .../common/resources/currentuser.resource.js | 53 +++++ .../src/common/resources/user.resource.js | 113 ---------- .../dashboard/dashboard.tabs.controller.js | 6 +- .../Editors/BackOfficeController.cs | 4 +- ...Controller.cs => CurrentUserController.cs} | 199 ++++++++---------- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 6 files changed, 146 insertions(+), 231 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js delete mode 100644 src/Umbraco.Web.UI.Client/src/common/resources/user.resource.js rename src/Umbraco.Web/Editors/{UserController.cs => CurrentUserController.cs} (79%) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js new file mode 100644 index 0000000000..2a814fb2f1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js @@ -0,0 +1,53 @@ +/** + * @ngdoc service + * @name umbraco.resources.currentUserResource + * @description Used for read/updates for the currently logged in user + * + * + **/ +function currentUserResource($q, $http, umbRequestHelper) { + + //the factory object returned + return { + + /** + * @ngdoc method + * @name umbraco.resources.currentUserResource#changePassword + * @methodOf umbraco.resources.currentUserResource + * + * @description + * Changes the current users password + * + * @returns {Promise} resourcePromise object containing the user array. + * + */ + changePassword: function (changePasswordArgs) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "currentUserApiBaseUrl", + "PostChangePassword"), + changePasswordArgs), + 'Failed to change password'); + }, + + /** + * @ngdoc method + * @name umbraco.resources.currentUserResource#getMembershipProviderConfig + * @methodOf umbraco.resources.currentUserResource + * + * @description + * Gets the configuration of the user membership provider which is used to configure the change password form + */ + getMembershipProviderConfig: function () { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "currentUserApiBaseUrl", + "GetMembershipProviderConfig")), + 'Failed to retreive membership provider config'); + }, + }; +} + +angular.module('umbraco.resources').factory('currentUserResource', currentUserResource); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/user.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/user.resource.js deleted file mode 100644 index 857ef65160..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/resources/user.resource.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @ngdoc service - * @name umbraco.resources.userResource - * @description Retrives user data from the server, cannot be used for authentication, for this, use the user.service - * - * - **/ -function userResource($q, $http, umbRequestHelper) { - - //the factory object returned - return { - - /** - * @ngdoc method - * @name umbraco.resources.userResource#getById - * @methodOf umbraco.resources.userResource - * - * @description - * Gets a user with a given id - * - * ##usage - *
-         * userResource.getById(1234)
-         *    .then(function(ent) {
-         *        var myUser = ent; 
-         *        alert('im here!');
-         *    });
-         * 
- * - * @param {Int} id id of user to return - * @returns {Promise} resourcePromise object containing the user. - * - */ - getById: function (id) { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetById", - [{ id: id }])), - 'Failed to retreive user data for id ' + id); - }, - - /** - * @ngdoc method - * @name umbraco.resources.userResource#getAll - * @methodOf umbraco.resources.userResource - * - * @description - * Gets all users available on the system - * - * ##usage - *
-         * contentResource.getAll()
-         *    .then(function(userArray) {
-         *        var myUsers = userArray; 
-         *        alert('they are here!');
-         *    });
-         * 
- * - * @returns {Promise} resourcePromise object containing the user array. - * - */ - getAll: function () { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetAll")), - 'Failed to retreive all users'); - }, - - /** - * @ngdoc method - * @name umbraco.resources.userResource#changePassword - * @methodOf umbraco.resources.userResource - * - * @description - * Changes the current users password - * - * @returns {Promise} resourcePromise object containing the user array. - * - */ - changePassword: function (changePasswordArgs) { - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostChangePassword"), - changePasswordArgs), - 'Failed to change password'); - }, - - /** - * @ngdoc method - * @name umbraco.resources.userResource#getMembershipProviderConfig - * @methodOf umbraco.resources.userResource - * - * @description - * Gets the configuration of the user membership provider which is used to configure the change password form - */ - getMembershipProviderConfig: function () { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetMembershipProviderConfig")), - 'Failed to retreive membership provider config'); - }, - }; -} - -angular.module('umbraco.resources').factory('userResource', userResource); diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index 4e0426f620..496ed9e47f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -80,7 +80,7 @@ function MediaFolderBrowserDashboardController($rootScope, $scope, assetsService angular.module("umbraco").controller("Umbraco.Dashboard.MediaFolderBrowserDashboardController", MediaFolderBrowserDashboardController); -function ChangePasswordDashboardController($scope, xmlhelper, $log, userResource, formHelper) { +function ChangePasswordDashboardController($scope, xmlhelper, $log, currentUserResource, formHelper) { //create the initial model for change password property editor $scope.changePasswordModel = { @@ -91,7 +91,7 @@ function ChangePasswordDashboardController($scope, xmlhelper, $log, userResource }; //go get the config for the membership provider and add it to the model - userResource.getMembershipProviderConfig().then(function(data) { + currentUserResource.getMembershipProviderConfig().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 @@ -105,7 +105,7 @@ function ChangePasswordDashboardController($scope, xmlhelper, $log, userResource $scope.changePassword = function() { if (formHelper.submitForm({ scope: $scope })) { - userResource.changePassword($scope.changePasswordModel.value).then(function(data) { + currentUserResource.changePassword($scope.changePasswordModel.value).then(function(data) { //if the password has been reset, then update our model if (data.value) { diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 2ed33b2f91..1e36107689 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -102,8 +102,8 @@ namespace Umbraco.Web.Editors controller => controller.PostLogin(null, null)) }, { - "userApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( - controller => controller.GetAll()) + "currentUserApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( + controller => controller.GetMembershipProviderConfig()) }, { "legacyApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( diff --git a/src/Umbraco.Web/Editors/UserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs similarity index 79% rename from src/Umbraco.Web/Editors/UserController.cs rename to src/Umbraco.Web/Editors/CurrentUserController.cs index bea40acc81..880ca7ab41 100644 --- a/src/Umbraco.Web/Editors/UserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -1,112 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Security; -using AutoMapper; -using Umbraco.Core.Configuration; -using Umbraco.Web.Models; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Models.Mapping; -using Umbraco.Web.Mvc; -using Umbraco.Web.UI; -using Umbraco.Web.WebApi; -using umbraco; -using legacyUser = umbraco.BusinessLogic.User; -using System.Net.Http; -using System.Collections.Specialized; -using Constants = Umbraco.Core.Constants; - - -namespace Umbraco.Web.Editors -{ - /// - /// Controller to back the User.Resource service, used for fetching user data when already authenticated. user.service is currently used for handling authentication - /// - [PluginController("UmbracoApi")] - public class UserController : UmbracoAuthorizedJsonController - { - - /// - /// Returns the configuration for the backoffice user membership provider - used to configure the change password dialog - /// - /// - public IDictionary GetMembershipProviderConfig() - { - var provider = Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider]; - if (provider == null) - { - throw new InvalidOperationException("No back office membership provider found with the name " + UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); - } - return provider.GetConfiguration(); - } - - /// - /// Returns a user by id - /// - /// - /// - public UserDetail GetById(int id) - { - var user = Services.UserService.GetUserById(id); - if (user == null) - { - throw new HttpResponseException(HttpStatusCode.NotFound); - } - - - return Mapper.Map(user); - } - - /// - /// Changes the users password - /// - /// - /// - /// If the password is being reset it will return the newly reset password, otherwise will return an empty value - /// - public ModelWithNotifications PostChangePassword(ChangingPasswordModel data) - { - var userProvider = Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider]; - if (userProvider == null) - { - throw new InvalidOperationException("No membership provider found with the name " + UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); - } - - //TODO: WE need to support this! - requires UI updates, etc... - if (userProvider.RequiresQuestionAndAnswer) - { - throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified"); - } - - var passwordChangeResult = Security.ChangePassword(Security.CurrentUser.Username, data, userProvider); - if (passwordChangeResult.Success) - { - //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword - var result = new ModelWithNotifications(passwordChangeResult.Result.ResetPassword); - result.AddSuccessNotification(ui.Text("user", "password"), ui.Text("user", "passwordChanged")); - return result; - } - - //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form - // so that is why it is being used here. - ModelState.AddPropertyError( - passwordChangeResult.Result.ChangeError, - string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); - - throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); - } - - /// - /// Returns all active users - /// - /// - public IEnumerable GetAll() - { - return Services.UserService.GetAllUsers().Where(x => x.IsLockedOut == false).Select(Mapper.Map); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using System.Web.Security; +using AutoMapper; +using Umbraco.Core.Configuration; +using Umbraco.Web.Models; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Mapping; +using Umbraco.Web.Mvc; +using Umbraco.Web.UI; +using Umbraco.Web.WebApi; +using umbraco; +using legacyUser = umbraco.BusinessLogic.User; +using System.Net.Http; +using System.Collections.Specialized; +using Constants = Umbraco.Core.Constants; + + +namespace Umbraco.Web.Editors +{ + /// + /// Controller to back the User.Resource service, used for fetching user data when already authenticated. user.service is currently used for handling authentication + /// + [PluginController("UmbracoApi")] + public class CurrentUserController : UmbracoAuthorizedJsonController + { + + /// + /// Returns the configuration for the backoffice user membership provider - used to configure the change password dialog + /// + /// + public IDictionary GetMembershipProviderConfig() + { + var provider = Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider]; + if (provider == null) + { + throw new InvalidOperationException("No back office membership provider found with the name " + UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); + } + return provider.GetConfiguration(); + } + + /// + /// Changes the users password + /// + /// + /// + /// If the password is being reset it will return the newly reset password, otherwise will return an empty value + /// + public ModelWithNotifications PostChangePassword(ChangingPasswordModel data) + { + var userProvider = Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider]; + if (userProvider == null) + { + throw new InvalidOperationException("No membership provider found with the name " + UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); + } + + //TODO: WE need to support this! - requires UI updates, etc... + if (userProvider.RequiresQuestionAndAnswer) + { + throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified"); + } + + var passwordChangeResult = Security.ChangePassword(Security.CurrentUser.Username, data, userProvider); + if (passwordChangeResult.Success) + { + //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword + var result = new ModelWithNotifications(passwordChangeResult.Result.ResetPassword); + result.AddSuccessNotification(ui.Text("user", "password"), ui.Text("user", "passwordChanged")); + return result; + } + + //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form + // so that is why it is being used here. + ModelState.AddPropertyError( + passwordChangeResult.Result.ChangeError, + string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); + + throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); + } + + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a9173caa86..563d415509 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -362,7 +362,7 @@ - +