From 9a0f50f0fa33b0c31aa12a11b2259e9257c0e0a9 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Tue, 2 Jul 2013 02:37:36 -0400 Subject: [PATCH] License check added immediately after login. If key is invalid, user will bis not permitted to continue. If expiration date has past, server is in demo mode, or all allowed hosts have been used, a warning dialog is displayed. --- awx/ui/static/js/app.js | 9 +-- .../static/js/controllers/Authentication.js | 19 +++++- awx/ui/static/js/helpers/Access.js | 61 ++++++++++++++++++- awx/ui/static/lib/ansible/authenticate.js | 30 +++++++++ awx/ui/static/lib/ansible/rest-services.js | 2 +- awx/ui/static/lib/ansible/utilities.js | 35 +++++++++-- awx/ui/templates/ui/index.html | 24 ++++++-- 7 files changed, 159 insertions(+), 21 deletions(-) diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 82728ebc3c..63e6607485 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -207,8 +207,8 @@ angular.module('ansible', [ otherwise({redirectTo: '/'}); }]) - .run(['$rootScope', '$location', 'Authorization','LoadBasePaths', - function($rootScope, $location, Authorization, LoadBasePaths) { + .run(['$rootScope', 'CheckLicense', '$location', 'Authorization','LoadBasePaths', + function($rootScope, CheckLicense, $location, Authorization, LoadBasePaths) { LoadBasePaths(); @@ -226,6 +226,7 @@ angular.module('ansible', [ if ($rootScope.current_user == undefined || $rootScope.current_user == null) { Authorization.restoreUserInfo(); //user must have hit browser refresh } + CheckLicense(); } // Make the correct tab active var base = ($location.path().replace(/^\//,'').split('/')[0]); @@ -236,13 +237,13 @@ angular.module('ansible', [ base.replace(/\_/g,' '); $('.nav-tabs a[href="#' + base + '"]').tab('show'); } - }); + }); if (! Authorization.isTokenValid() ) { // When the app first loads, redirect to login page $location.path('/login'); } - + // If browser refresh, activate the correct tab var base = ($location.path().replace(/^\//,'').split('/')[0]); if (base == '') { diff --git a/awx/ui/static/js/controllers/Authentication.js b/awx/ui/static/js/controllers/Authentication.js index 8d4b77bf63..c973160e24 100644 --- a/awx/ui/static/js/controllers/Authentication.js +++ b/awx/ui/static/js/controllers/Authentication.js @@ -41,20 +41,32 @@ function Authenticate($scope, $rootScope, $location, Authorization, ToggleClass, // Call the API to get an auth token $scope.systemLogin = function(username, password) { + $('.api-error').empty(); + var token; + Authorization.retrieveToken(username, password) .success( function(data, status, headers, config) { + token = data.token; Authorization.setToken(data.token); $scope.reset(); + // Get all the profile/access info regarding the logged in user Authorization.getUser() .success(function(data, status, headers, config) { $('#login-modal').modal('hide'); Authorization.setUserInfo(data); - $location.path('/organizations'); + Authorization.getLicense() + .success(function(data, status, headers, config) { + Authorization.setLicense(data['license_info']); + $location.path('/organizations'); + }) + .error(function(data, status, headers, config) { + Alert('Error', 'Failed to access user information. GET returned status: ' + status); + }); }) .error( function(data, status, headers, config) { - Alert('Error', 'Failed to get user data from /api/v1/me. GET status: ' + status); + Alert('Error', 'Failed to access license information. GET returned status: ' + status); }); }) .error( function(data, status, headers, config) { @@ -79,3 +91,6 @@ function Authenticate($scope, $rootScope, $location, Authorization, ToggleClass, }); } } + +Authenticate.$inject = ['$scope', '$rootScope', '$location', 'Authorization', 'ToggleClass', 'Alert']; + diff --git a/awx/ui/static/js/helpers/Access.js b/awx/ui/static/js/helpers/Access.js index f4e530680a..f33b93133c 100644 --- a/awx/ui/static/js/helpers/Access.js +++ b/awx/ui/static/js/helpers/Access.js @@ -3,9 +3,9 @@ * */ -angular.module('AccessHelper', ['RestServices', 'Utilities']) - .factory('CheckAccess', ['$rootScope', 'Alert', 'Rest', 'GetBasePath','ProcessErrors', 'Alert', - function($rootScope, Alert, Rest, GetBasePath, ProcessErrors, Prompt) { +angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies']) + .factory('CheckAccess', ['$rootScope', 'Alert', 'Rest', 'GetBasePath','ProcessErrors', + function($rootScope, Alert, Rest, GetBasePath, ProcessErrors) { return function(params) { var me = $rootScope.current_user; var access = false; @@ -33,4 +33,59 @@ angular.module('AccessHelper', ['RestServices', 'Utilities']) } return access; } + }]) + + .factory('CheckLicense', ['$rootScope', '$cookieStore', 'Alert', '$location', 'Authorization', + function($rootScope, $cookieStore, Alert, $location, Authorization) { + return function() { + // Check license status and alert the user, if needed + var status = 'success'; + var hdr, msg; + var license = $cookieStore.get('license'); + if (license && !Authorization.licenseTested()) { + // This is our first time evaluating the license + license['tested'] = true; + $cookieStore.remove('license'); + $cookieStore.put('license', license); + $rootScope.license_tested = true; + if (license['key_valid'] !== undefined && license['key_valid'] == false) { + // The license is invalid. Stop the user from logging in. + status = 'alert-error'; + hdr = 'License Error'; + msg = 'Something is wrong with your /etc/awx/license file on this server. ' + + 'Please contact info@ansibleworks.com for assistance.'; + //action = function() { window.location = '#/logout'; }; + Alert(hdr, msg, status, null, false, true); + } + else if (license['demo'] !== undefined && license['demo'] == true) { + // demo + status = 'alert-info'; + hdr = 'AWX Demo'; + msg = 'Thank you for trying AnsibleWorks AWX. You can use this edition to manage up to 5 hosts. ' + + 'Should you wish to acquire a license for additional servers, please visit ' + + 'ansibleworks.com/ansibleworks-awx, or ' + + 'contact info@ansibleworks.com for assistance.'; + Alert(hdr, msg, status); + } + if (license['date_warning'] !== undefined && license['date_warning'] == true) { + status = 'alert-info'; + hdr = 'License Expired'; + msg = 'Your AnsibleWorks AWX License has expired and is no longer compliant. ' + + 'You can continue, but you will be unable to add any additional hosts. Please ' + + 'visit ansibleworks.com/ansibleworks-awx ' + + 'for license and renewal information, or contact info@ansibleworks.com ' + + 'for assistance.'; + Alert(hdr, msg, status); + } + if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) { + status = 'alert-info'; + hdr = 'License Warning'; + msg = 'Your AnsibleWorks AWX License has reached capacity for the number of managed ' + + 'hosts allowed. You will not be able to add any additional hosts. To extend your license, please visit ' + + 'ansibleworks.com/ansibleworks-awx., or ' + + 'contact info@ansibleworks.com for more information.'; + Alert(hdr, msg, status, null, true); + } + } + } }]); \ No newline at end of file diff --git a/awx/ui/static/lib/ansible/authenticate.js b/awx/ui/static/lib/ansible/authenticate.js index 05304b7a4c..7b60635fb6 100644 --- a/awx/ui/static/lib/ansible/authenticate.js +++ b/awx/ui/static/lib/ansible/authenticate.js @@ -69,6 +69,36 @@ angular.module('AuthService', ['ngCookies']) $rootScope.userLoggedIn = false; }, + getLicense: function() { + return $http({ + method: 'GET', + url: '/api/v1/config/', + headers: { 'Authorization': 'Token ' + this.getToken() } + }); + }, + + setLicense: function(license) { + license['tested'] = false; + $cookieStore.put('license', license); + }, + + licenseTested: function() { + var result; + if ($rootScope.license_test !== undefined) { + result = $rootScope.license_test; + } + else { + var license = $cookieStore.get('license'); + if (license && license.tested !== undefined) { + result = license.tested; + } + else { + result = false; + } + } + return result; + }, + getUser: function() { return $http({ method: 'GET', diff --git a/awx/ui/static/lib/ansible/rest-services.js b/awx/ui/static/lib/ansible/rest-services.js index 2438c223f6..3fa0bb91cd 100644 --- a/awx/ui/static/lib/ansible/rest-services.js +++ b/awx/ui/static/lib/ansible/rest-services.js @@ -16,7 +16,7 @@ angular.module('RestServices',['ngCookies','AuthService']) pReplace: function() { //in our url, replace :xx params with a value, assuming - // we can find it in user supplied params. + //we can find it in user supplied params. var key,rgx; for (key in this.params) { rgx = new RegExp("\\:" + key,'gm'); diff --git a/awx/ui/static/lib/ansible/utilities.js b/awx/ui/static/lib/ansible/utilities.js index c9db467d85..0b6c952042 100644 --- a/awx/ui/static/lib/ansible/utilities.js +++ b/awx/ui/static/lib/ansible/utilities.js @@ -27,13 +27,36 @@ angular.module('Utilities',[]) } }) - .factory('Alert', ['$rootScope', function($rootScope) { - return function(hdr, msg) { + .factory('Alert', ['$rootScope', '$location', function($rootScope, $location) { + return function(hdr, msg, cls, action, secondAlert, disableButtons) { // Pass in the header and message you want displayed on TB modal dialog found in index.html. - // Assumes an id of 'alert-modal' - $rootScope.alertHeader = hdr; - $rootScope.alertBody = msg; - $('#alert-modal').modal({ show: true, keyboard: true, backdrop: 'static' }); + // Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-error, alert-success, + // alert-info...). Pass an optional function(){}, if you want a specific action to occur when user + // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. + if (secondAlert) { + $rootScope.alertHeader2 = hdr; + $rootScope.alertBody2 = msg; + $rootScope.alertClass2 = (cls) ? cls : 'alert-error'; //default alert class is alert-error + $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); + $rootScope.disableButtons2 = (disableButtons) ? true : false; + if (action) { + $('#alert-modal2').on('hidden', function() { + action(); + }); + } + } + else { + $rootScope.alertHeader = hdr; + $rootScope.alertBody = msg; + $rootScope.alertClass = (cls) ? cls : 'alert-error'; //default alert class is alert-error + $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); + $rootScope.disableButtons = (disableButtons) ? true : false; + if (action) { + $('#alert-modal').on('hidden', function() { + action(); + }); + } + } } }]) diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 4aac6ac39e..cc6da81654 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -14,6 +14,7 @@ + {% if settings.USE_MINIFIED_JS %} {# FIXME: Change to use minified JS once we are building it. #} {% else %} @@ -189,18 +190,31 @@ - + +