Merge pull request #4032 from ghjm/configurable_login_3.6.2

[3.6.2] Configurable login redirect
This commit is contained in:
Ryan Petrello
2019-12-12 15:43:58 -05:00
committed by GitHub
9 changed files with 82 additions and 44 deletions

View File

@@ -62,3 +62,14 @@ register(
category=_('Authentication'), category=_('Authentication'),
category_slug='authentication', category_slug='authentication',
) )
register(
'LOGIN_REDIRECT_OVERRIDE',
field_class=fields.CharField,
allow_blank=True,
required=False,
label=_('Login redirect override URL'),
help_text=_('URL to which unauthorized users will be redirected to log in. '
'If blank, users will be sent to the Tower login page.'),
category=_('Authentication'),
category_slug='authentication',
)

View File

@@ -60,6 +60,7 @@ class ApiRootView(APIView):
data['oauth2'] = drf_reverse('api:oauth_authorization_root_view') data['oauth2'] = drf_reverse('api:oauth_authorization_root_view')
data['custom_logo'] = settings.CUSTOM_LOGO data['custom_logo'] = settings.CUSTOM_LOGO
data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO
data['login_redirect_override'] = settings.LOGIN_REDIRECT_OVERRIDE
return Response(data) return Response(data)

View File

@@ -4,7 +4,7 @@
import json import json
# Django # Django
from django.http import HttpResponse from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render from django.shortcuts import render
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -97,3 +97,7 @@ def handle_csp_violation(request):
logger = logging.getLogger('awx') logger = logging.getLogger('awx')
logger.error(json.loads(request.body)) logger.error(json.loads(request.body))
return HttpResponse(content=None) return HttpResponse(content=None)
def handle_login_redirect(request):
return HttpResponseRedirect("/#/login")

View File

@@ -379,6 +379,10 @@ TACACSPLUS_AUTH_PROTOCOL = 'ascii'
# Note: This setting may be overridden by database settings. # Note: This setting may be overridden by database settings.
AUTH_BASIC_ENABLED = True AUTH_BASIC_ENABLED = True
# If set, specifies a URL that unauthenticated users will be redirected to
# when trying to access a UI page that requries authentication.
LOGIN_REDIRECT_OVERRIDE = None
# If set, serve only minified JS for UI. # If set, serve only minified JS for UI.
USE_MINIFIED_JS = False USE_MINIFIED_JS = False

View File

@@ -3,6 +3,8 @@ global.$AnsibleConfig = null;
// Provided via Webpack DefinePlugin in webpack.config.js // Provided via Webpack DefinePlugin in webpack.config.js
global.$ENV = {}; global.$ENV = {};
global.$ConfigResponse = {};
var urlPrefix; var urlPrefix;
if ($basePath) { if ($basePath) {
@@ -383,7 +385,11 @@ angular
var stime = timestammp[lastUser.id].time, var stime = timestammp[lastUser.id].time,
now = new Date().getTime(); now = new Date().getTime();
if ((stime - now) <= 0) { if ((stime - now) <= 0) {
$location.path('/login'); if (global.$AnsibleConfig.login_redirect_override) {
window.location.replace(global.$AnsibleConfig.login_redirect_override);
} else {
$location.path('/login');
}
} }
} }
// If browser refresh, set the user_is_superuser value // If browser refresh, set the user_is_superuser value

View File

