From 24de951f6ce2c24628ac8c4f1970a4e2e004b5f5 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 15 Jan 2019 14:05:48 -0500 Subject: [PATCH] add access token and authorization code expiration settings to ui --- .../configuration-auth.controller.js | 8 ++- .../auth-form/configuration-auth.partial.html | 4 ++ .../auth-form/sub-forms/auth-misc.form.js | 40 +++++++++++++++ .../forms/settings-form.controller.js | 49 +++++++++++++++++-- awx/ui/client/src/configuration/main.js | 2 + .../src/configuration/settings.service.js | 31 ++++++++++-- 6 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 awx/ui/client/src/configuration/forms/auth-form/sub-forms/auth-misc.form.js diff --git a/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.controller.js b/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.controller.js index d3ef949ca6..966ecdc8e1 100644 --- a/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.controller.js +++ b/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.controller.js @@ -94,7 +94,8 @@ export default [ {label: i18n._('LDAP'), value: 'ldap'}, {label: i18n._('RADIUS'), value: 'radius'}, {label: i18n._('SAML'), value: 'saml'}, - {label: i18n._('TACACS+'), value: 'tacacs'} + {label: i18n._('TACACS+'), value: 'tacacs'}, + {label: i18n._('MISC'), value: 'authMisc'} ]; authVm.ldapDropdownOptions = [ @@ -198,6 +199,11 @@ export default [ id: 'auth-ldap5-form', name: 'ldap5' }, + { + formDef: formDefs.authMisc, + id: 'auth-misc-form', + name: 'authMisc' + }, ]; var forms = _.map(authForms, 'formDef'); _.each(forms, function(form) { diff --git a/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.partial.html b/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.partial.html index 5154285c80..04f0f2b542 100644 --- a/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.partial.html +++ b/awx/ui/client/src/configuration/forms/auth-form/configuration-auth.partial.html @@ -97,6 +97,10 @@
+ +
+
+
diff --git a/awx/ui/client/src/configuration/forms/auth-form/sub-forms/auth-misc.form.js b/awx/ui/client/src/configuration/forms/auth-form/sub-forms/auth-misc.form.js new file mode 100644 index 0000000000..d55662c469 --- /dev/null +++ b/awx/ui/client/src/configuration/forms/auth-form/sub-forms/auth-misc.form.js @@ -0,0 +1,40 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['i18n', function(i18n) { + return { + name: 'configuration_authMisc_template', + showActions: true, + showHeader: false, + + fields: { + ACCESS_TOKEN_EXPIRE_SECONDS: { + type: 'text', + reset: 'ACCESS_TOKEN_EXPIRE_SECONDS' + }, + AUTHORIZATION_CODE_EXPIRE_SECONDS: { + type: 'text', + reset: 'AUTHORIZATION_CODE_EXPIRE_SECONDS' + } + }, + buttons: { + reset: { + ngShow: '!user_is_system_auditor', + ngClick: 'vm.resetAllConfirm()', + label: i18n._('Revert all to default'), + class: 'Form-resetAll' + }, + cancel: { + ngClick: 'vm.formCancel()', + }, + save: { + ngClick: 'vm.formSave()', + ngDisabled: "!enterprise_auth || configuration_authMisc_template_form.$invalid || configuration_authMisc_template_form.$pending" + } + } + }; +} +]; diff --git a/awx/ui/client/src/configuration/forms/settings-form.controller.js b/awx/ui/client/src/configuration/forms/settings-form.controller.js index 57216d9b85..828928f78b 100644 --- a/awx/ui/client/src/configuration/forms/settings-form.controller.js +++ b/awx/ui/client/src/configuration/forms/settings-form.controller.js @@ -19,6 +19,7 @@ export default [ 'configurationRadiusForm', 'configurationTacacsForm', 'configurationSamlForm', + 'configurationMiscForm', 'systemActivityStreamForm', 'systemLoggingForm', 'systemMiscForm', @@ -44,6 +45,7 @@ export default [ configurationRadiusForm, configurationTacacsForm, configurationSamlForm, + configurationMiscForm, systemActivityStreamForm, systemLoggingForm, systemMiscForm, @@ -71,6 +73,7 @@ export default [ 'radius': configurationRadiusForm, 'tacacs': configurationTacacsForm, 'saml': configurationSamlForm, + 'authMisc': configurationMiscForm, 'activity_stream': systemActivityStreamForm, 'logging': systemLoggingForm, 'misc': systemMiscForm, @@ -92,10 +95,15 @@ export default [ var populateFromApi = function() { SettingsService.getCurrentValues() .then(function(data) { + // these two values need to be unnested from the + // OAUTH2_PROVIDER key + data.ACCESS_TOKEN_EXPIRE_SECONDS = data + .OAUTH2_PROVIDER.ACCESS_TOKEN_EXPIRE_SECONDS; + data.AUTHORIZATION_CODE_EXPIRE_SECONDS = data + .OAUTH2_PROVIDER.AUTHORIZATION_CODE_EXPIRE_SECONDS; var currentKeys = _.keys(data); $scope.requiredLogValues = {}; _.each(currentKeys, function(key) { - if(key === "LOG_AGGREGATOR_HOST") { $scope.requiredLogValues.LOG_AGGREGATOR_HOST = data[key]; } @@ -232,7 +240,18 @@ export default [ $scope.resetValue = function(key) { Wait('start'); var payload = {}; - payload[key] = $scope.configDataResolve[key].default; + if (key === 'ACCESS_TOKEN_EXPIRE_SECONDS' || key === 'AUTHORIZATION_CODE_EXPIRE_SECONDS') { + // the reset for these two keys needs to be nested under OAUTH2_PROVIDER + if (payload.OAUTH2_PROVIDER === undefined) { + payload.OAUTH2_PROVIDER = { + ACCESS_TOKEN_EXPIRE_SECONDS: $scope.ACCESS_TOKEN_EXPIRE_SECONDS, + AUTHORIZATION_CODE_EXPIRE_SECONDS: $scope.AUTHORIZATION_CODE_EXPIRE_SECONDS + }; + } + payload.OAUTH2_PROVIDER[key] = $scope.configDataResolve[key].default; + } else { + payload[key] = $scope.configDataResolve[key].default; + } SettingsService.patchConfiguration(payload) .then(function() { $scope[key] = $scope.configDataResolve[key].default; @@ -310,7 +329,16 @@ export default [ var keys = _.keys(formDefs[formTracker.getCurrent()].fields); var payload = {}; _.each(keys, function(key) { - if($scope.configDataResolve[key].type === 'choice' || multiselectDropdowns.indexOf(key) !== -1) { + if (key === 'ACCESS_TOKEN_EXPIRE_SECONDS' || key === 'AUTHORIZATION_CODE_EXPIRE_SECONDS') { + // These two values need to be POSTed nested under the OAUTH2_PROVIDER key + if (payload.OAUTH2_PROVIDER === undefined) { + payload.OAUTH2_PROVIDER = { + ACCESS_TOKEN_EXPIRE_SECONDS: $scope.ACCESS_TOKEN_EXPIRE_SECONDS, + AUTHORIZATION_CODE_EXPIRE_SECONDS: $scope.AUTHORIZATION_CODE_EXPIRE_SECONDS + }; + } + payload.OAUTH2_PROVIDER[key] = $scope[key]; + } else if($scope.configDataResolve[key].type === 'choice' || multiselectDropdowns.indexOf(key) !== -1) { //Parse dropdowns and dropdowns labeled as lists if($scope[key] === null) { payload[key] = null; @@ -394,7 +422,7 @@ export default [ return saveDeferred.promise; }; - vm.formCancel = function() { + vm.formCancel = function() { if ($scope[formTracker.currentFormName()].$dirty === true) { var msg = i18n._('You have unsaved changes. Would you like to proceed without saving?'); var title = i18n._('Warning: Unsaved Changes'); @@ -518,7 +546,18 @@ export default [ var payload = {}; clearApiErrors(); _.each(keys, function(key) { - payload[key] = $scope.configDataResolve[key].default; + if (key === 'ACCESS_TOKEN_EXPIRE_SECONDS' || key === 'AUTHORIZATION_CODE_EXPIRE_SECONDS') { + // the reset for these two keys needs to be nested under OAUTH2_PROVIDER + if (payload.OAUTH2_PROVIDER === undefined) { + payload.OAUTH2_PROVIDER = { + ACCESS_TOKEN_EXPIRE_SECONDS: $scope.ACCESS_TOKEN_EXPIRE_SECONDS, + AUTHORIZATION_CODE_EXPIRE_SECONDS: $scope.AUTHORIZATION_CODE_EXPIRE_SECONDS + }; + } + payload.OAUTH2_PROVIDER[key] = $scope.configDataResolve[key].default; + } else { + payload[key] = $scope.configDataResolve[key].default; + } }); Wait('start'); diff --git a/awx/ui/client/src/configuration/main.js b/awx/ui/client/src/configuration/main.js index 809f3312fd..b034243652 100644 --- a/awx/ui/client/src/configuration/main.js +++ b/awx/ui/client/src/configuration/main.js @@ -23,6 +23,7 @@ import configurationLdap5Form from './forms/auth-form/sub-forms/auth-ldap5.form. import configurationRadiusForm from './forms/auth-form/sub-forms/auth-radius.form.js'; import configurationTacacsForm from './forms/auth-form/sub-forms/auth-tacacs.form.js'; import configurationSamlForm from './forms/auth-form/sub-forms/auth-saml.form'; +import configurationMiscForm from './forms/auth-form/sub-forms/auth-misc.form'; //system sub-forms import systemActivityStreamForm from './forms/system-form/sub-forms/system-activity-stream.form.js'; @@ -56,6 +57,7 @@ angular.module('configuration', []) .factory('configurationRadiusForm', configurationRadiusForm) .factory('configurationTacacsForm', configurationTacacsForm) .factory('configurationSamlForm', configurationSamlForm) + .factory('configurationMiscForm', configurationMiscForm) //system forms .factory('systemActivityStreamForm', systemActivityStreamForm) .factory('systemLoggingForm', systemLoggingForm) diff --git a/awx/ui/client/src/configuration/settings.service.js b/awx/ui/client/src/configuration/settings.service.js index 1d437dc2cd..a29f069869 100644 --- a/awx/ui/client/src/configuration/settings.service.js +++ b/awx/ui/client/src/configuration/settings.service.js @@ -4,8 +4,8 @@ * All Rights Reserved *************************************************/ -export default ['$rootScope', 'GetBasePath', 'ProcessErrors', '$q', '$http', 'Rest', - function($rootScope, GetBasePath, ProcessErrors, $q, $http, Rest) { +export default ['GetBasePath', '$q', 'Rest', 'i18n', + function(GetBasePath, $q, Rest, i18n) { var url = GetBasePath('settings') + 'all'; return { @@ -18,9 +18,32 @@ export default ['$rootScope', 'GetBasePath', 'ProcessErrors', '$q', '$http', 'Re .then(({data}) => { // Compare GET actions with PUT actions and flag discrepancies // for disabling in the UI - var getActions = data.actions.GET; + // + // since OAUTH2_PROVIDER returns two of the keys in a nested format, + // we need to split those out into the root of the options payload + // in order for them to be consumed + var appendOauth2ProviderKeys = (optsFromAPI) => { + var unnestOauth2ProviderKey = (key, label, parentKey) => { + optsFromAPI[key] = _.cloneDeep(optsFromAPI[parentKey]); + optsFromAPI[key].label = i18n._(label); + optsFromAPI[key].type = optsFromAPI[parentKey].child.type; + optsFromAPI[key].min_value = optsFromAPI[parentKey].child.min_value; + if (optsFromAPI[parentKey].default) { + optsFromAPI[key].default = optsFromAPI[parentKey].default[key]; + } + delete optsFromAPI[key].child; + }; + unnestOauth2ProviderKey('ACCESS_TOKEN_EXPIRE_SECONDS', + 'Access Token Expiration', + 'OAUTH2_PROVIDER'); + unnestOauth2ProviderKey('AUTHORIZATION_CODE_EXPIRE_SECONDS', + 'Authorization Code Expiration', + 'OAUTH2_PROVIDER'); + return optsFromAPI; + }; + var getActions = appendOauth2ProviderKeys(data.actions.GET); var getKeys = _.keys(getActions); - var putActions = data.actions.PUT; + var putActions = appendOauth2ProviderKeys(data.actions.PUT); _.each(getKeys, function(key) { if(putActions && putActions[key]) {