From 0f207b01f27aa0be62675e2f004df57540763b63 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 10 Jul 2013 13:24:28 +1000 Subject: [PATCH] Integrated auth into the UI project and unit tests (you need to log in each time with arbitrary username/password). Fixes authorization, the auth check SHOULD return a 401 so that the MainController re-fires the auth check in order to re-set the 'authenticated' scope flag. Fixed err caused by trying to launch login dialog too many times when too many http calls fail. Converted over authResource to use correct resourcePromise structure. The mock auth is done with angular cookies, so integrated that too. Removes main.js since we don't use it anymore. Fixes media mocks. Removes call to get sections in navigationService since it is irrelevant and causing more issues when not authenticated. --- .../lib/angular/angular-cookies.js | 326 +++++++++--------- .../lib/angular/angular-cookies.min.js | 10 +- src/Umbraco.Web.UI.Client/src/app.dev.js | 3 +- src/Umbraco.Web.UI.Client/src/app.js | 3 +- .../directives/umbproperty.directive.js | 7 +- .../src/common/mocks/resources/_module.js | 2 +- .../src/common/mocks/resources/_utills.js | 66 +++- .../common/mocks/resources/content.mocks.js | 10 + .../mocks/resources/contenttype.mocks.js | 5 + .../src/common/mocks/resources/media.mocks.js | 9 +- .../mocks/resources/section.resource.js | 5 + .../src/common/mocks/resources/tree.mocks.js | 13 + .../src/common/mocks/resources/user.mocks.js | 43 ++- .../src/common/mocks/umbraco.httpbackend.js | 5 +- .../src/common/resources/auth.resource.js | 14 +- .../src/common/security/security.service.js | 169 ++++----- .../src/common/services/navigation.service.js | 5 +- .../src/common/services/user.service.js | 51 ++- src/Umbraco.Web.UI.Client/src/loader.js | 3 +- src/Umbraco.Web.UI.Client/src/main.js | 75 ---- .../src/views/common/main.controller.js | 4 +- .../test/config/app.unit.js | 3 +- .../test/config/karma.conf.js | 1 + src/Umbraco.Web.UI.Client/test/config/unit.js | 1 + .../app/content/editContentController.spec.js | 6 +- .../common/services/contentFactory.spec.js | 6 +- .../services/contenttypeFactory.spec.js | 6 +- src/Umbraco.Web.UI/umbraco/js/app.dev.js | 3 +- src/Umbraco.Web.UI/umbraco/js/loader.js | 3 +- .../Editors/AuthenticationController.cs | 6 +- src/Umbraco.Web/UI/JavaScript/JsInitialize.js | 2 +- 31 files changed, 421 insertions(+), 444 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/main.js diff --git a/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.js b/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.js index fbf0acb406..44a728d2c4 100644 --- a/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.js +++ b/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.js @@ -1,183 +1,185 @@ /** - * @license AngularJS v1.0.5 + * @license AngularJS v1.0.7 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ -(function(window, angular, undefined) { -'use strict'; +(function (window, angular, undefined) { + 'use strict'; -/** - * @ngdoc overview - * @name ngCookies - */ + /** + * @ngdoc overview + * @name ngCookies + */ -angular.module('ngCookies', ['ng']). - /** - * @ngdoc object - * @name ngCookies.$cookies - * @requires $browser - * - * @description - * Provides read/write access to browser's cookies. - * - * Only a simple Object is exposed and by adding or removing properties to/from - * this object, new cookies are created/deleted at the end of current $eval. - * - * @example - - - - - - */ - factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { - var cookies = {}, - lastCookies = {}, - lastBrowserCookies, - runEval = false, - copy = angular.copy, - isUndefined = angular.isUndefined; + angular.module('ngCookies', ['ng']). + /** + * @ngdoc object + * @name ngCookies.$cookies + * @requires $browser + * + * @description + * Provides read/write access to browser's cookies. + * + * Only a simple Object is exposed and by adding or removing properties to/from + * this object, new cookies are created/deleted at the end of current $eval. + * + * @example + + + + + + */ + factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { + var cookies = {}, + lastCookies = {}, + lastBrowserCookies, + runEval = false, + copy = angular.copy, + isUndefined = angular.isUndefined; - //creates a poller fn that copies all cookies from the $browser to service & inits the service - $browser.addPollFn(function() { - var currentCookies = $browser.cookies(); - if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl - lastBrowserCookies = currentCookies; - copy(currentCookies, lastCookies); - copy(currentCookies, cookies); - if (runEval) $rootScope.$apply(); - } - })(); + //creates a poller fn that copies all cookies from the $browser to service & inits the service + $browser.addPollFn(function () { + var currentCookies = $browser.cookies(); + if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl + lastBrowserCookies = currentCookies; + copy(currentCookies, lastCookies); + copy(currentCookies, cookies); + if (runEval) $rootScope.$apply(); + } + })(); - runEval = true; + runEval = true; - //at the end of each eval, push cookies - //TODO: this should happen before the "delayed" watches fire, because if some cookies are not - // strings or browser refuses to store some cookies, we update the model in the push fn. - $rootScope.$watch(push); + //at the end of each eval, push cookies + //TODO: this should happen before the "delayed" watches fire, because if some cookies are not + // strings or browser refuses to store some cookies, we update the model in the push fn. + $rootScope.$watch(push); - return cookies; + return cookies; + + + /** + * Pushes all the cookies from the service to the browser and verifies if all cookies were stored. + */ + function push() { + var name, + value, + browserCookies, + updated; + + //delete any cookies deleted in $cookies + for (name in lastCookies) { + if (isUndefined(cookies[name])) { + $browser.cookies(name, undefined); + } + } + + //update all cookies updated in $cookies + for (name in cookies) { + value = cookies[name]; + if (!angular.isString(value)) { + if (angular.isDefined(lastCookies[name])) { + cookies[name] = lastCookies[name]; + } else { + delete cookies[name]; + } + } else if (value !== lastCookies[name]) { + $browser.cookies(name, value); + updated = true; + } + } + + //verify what was actually stored + if (updated) { + updated = false; + browserCookies = $browser.cookies(); + + for (name in cookies) { + if (cookies[name] !== browserCookies[name]) { + //delete or reset all cookies that the browser dropped from $cookies + if (isUndefined(browserCookies[name])) { + delete cookies[name]; + } else { + cookies[name] = browserCookies[name]; + } + updated = true; + } + } + } + } + }]). /** - * Pushes all the cookies from the service to the browser and verifies if all cookies were stored. + * @ngdoc object + * @name ngCookies.$cookieStore + * @requires $cookies + * + * @description + * Provides a key-value (string-object) storage, that is backed by session cookies. + * Objects put or retrieved from this storage are automatically serialized or + * deserialized by angular's toJson/fromJson. + * @example */ - function push() { - var name, - value, - browserCookies, - updated; + factory('$cookieStore', ['$cookies', function ($cookies) { - //delete any cookies deleted in $cookies - for (name in lastCookies) { - if (isUndefined(cookies[name])) { - $browser.cookies(name, undefined); - } - } + return { + /** + * @ngdoc method + * @name ngCookies.$cookieStore#get + * @methodOf ngCookies.$cookieStore + * + * @description + * Returns the value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {Object} Deserialized cookie value. + */ + get: function (key) { + var value = $cookies[key]; + return value ? angular.fromJson(value) : value; + }, - //update all cookies updated in $cookies - for(name in cookies) { - value = cookies[name]; - if (!angular.isString(value)) { - if (angular.isDefined(lastCookies[name])) { - cookies[name] = lastCookies[name]; - } else { - delete cookies[name]; - } - } else if (value !== lastCookies[name]) { - $browser.cookies(name, value); - updated = true; - } - } + /** + * @ngdoc method + * @name ngCookies.$cookieStore#put + * @methodOf ngCookies.$cookieStore + * + * @description + * Sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {Object} value Value to be stored. + */ + put: function (key, value) { + $cookies[key] = angular.toJson(value); + }, - //verify what was actually stored - if (updated){ - updated = false; - browserCookies = $browser.cookies(); + /** + * @ngdoc method + * @name ngCookies.$cookieStore#remove + * @methodOf ngCookies.$cookieStore + * + * @description + * Remove given cookie + * + * @param {string} key Id of the key-value pair to delete. + */ + remove: function (key) { + delete $cookies[key]; + } + }; - for (name in cookies) { - if (cookies[name] !== browserCookies[name]) { - //delete or reset all cookies that the browser dropped from $cookies - if (isUndefined(browserCookies[name])) { - delete cookies[name]; - } else { - cookies[name] = browserCookies[name]; - } - updated = true; - } - } - } - } - }]). + }]); - /** - * @ngdoc object - * @name ngCookies.$cookieStore - * @requires $cookies - * - * @description - * Provides a key-value (string-object) storage, that is backed by session cookies. - * Objects put or retrieved from this storage are automatically serialized or - * deserialized by angular's toJson/fromJson. - * @example - */ - factory('$cookieStore', ['$cookies', function($cookies) { - - return { - /** - * @ngdoc method - * @name ngCookies.$cookieStore#get - * @methodOf ngCookies.$cookieStore - * - * @description - * Returns the value of given cookie key - * - * @param {string} key Id to use for lookup. - * @returns {Object} Deserialized cookie value. - */ - get: function(key) { - return angular.fromJson($cookies[key]); - }, - - /** - * @ngdoc method - * @name ngCookies.$cookieStore#put - * @methodOf ngCookies.$cookieStore - * - * @description - * Sets a value for given cookie key - * - * @param {string} key Id for the `value`. - * @param {Object} value Value to be stored. - */ - put: function(key, value) { - $cookies[key] = angular.toJson(value); - }, - - /** - * @ngdoc method - * @name ngCookies.$cookieStore#remove - * @methodOf ngCookies.$cookieStore - * - * @description - * Remove given cookie - * - * @param {string} key Id of the key-value pair to delete. - */ - remove: function(key) { - delete $cookies[key]; - } - }; - - }]); - -})(window, window.angular); +})(window, window.angular); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.min.js b/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.min.js index bd82c75d2c..2244789e89 100644 --- a/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.min.js +++ b/src/Umbraco.Web.UI.Client/lib/angular/angular-cookies.min.js @@ -1,7 +1,9 @@ -/* - AngularJS v1.0.5 +/* + AngularJS v1.0.7 (c) 2010-2012 Google, Inc. http://angularjs.org License: MIT */ -(function(m,f,l){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,c){var b={},g={},h,i=!1,j=f.copy,k=f.isUndefined;c.addPollFn(function(){var a=c.cookies();h!=a&&(h=a,j(a,g),j(a,b),i&&d.$apply())})();i=!0;d.$watch(function(){var a,e,d;for(a in g)k(b[a])&&c.cookies(a,l);for(a in b)e=b[a],f.isString(e)?e!==g[a]&&(c.cookies(a,e),d=!0):f.isDefined(g[a])?b[a]=g[a]:delete b[a];if(d)for(a in e=c.cookies(),b)b[a]!==e[a]&&(k(e[a])?delete b[a]:b[a]=e[a])});return b}]).factory("$cookieStore", -["$cookies",function(d){return{get:function(c){return f.fromJson(d[c])},put:function(c,b){d[c]=f.toJson(b)},remove:function(c){delete d[c]}}}])})(window,window.angular); +(function (m, f, l) { + 'use strict'; f.module("ngCookies", ["ng"]).factory("$cookies", ["$rootScope", "$browser", function (d, b) { var c = {}, g = {}, h, i = !1, j = f.copy, k = f.isUndefined; b.addPollFn(function () { var a = b.cookies(); h != a && (h = a, j(a, g), j(a, c), i && d.$apply()) })(); i = !0; d.$watch(function () { var a, e, d; for (a in g) k(c[a]) && b.cookies(a, l); for (a in c) e = c[a], f.isString(e) ? e !== g[a] && (b.cookies(a, e), d = !0) : f.isDefined(g[a]) ? c[a] = g[a] : delete c[a]; if (d) for (a in e = b.cookies(), c) c[a] !== e[a] && (k(e[a]) ? delete c[a] : c[a] = e[a]) }); return c }]).factory("$cookieStore", + ["$cookies", function (d) { return { get: function (b) { return (b = d[b]) ? f.fromJson(b) : b }, put: function (b, c) { d[b] = f.toJson(c) }, remove: function (b) { delete d[b] } } }]) +})(window, window.angular); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/app.dev.js b/src/Umbraco.Web.UI.Client/src/app.dev.js index fd806e6d25..42b4abb61a 100644 --- a/src/Umbraco.Web.UI.Client/src/app.dev.js +++ b/src/Umbraco.Web.UI.Client/src/app.dev.js @@ -4,5 +4,6 @@ var app = angular.module('umbraco', [ 'umbraco.resources', 'umbraco.services', 'umbraco.httpbackend', - 'umbraco.security' + 'umbraco.security', + 'ngCookies' ]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/app.js b/src/Umbraco.Web.UI.Client/src/app.js index 921d490c19..02f45c2447 100644 --- a/src/Umbraco.Web.UI.Client/src/app.js +++ b/src/Umbraco.Web.UI.Client/src/app.js @@ -3,5 +3,6 @@ var app = angular.module('umbraco', [ 'umbraco.directives', 'umbraco.resources', 'umbraco.services', - 'umbraco.security' + 'umbraco.security', + 'ngCookies' ]); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js index dbdce22dd8..01f0dd6890 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js @@ -10,7 +10,12 @@ angular.module("umbraco.directives") restrict: 'E', replace: true, templateUrl: 'views/directives/umb-property.html', - link: function(scope, element, attrs, ctrl) { + link: function (scope, element, attrs, ctrl) { + + if (!scope || !scope.model || !scope.model.view) { + return; + } + scope.propertyEditorView = umbPropEditorHelper.getViewPath(scope.model.view); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_module.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_module.js index ac14bd4a6a..2a9030fe0c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_module.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_module.js @@ -1 +1 @@ -angular.module("umbraco.mocks", []); \ No newline at end of file +angular.module("umbraco.mocks", ['ngCookies']); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utills.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utills.js index 1e31e4aa07..d43cd5cc41 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utills.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utills.js @@ -1,18 +1,52 @@ angular.module('umbraco.mocks'). - factory('mocksUtills', function () { - 'use strict'; + factory('mocksUtills', ['$cookieStore', function($cookieStore) { + 'use strict'; + + //by default we will perform authorization + var doAuth = true; - return { - urlRegex: function(url) { - url = url.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - return new RegExp("^" + url); - }, - - getParameterByName: function(url, name) { - name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); - var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), - results = regex.exec(url); - return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); - } - }; - }); \ No newline at end of file + return { + + /** generally used for unit tests, calling this will disable the auth check and always return true */ + disableAuth: function() { + doAuth = false; + }, + + /** generally used for unit tests, calling this will enabled the auth check */ + enabledAuth: function() { + doAuth = true; + }, + + /** Checks for our mock auth cookie, if it's not there, returns false */ + checkAuth: function () { + if (doAuth) { + var mockAuthCookie = $cookieStore.get("mockAuthCookie"); + if (!mockAuthCookie) { + return false; + } + return true; + } + else { + return true; + } + }, + + /** Creates/sets the auth cookie with a value indicating the user is now authenticated */ + setAuth: function() { + //set the cookie for loging + $cookieStore.put("mockAuthCookie", "Logged in!"); + }, + + urlRegex: function(url) { + url = url.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + return new RegExp("^" + url); + }, + + getParameterByName: function(url, name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(url); + return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + }; + }]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/content.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/content.mocks.js index 1abc57898b..b159d01274 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/content.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/content.mocks.js @@ -3,6 +3,11 @@ angular.module('umbraco.mocks'). 'use strict'; function returnEmptyNode(status, data, headers) { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var response = returnNodebyId(200, "", null); var node = response[1]; var parentId = mocksUtills.getParameterByName(data, "parentId") || 1234; @@ -21,6 +26,11 @@ angular.module('umbraco.mocks'). } function returnNodebyId(status, data, headers) { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var id = mocksUtills.getParameterByName(data, "id") || "1234"; id = parseInt(id, 10); diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/contenttype.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/contenttype.mocks.js index fdc15f5b30..594094e711 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/contenttype.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/contenttype.mocks.js @@ -3,6 +3,11 @@ angular.module('umbraco.mocks'). 'use strict'; function returnAllowedChildren(status, data, headers) { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var types = [ { name: "News Article", description: "Standard news article", alias: "newsArticle", id: 1234, cssClass: "file" }, { name: "News Area", description: "Area to hold all news articles, there should be only one", alias: "newsArea", id: 1234, cssClass: "suitcase" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js index 84c2bc5fe2..68c36b6280 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js @@ -3,6 +3,11 @@ angular.module('umbraco.mocks'). 'use strict'; function returnNodebyId(status, data, headers) { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var id = mocksUtills.getParameterByName(data, "id") || 1234; var node = { @@ -81,12 +86,12 @@ angular.module('umbraco.mocks'). return { register: function() { $httpBackend - .whenGET(mocksUtills.urlRegex('/umbraco/UmbracoApi/Content/GetById')) + .whenGET(mocksUtills.urlRegex('/umbraco/UmbracoApi/Media/GetById')) .respond(returnNodebyId); }, expectGetById: function() { $httpBackend - .expectGET(mocksUtills.urlRegex('/umbraco/UmbracoApi/Content/GetById')); + .expectGET(mocksUtills.urlRegex('/umbraco/UmbracoApi/Media/GetById')); } }; }]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/section.resource.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/section.resource.js index bd866495b8..d9c4107b25 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/section.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/section.resource.js @@ -7,6 +7,11 @@ function sectionMocks($httpBackend, mocksUtills) { /** internal method to mock the sections to be returned */ function getSections() { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var sections = [ { name: "Content", cssclass: "traycontent", alias: "content" }, { name: "Media", cssclass: "traymedia", alias: "media" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js index 3f648ea8f6..c45d1e3b41 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js @@ -4,6 +4,10 @@ angular.module('umbraco.mocks'). function getMenuItems() { + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var menu = [ { name: "Create", cssclass: "plus", alias: "create" }, @@ -30,6 +34,10 @@ angular.module('umbraco.mocks'). function returnChildren(status, data, headers) { + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var id = mocksUtills.getParameterByName(data, "id"); var section = mocksUtills.getParameterByName(data, "treeType"); var level = mocksUtills.getParameterByName(data, "level")+1; @@ -54,6 +62,11 @@ angular.module('umbraco.mocks'). } function returnApplicationTrees(status, data, headers) { + + if (!mocksUtills.checkAuth()) { + return [401, null, null]; + } + var section = mocksUtills.getParameterByName(data, "application"); var url = "/umbraco/UmbracoTrees/ApplicationTreeApi/GetChildren?treeType=" + section + "&id=1234&level=1"; var menuUrl = "/umbraco/UmbracoTrees/ApplicationTreeApi/GetMenu?treeType=" + section + "&id=1234&parentId=456"; diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.mocks.js index 0255023f0f..ca8e005cc3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.mocks.js @@ -1,25 +1,34 @@ angular.module('umbraco.mocks'). factory('userMocks', ['$httpBackend', 'mocksUtills', function ($httpBackend, mocksUtills) { 'use strict'; - - var firsttry = true; - function returnUser(status, data, headers) { - var app = mocksUtills.getParameterByName(data, "application"); + + var mocked = { + name: "Per Ploug", + email: "test@test.com", + emailHash: "f9879d71855b5ff21e4963273a886bfc", + id: 0, + locale: 'da-DK' + }; - var mocked = { - name: "Per Ploug", - email: "test@test.com", - emailHash: "f9879d71855b5ff21e4963273a886bfc", - id: 0, - locale: 'da-DK' - }; - - if (firsttry) { - firsttry = false; - return [200, mocked, null]; - } else { + function getCurrentUser(status, data, headers) { + //check for existence of a cookie so we can do login/logout in the belle app (ignore for tests). + if (!mocksUtills.checkAuth()) { + //return a 204 with a null value + //return [204, null, null]; + + return [401, null, null]; + } + else { return [200, mocked, null]; } + } + + function returnUser(status, data, headers) { + + //set the cookie for loging + mocksUtills.setAuth(); + + return [200, mocked, null]; } return { @@ -32,7 +41,7 @@ angular.module('umbraco.mocks'). $httpBackend .whenGET('/umbraco/UmbracoApi/Authentication/GetCurrentUser') - .respond(returnUser); + .respond(getCurrentUser); } diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/umbraco.httpbackend.js b/src/Umbraco.Web.UI.Client/src/common/mocks/umbraco.httpbackend.js index 2c0568bf65..2ccbe13d67 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/umbraco.httpbackend.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/umbraco.httpbackend.js @@ -1,12 +1,13 @@ var umbracoAppDev = angular.module('umbraco.httpbackend', ['umbraco', 'ngMockE2E', 'umbraco.mocks']); -function initBackEnd($httpBackend, contentMocks, treeMocks, userMocks, contentTypeMocks, sectionMocks) { +function initBackEnd($httpBackend, contentMocks, mediaMocks, treeMocks, userMocks, contentTypeMocks, sectionMocks) { console.log("httpBackend inited"); //Register mocked http responses - contentMocks.register(); + contentMocks.register(); + mediaMocks.register(); sectionMocks.register(); treeMocks.register(); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js index 63ef482ddc..18d78a8789 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js @@ -33,19 +33,7 @@ function authResource($q, $http, angularHelper) { return angularHelper.resourcePromise( $http.get(getIsAuthUrl()), - { - success: function (data, status, headers, config) { - //204 - means the current user is not-authorized, the result was empty. - if (status === 204) { - //if it's unauthorized it just means we are not authenticated so we'll just return null - return null; - } - else { - return data; - } - }, - errorMsg: 'Server call failed for checking authorization' - }); + 'Server call failed for checking authorization'); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/common/security/security.service.js b/src/Umbraco.Web.UI.Client/src/common/security/security.service.js index 4e4f2adc77..fc8b51f121 100644 --- a/src/Umbraco.Web.UI.Client/src/common/security/security.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/security/security.service.js @@ -1,5 +1,8 @@ // Based loosely around work by Witold Szczerba - https://github.com/witoldsz/angular-http-auth +//TODO: We need to streamline the usage of this class and the overlap it has with userService and authResource! +// SD: IMO, I think we can remove this class and just put this all into the userService class. + angular.module('umbraco.security.service', [ 'umbraco.security.retryQueue', // Keeps track of failed requests that need to be retried once the user logs in 'umbraco.resources', @@ -8,112 +11,72 @@ angular.module('umbraco.security.service', [ .factory('security', ['$http', '$q', '$location', 'securityRetryQueue', 'authResource', 'dialogService', '$log', function ($http, $q, $location, queue, authResource, dialogService, $log) { - // Register a handler for when an item is added to the retry queue - queue.onItemAddedCallbacks.push(function (retryItem) { - if (queue.hasMore()) { - service.showLogin(); - } - }); - - - // Redirect to the given url (defaults to '/') - function redirect(url) { - url = url || '/'; - $location.path(url); - } - - // Login form dialog stuff - var loginDialog = null; - - function openLoginDialog() { - if ( loginDialog ) { - throw new Error('Trying to open a dialog that is already open!'); - } - - loginDialog = dialogService.open({ - template: 'views/common/dialogs/login.html', - modalClass: "login-overlay", - animation: "slide", - show: true, - callback: onLoginDialogClose}); - } - - //function closeLoginDialog(success) { - // if (loginDialog) { - // loginDialog = null; - // } - //} - - function onLoginDialogClose(success) { - loginDialog = null; - - if ( success ) { - queue.retryAll(); - } else { - queue.cancelAll(); - redirect(); - } - } - - //TODO: Clean this class up since most of this doesn't do anything! + // Register a handler for when an item is added to the retry queue + queue.onItemAddedCallbacks.push(function (retryItem) { + if (queue.hasMore()) { + service.showLogin(); + } + }); - // The public API of the service - var service = { - - //// Get the first reason for needing a login - //getLoginReason: function() { - // return queue.retryReason(); - //}, - - // Show the modal login dialog - showLogin: function() { - openLoginDialog(); - }, - - //// Attempt to authenticate a user by the given email and password - //login: function(email, password) { - // var request = $http.post('/login', {email: email, password: password}); - // return request.then(function(response) { - // service.currentUser = response.data.user; - // if ( service.isAuthenticated() ) { - // closeLoginDialog(true); - // } - // }); - //}, - - //// Give up trying to login and clear the retry queue - //cancelLogin: function() { - // closeLoginDialog(false); - // redirect(); - //}, - - //// Logout the current user and redirect - //logout: function(redirectTo) { - // $http.post('/logout').then(function() { - // service.currentUser = null; - // redirect(redirectTo); - // }); - //}, - - // Ask the backend to see if a user is already authenticated - this may be from a previous session. - requestCurrentUser: function() { - if ( service.isAuthenticated() ) { - return $q.when(service.currentUser); - } else { - service.currentUser = authResource.currentUser; - return service.currentUser; + // Redirect to the given url (defaults to '/') + function redirect(url) { + url = url || '/'; + $location.path(url); } - }, - // Information about the current user - currentUser: null, + // Login form dialog stuff + var loginDialog = null; - // Is the current user authenticated? - isAuthenticated: function(){ - return !!service.currentUser; - } - }; + function openLoginDialog() { + if (!loginDialog) { + loginDialog = dialogService.open({ + template: 'views/common/dialogs/login.html', + modalClass: "login-overlay", + animation: "slide", + show: true, + callback: onLoginDialogClose + }); + } + } - return service; -}]); \ No newline at end of file + function onLoginDialogClose(success) { + loginDialog = null; + + if (success) { + queue.retryAll(); + } else { + queue.cancelAll(); + redirect(); + } + } + + // The public API of the service + var service = { + + // Show the modal login dialog + showLogin: function () { + openLoginDialog(); + }, + + // Ask the backend to see if a user is already authenticated - this may be from a previous session. + requestCurrentUser: function () { + if (service.isAuthenticated()) { + return $q.when(service.currentUser); + } else { + service.currentUser = authResource.currentUser; + return service.currentUser; + } + }, + + // Information about the current user + currentUser: null, + + // Is the current user authenticated? + isAuthenticated: function () { + return !!service.currentUser; + } + }; + + return service; + }]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 7f5832a152..0bbca1b7cd 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -24,8 +24,6 @@ angular.module('umbraco.services') var currentNode; var ui = {}; - var _sections = sectionResource.getSections(); - function setMode(mode) { switch (mode) { case 'tree': @@ -69,8 +67,7 @@ angular.module('umbraco.services') currentNode: currentNode, mode: "default", ui: ui, - sections: _sections, - + /** * @ngdoc method * @name umbraco.services.navigationService#load diff --git a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js index 0af24cf1d4..aa78bf5c17 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js @@ -1,48 +1,41 @@ angular.module('umbraco.services') .factory('userService', function (authResource, $q) { - var currentUser = null; + var currentUser = null; return { - + /** Returns a promise, sends a request to the server to check if the current cookie is authorized */ - isAuthenticated: function() { - var deferred = $q.defer(); - - $q.when(authResource.isAuthenticated()) + isAuthenticated: function () { + + return $q.when(authResource.isAuthenticated()) .then(function(data) { - currentUser = data; - currentUser.avatar = 'http://www.gravatar.com/avatar/' + data.emailHash + '?s=40'; - - //note, this can return null if they are not authenticated - deferred.resolve({ user: data, authenticated: true }); - }, - function(reason) { - deferred.reject(reason); - }); - return deferred.promise; - }, + //note, this can return null if they are not authenticated + if (!data) { + throw "Not authenticated"; + } + else { + currentUser = data; + currentUser.avatar = 'http://www.gravatar.com/avatar/' + data.emailHash + '?s=40'; + return { user: data, authenticated: true }; + } + }); + }, /** Returns a promise, sends a request to the server to validate the credentials */ authenticate: function (login, password) { - var deferred = $q.defer(); - - $q.when(authResource.performLogin(login, password)) - .then(function(data) { + return $q.when(authResource.performLogin(login, password)) + .then(function (data) { + //when it's successful, return the user data currentUser = data; - deferred.resolve({ user: data, authenticated: true }); - }, - function(reason) { - deferred.reject(reason); - }); - - return deferred.promise; + return { user: data, authenticated: true }; + }); }, logout: function () { - $rootScope.$apply(function () { + $rootScope.$apply(function () { currentUser = undefined; }); }, diff --git a/src/Umbraco.Web.UI.Client/src/loader.js b/src/Umbraco.Web.UI.Client/src/loader.js index 1c8490e1f1..b00e75f242 100644 --- a/src/Umbraco.Web.UI.Client/src/loader.js +++ b/src/Umbraco.Web.UI.Client/src/loader.js @@ -2,8 +2,9 @@ yepnope({ load: [ 'lib/jquery/jquery-1.8.2.min.js', - 'lib/jquery/jquery.cookie.js', + 'lib/angular/angular.min.js', + 'lib/angular/angular-cookies.min.js', 'lib/angular/angular-mocks.js', 'lib/bootstrap/js/bootstrap.js', 'lib/underscore/underscore.js', diff --git a/src/Umbraco.Web.UI.Client/src/main.js b/src/Umbraco.Web.UI.Client/src/main.js deleted file mode 100644 index 77187671ef..0000000000 --- a/src/Umbraco.Web.UI.Client/src/main.js +++ /dev/null @@ -1,75 +0,0 @@ -require.config({ - waitSeconds: 120, - paths: { - app: 'app_dev', - jquery: '../lib/jquery/jquery-1.8.2.min', - jqueryCookie: '../lib/jquery/jquery.cookie', - umbracoExtensions: "../lib/umbraco/extensions", - bootstrap: '../lib/bootstrap/js/bootstrap', - underscore: '../lib/underscore/underscore', - angular: '../lib/angular/angular.min', - angularResource: '../lib/angular/angular-resource', - - app: 'app_dev', - - codemirror: '../lib/codemirror/js/lib/codemirror', - codemirrorJs: '../lib/codemirror/js/mode/javascript/javascript', - codemirrorCss: '../lib/codemirror/js/mode/css/css', - codemirrorXml: '../lib/codemirror/js/mode/xml/xml', - codemirrorHtml: '../lib/codemirror/js/mode/htmlmixed/htmlmixed', - - tinymce: '../lib/tinymce/tinymce.min', - text: '../lib/require/text', - async: '../lib/require/async', - css: '../lib/require/css' - }, - shim: { - 'angular' : {'exports' : 'angular'}, - 'angular-resource': { deps: ['angular'] }, - 'bootstrap': { deps: ['jquery'] }, - 'jqueryCookie': { deps: ['jquery'] }, - 'underscore': {exports: '_'}, - 'codemirror': {exports: 'CodeMirror'}, - 'codemirrorJs':{deps:['codemirror']}, - 'codemirrorCss':{deps:['codemirror']}, - 'codemirrorXml':{deps:['codemirror']}, - 'codemirrorHtml':{deps:['codemirrorXml','codemirrorCss','codemirrorJs'], exports: 'mixedMode'}, - 'tinymce': { - exports: 'tinyMCE', - init: function () { - this.tinymce.DOM.events.domLoaded = true; - return this.tinymce; - } - } - }, - priority: [ - "angular" - ], - urlArgs: 'v=1.1' -}); - -require( [ - 'angular', - 'app', - 'jquery', - 'jqueryCookie', - 'bootstrap', - 'umbracoExtensions', - 'umbraco.mocks', - 'umbraco.directives', - 'umbraco.filters', - 'umbraco.services', - 'umbraco.security', - 'umbraco.controllers', - 'routes' - ], function(angular, app, jQuery) { - //This function will be called when all the dependencies - //listed above are loaded. Note that this function could - //be called before the page is loaded. - //This callback is optional. - - jQuery(document).ready(function () { - angular.bootstrap(document, ['umbraco']); - }); - -}); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js index 710e7ce619..d421919984 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js @@ -10,7 +10,9 @@ */ function MainController($scope, $routeParams, $rootScope, $timeout, notificationsService, userService, navigationService, legacyJsLoader) { //set default properties - $scope.authenticated = null; //the null is important because we do an explicit bool check on this in the view + + //the null is important because we do an explicit bool check on this in the view + $scope.authenticated = null; //subscribes to notifications in the notification service $scope.notifications = notificationsService.current; diff --git a/src/Umbraco.Web.UI.Client/test/config/app.unit.js b/src/Umbraco.Web.UI.Client/test/config/app.unit.js index e21617e5f5..ed1d63bc18 100644 --- a/src/Umbraco.Web.UI.Client/test/config/app.unit.js +++ b/src/Umbraco.Web.UI.Client/test/config/app.unit.js @@ -4,5 +4,6 @@ var app = angular.module('umbraco', [ 'umbraco.resources', 'umbraco.services', 'umbraco.mocks', - 'umbraco.security' + 'umbraco.security', + 'ngCookies' ]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js index 8b6f171072..9a012be1a0 100644 --- a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js +++ b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js @@ -9,6 +9,7 @@ module.exports = function(karma) { files: [ 'lib/jquery/jquery-1.8.2.min.js', 'lib/angular/angular.min.js', + 'lib/angular/angular-cookies.min.js', 'lib/underscore/underscore.js', 'test/lib/angular/angular-mocks.js', 'lib/umbraco/Extensions.js', diff --git a/src/Umbraco.Web.UI.Client/test/config/unit.js b/src/Umbraco.Web.UI.Client/test/config/unit.js index d84fed1171..7f8b49e30e 100644 --- a/src/Umbraco.Web.UI.Client/test/config/unit.js +++ b/src/Umbraco.Web.UI.Client/test/config/unit.js @@ -8,6 +8,7 @@ files = [ 'lib/jquery/jquery-1.8.2.min.js', 'lib/angular/angular.min.js', + 'lib/angular/angular-cookies.min.js', 'test/lib/angular/angular-mocks.js', 'lib/umbraco/Extensions.js', 'src/app_dev.js', diff --git a/src/Umbraco.Web.UI.Client/test/unit/app/content/editContentController.spec.js b/src/Umbraco.Web.UI.Client/test/unit/app/content/editContentController.spec.js index fd1d963e16..d8dd8277a9 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/app/content/editContentController.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/app/content/editContentController.spec.js @@ -5,7 +5,11 @@ describe('edit content controller tests', function () { beforeEach(module('umbraco')); //inject the contentMocks service - beforeEach(inject(function ($rootScope, $controller, angularHelper, $httpBackend, contentMocks) { + beforeEach(inject(function ($rootScope, $controller, angularHelper, $httpBackend, contentMocks, mocksUtills) { + + //for these tests we don't want any authorization to occur + mocksUtills.disableAuth(); + httpBackend = $httpBackend; scope = $rootScope.$new(); diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/contentFactory.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/contentFactory.spec.js index 51d0d49a8d..349fde0549 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/contentFactory.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/contentFactory.spec.js @@ -5,7 +5,11 @@ describe('content factory tests', function () { beforeEach(module('umbraco.resources')); beforeEach(module('umbraco.mocks')); - beforeEach(inject(function ($injector) { + beforeEach(inject(function ($injector, mocksUtills) { + + //for these tests we don't want any authorization to occur + mocksUtills.disableAuth(); + $rootScope = $injector.get('$rootScope'); $httpBackend = $injector.get('$httpBackend'); mocks = $injector.get("contentMocks"); diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/contenttypeFactory.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/contenttypeFactory.spec.js index 390820552c..261c5c0e8b 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/contenttypeFactory.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/contenttypeFactory.spec.js @@ -5,7 +5,11 @@ describe('content type factory tests', function () { beforeEach(module('umbraco.resources')); beforeEach(module('umbraco.mocks')); - beforeEach(inject(function ($injector) { + beforeEach(inject(function ($injector, mocksUtills) { + + //for these tests we don't want any authorization to occur + mocksUtills.disableAuth(); + $rootScope = $injector.get('$rootScope'); $httpBackend = $injector.get('$httpBackend'); mocks = $injector.get("contentTypeMocks"); diff --git a/src/Umbraco.Web.UI/umbraco/js/app.dev.js b/src/Umbraco.Web.UI/umbraco/js/app.dev.js index fd806e6d25..42b4abb61a 100644 --- a/src/Umbraco.Web.UI/umbraco/js/app.dev.js +++ b/src/Umbraco.Web.UI/umbraco/js/app.dev.js @@ -4,5 +4,6 @@ var app = angular.module('umbraco', [ 'umbraco.resources', 'umbraco.services', 'umbraco.httpbackend', - 'umbraco.security' + 'umbraco.security', + 'ngCookies' ]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/js/loader.js b/src/Umbraco.Web.UI/umbraco/js/loader.js index 1c8490e1f1..b00e75f242 100644 --- a/src/Umbraco.Web.UI/umbraco/js/loader.js +++ b/src/Umbraco.Web.UI/umbraco/js/loader.js @@ -2,8 +2,9 @@ yepnope({ load: [ 'lib/jquery/jquery-1.8.2.min.js', - 'lib/jquery/jquery.cookie.js', + 'lib/angular/angular.min.js', + 'lib/angular/angular-cookies.min.js', 'lib/angular/angular-mocks.js', 'lib/bootstrap/js/bootstrap.js', 'lib/underscore/underscore.js', diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 505d12253d..6dcf4cf149 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -43,11 +43,9 @@ namespace Umbraco.Web.Editors Services.UserService.GetUserById( UmbracoContext.Security.GetUserId(UmbracoContext.Security.UmbracoUserContextId)); return _userModelMapper.ToUserDetail(user); - } + } - //don't return not-authorized because this method is here to check if the current user is authorized. - // if they are not, then we just return no content. - throw new HttpResponseException(HttpStatusCode.NoContent); + throw new HttpResponseException(HttpStatusCode.Unauthorized); } public UserDetail PostLogin(string username, string password) diff --git a/src/Umbraco.Web/UI/JavaScript/JsInitialize.js b/src/Umbraco.Web/UI/JavaScript/JsInitialize.js index a4a5eacec6..ff9815f03b 100644 --- a/src/Umbraco.Web/UI/JavaScript/JsInitialize.js +++ b/src/Umbraco.Web/UI/JavaScript/JsInitialize.js @@ -1,7 +1,7 @@ [ 'lib/jquery/jquery-1.8.2.min.js', - 'lib/jquery/jquery.cookie.js', 'lib/angular/angular.min.js', + 'lib/angular/angular-cookies.min.js', 'lib/bootstrap/js/bootstrap.js', 'lib/underscore/underscore.js', 'lib/umbraco/Extensions.js',