@@ -15,7 +15,9 @@ function bootstrap (callback) {
angular.module('I18N').constant('LOCALE', locale); angular.module('I18N').constant('LOCALE', locale);
} }
angular.element(document).ready(() => callback()); fetchConfig(() => {
angular.element(document).ready(() => callback());
});
}); });
} }
@@ -49,6 +51,25 @@ function fetchLocaleStrings (callback) {
request.fail(() => callback({ code: DEFAULT_LOCALE })); request.fail(() => callback({ code: DEFAULT_LOCALE }));
} }
function fetchConfig (callback) {
const request = $.ajax('/api/');
request.done(res => {
global.$ConfigResponse = res;
if (res.login_redirect_override) {
if (!document.cookie.split(';').filter((item) => item.includes('userLoggedIn=true')).length && !window.location.href.includes('/#/login')) {
window.location.replace(res.login_redirect_override);
} else {
callback();
}
} else {
callback();
}
});
request.fail(() => callback());
}
/** /**
* Grabs the language off of navigator for browser compatibility. * Grabs the language off of navigator for browser compatibility.
* If the language isn't set, then it falls back to the DEFAULT_LOCALE. The * If the language isn't set, then it falls back to the DEFAULT_LOCALE. The

View File

@@ -43,6 +43,10 @@ export default ['i18n', function(i18n) {
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: { ALLOW_OAUTH2_FOR_EXTERNAL_USERS: {
type: 'toggleSwitch', type: 'toggleSwitch',
}, },
LOGIN_REDIRECT_OVERRIDE: {
type: 'text',
reset: 'LOGIN_REDIRECT_OVERRIDE'
},
ACCESS_TOKEN_EXPIRE_SECONDS: { ACCESS_TOKEN_EXPIRE_SECONDS: {
type: 'text', type: 'text',
reset: 'ACCESS_TOKEN_EXPIRE_SECONDS' reset: 'ACCESS_TOKEN_EXPIRE_SECONDS'

View File

@@ -1,55 +1,40 @@
export default export default
function LoadConfig($log, $rootScope, $http, Store) { function LoadConfig($rootScope, Store) {
return function() { return function() {
var configSettings = {}; var configSettings = {};
var configInit = function() { if(global.$ConfigResponse.custom_logo) {
// Auto-resolving what used to be found when attempting to load local_setting.json configSettings.custom_logo = true;
if ($rootScope.loginConfig) { $rootScope.custom_logo = global.$ConfigResponse.custom_logo;
$rootScope.loginConfig.resolve('config loaded'); } else {
} configSettings.custom_logo = false;
$rootScope.$emit('ConfigReady'); }
// Load new hardcoded settings from above if(global.$ConfigResponse.custom_login_info) {
configSettings.custom_login_info = global.$ConfigResponse.custom_login_info;
$rootScope.custom_login_info = global.$ConfigResponse.custom_login_info;
} else {
configSettings.custom_login_info = false;
}
global.$AnsibleConfig = configSettings; if (global.$ConfigResponse.login_redirect_override) {
Store('AnsibleConfig', global.$AnsibleConfig); configSettings.login_redirect_override = global.$ConfigResponse.login_redirect_override;
$rootScope.$emit('LoadConfig'); }
};
// Retrieve the custom logo information - update configSettings from above // Auto-resolving what used to be found when attempting to load local_setting.json
$http({ if ($rootScope.loginConfig) {
method: 'GET', $rootScope.loginConfig.resolve('config loaded');
url: '/api/', }
}) global.$AnsibleConfig = configSettings;
.then(function({data}) { Store('AnsibleConfig', global.$AnsibleConfig);
if(data.custom_logo) { $rootScope.$emit('ConfigReady');
configSettings.custom_logo = true;
$rootScope.custom_logo = data.custom_logo;
} else {
configSettings.custom_logo = false;
}
if(data.custom_login_info) { // Load new hardcoded settings from above
configSettings.custom_login_info = data.custom_login_info; $rootScope.$emit('LoadConfig');
$rootScope.custom_login_info = data.custom_login_info;
} else {
configSettings.custom_login_info = false;
}
configInit();
}).catch(({error}) => {
$log.debug(error);
configInit();
});
}; };
} }
LoadConfig.$inject = LoadConfig.$inject =
[ '$log', '$rootScope', '$http', [ '$rootScope', 'Store' ];
'Store'
];

View File

@@ -9,6 +9,7 @@ from awx.main.views import (
handle_404, handle_404,
handle_500, handle_500,
handle_csp_violation, handle_csp_violation,
handle_login_redirect,
) )
@@ -22,6 +23,7 @@ urlpatterns = [
url(r'^(?:api/)?404.html$', handle_404), url(r'^(?:api/)?404.html$', handle_404),
url(r'^(?:api/)?500.html$', handle_500), url(r'^(?:api/)?500.html$', handle_500),
url(r'^csp-violation/', handle_csp_violation), url(r'^csp-violation/', handle_csp_violation),
url(r'^login/', handle_login_redirect),
] ]
if settings.SETTINGS_MODULE == 'awx.settings.development': if settings.SETTINGS_MODULE == 'awx.settings.development':