Merge pull request #11448 from rabbitmq/dynamic-load-oauth-deps-ui
Dynamically load oauth-related libraries
This commit is contained in:
commit
c67c940bcc
|
@ -16,48 +16,17 @@
|
||||||
<script src="js/prefs.js" type="text/javascript"></script>
|
<script src="js/prefs.js" type="text/javascript"></script>
|
||||||
<script src="js/formatters.js" type="text/javascript"></script>
|
<script src="js/formatters.js" type="text/javascript"></script>
|
||||||
<script src="js/charts.js" type="text/javascript"></script>
|
<script src="js/charts.js" type="text/javascript"></script>
|
||||||
<script src="js/oidc-oauth/helper.js"></script>
|
<script src="js/oidc-oauth/bootstrap.js" type="module"></script>
|
||||||
<script src="js/oidc-oauth/oidc-client-ts.js" type="text/javascript"></script>
|
|
||||||
<script src="js/oidc-oauth/bootstrap.js"></script>
|
|
||||||
|
|
||||||
<link href="css/main.css" rel="stylesheet" type="text/css"/>
|
<link href="css/main.css" rel="stylesheet" type="text/css"/>
|
||||||
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon"/>
|
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon"/>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="module">
|
||||||
var oauth = oauth_initialize_if_required();
|
window.oauth = oauth_initialize_if_required();
|
||||||
|
|
||||||
if (oauth.enabled) {
|
|
||||||
if (!oauth.sp_initiated) {
|
|
||||||
oauth.logged_in = has_auth_credentials();
|
|
||||||
oauth.access_token = get_auth_credentials(); // DEPRECATED
|
|
||||||
} else {
|
|
||||||
oauth_is_logged_in().then( status => {
|
|
||||||
if (status.loggedIn && !has_auth_credentials()) {
|
|
||||||
oauth.logged_in = false;
|
|
||||||
oauth_initiateLogout();
|
|
||||||
} else {
|
|
||||||
if (!status.loggedIn) {
|
|
||||||
clear_auth();
|
|
||||||
} else {
|
|
||||||
oauth.logged_in = true;
|
|
||||||
oauth.access_token = status.user.access_token; // DEPRECATED
|
|
||||||
oauth.expiryDate = new Date(status.user.expires_at * 1000); // it is epoch in seconds
|
|
||||||
let current = new Date();
|
|
||||||
_management_logger.debug('token expires in ', (oauth.expiryDate-current)/1000,
|
|
||||||
'secs at : ', oauth.expiryDate );
|
|
||||||
oauth.user_name = status.user.profile['user_name'];
|
|
||||||
if (!oauth.user_name || oauth.user_name == '') {
|
|
||||||
oauth.user_name = status.user.profile['sub'];
|
|
||||||
}
|
|
||||||
oauth.scopes = status.user.scope;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!--[if lte IE 8]>
|
<!--[if lte IE 8]>
|
||||||
<script src="js/excanvas.min.js" type="text/javascript"></script>
|
<script src="js/excanvas.min.js" type="text/javascript"></script>
|
||||||
<link href="css/evil.css" rel="stylesheet" type="text/css"/>
|
<link href="css/evil.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
|
@ -698,6 +698,7 @@ function DisplayControl() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set up the above vars
|
// Set up the above vars
|
||||||
function setup_global_vars(overview) {
|
function setup_global_vars(overview) {
|
||||||
rates_mode = overview.rates_mode;
|
rates_mode = overview.rates_mode;
|
||||||
|
@ -715,7 +716,7 @@ function setup_global_vars(overview) {
|
||||||
|
|
||||||
user_name = fmt_escape_html(user.name);
|
user_name = fmt_escape_html(user.name);
|
||||||
$('#header #logout').prepend(
|
$('#header #logout').prepend(
|
||||||
'User ' + (user_administrator && !oauth.enabled ? '<a href="#/users/' + user_name + '">' + user_name + '</a>' : user_name)
|
'User ' + (user_administrator && user.is_internal_user ? '<a href="#/users/' + user_name + '">' + user_name + '</a>' : user_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
var product = overview.rabbitmq_version;
|
var product = overview.rabbitmq_version;
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var url_string = window.location.href;
|
var url_string = window.location.href;
|
||||||
var url = new URL(url_string);
|
var url = new URL(url_string);
|
||||||
var error = url.searchParams.get('error');
|
var error = url.searchParams.get('error');
|
||||||
if (error) {
|
if (error) {
|
||||||
renderWarningMessageInLoginStatus(fmt_escape_html(error));
|
if (oauth.enabled) {
|
||||||
} else {
|
renderWarningMessageInLoginStatus(oauth, fmt_escape_html(error));
|
||||||
if (oauth.enabled) {
|
|
||||||
startWithOAuthLogin();
|
|
||||||
} else {
|
|
||||||
startWithLoginPage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (oauth.enabled) {
|
||||||
|
startWithOAuthLogin(oauth);
|
||||||
|
} else {
|
||||||
|
startWithLoginPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function startWithLoginPage() {
|
function startWithLoginPage() {
|
||||||
|
@ -27,85 +29,18 @@ function removeDuplicates(array){
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
function warningMessageOAuthResource(oauthResource, reason) {
|
|
||||||
return "OAuth resource [<b>" + (oauthResource["label"] != null ? oauthResource.label : oauthResource.id) +
|
|
||||||
"</b>] not available. OpenId Discovery endpoint " + readiness_url(oauthResource) + reason
|
|
||||||
}
|
|
||||||
function warningMessageOAuthResources(commonProviderURL, oauthResources, reason) {
|
|
||||||
return "OAuth resources [ <b>" + oauthResources.map(resource => resource["label"] != null ? resource.label : resource.id).join("</b>,<b>")
|
|
||||||
+ "</b>] not available. OpenId Discovery endpoint " + commonProviderURL + reason
|
|
||||||
}
|
|
||||||
|
|
||||||
function startWithOAuthLogin () {
|
|
||||||
|
function startWithOAuthLogin (oauth) {
|
||||||
store_pref("oauth-return-to", window.location.hash);
|
store_pref("oauth-return-to", window.location.hash);
|
||||||
|
|
||||||
if (!oauth.logged_in) {
|
if (!oauth.logged_in) {
|
||||||
|
hasAnyResourceServerReady(oauth, (oauth, warnings) => { render_login_oauth(oauth, warnings); start_app_login(); })
|
||||||
// Find out how many distinct oauthServers are configured
|
|
||||||
let oauthServers = removeDuplicates(oauth.resource_servers.filter((resource) => resource.sp_initiated))
|
|
||||||
oauthServers.forEach(function(entry) { console.log(readiness_url(entry)) })
|
|
||||||
if (oauthServers.length > 0) { // some resources are sp_initiated but there could be idp_initiated too
|
|
||||||
Promise.allSettled(oauthServers.map(oauthServer => fetch(readiness_url(oauthServer)).then(res => res.json())))
|
|
||||||
.then(results => {
|
|
||||||
results.forEach(function(entry) { console.log(entry) })
|
|
||||||
let notReadyServers = []
|
|
||||||
let notCompliantServers = []
|
|
||||||
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
|
||||||
switch (results[i].status) {
|
|
||||||
case "fulfilled":
|
|
||||||
try {
|
|
||||||
validate_openid_configuration(results[i].value)
|
|
||||||
}catch(e) {
|
|
||||||
console.log("Unable to connect to " + oauthServers[i].oauth_provider_url + ". " + e)
|
|
||||||
notCompliantServers.push(oauthServers[i].oauth_provider_url)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case "rejected":
|
|
||||||
notReadyServers.push(oauthServers[i].oauth_provider_url)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const spOauthServers = oauth.resource_servers.filter((resource) => resource.sp_initiated)
|
|
||||||
const groupByProviderURL = spOauthServers.reduce((group, oauthServer) => {
|
|
||||||
const { oauth_provider_url } = oauthServer;
|
|
||||||
group[oauth_provider_url] = group[oauth_provider_url] ?? [];
|
|
||||||
group[oauth_provider_url].push(oauthServer);
|
|
||||||
return group;
|
|
||||||
}, {})
|
|
||||||
let warnings = []
|
|
||||||
for(var url in groupByProviderURL){
|
|
||||||
console.log(url + ': ' + groupByProviderURL[url]);
|
|
||||||
const notReadyResources = groupByProviderURL[url].filter((oauthserver) => notReadyServers.includes(oauthserver.oauth_provider_url))
|
|
||||||
const notCompliantResources = groupByProviderURL[url].filter((oauthserver) => notCompliantServers.includes(oauthserver.oauth_provider_url))
|
|
||||||
if (notReadyResources.length == 1) {
|
|
||||||
warnings.push(warningMessageOAuthResource(notReadyResources[0], " not reachable"))
|
|
||||||
}else if (notReadyResources.length > 1) {
|
|
||||||
warnings.push(warningMessageOAuthResources(url, notReadyResources, " not reachable"))
|
|
||||||
}
|
|
||||||
if (notCompliantResources.length == 1) {
|
|
||||||
warnings.push(warningMessageOAuthResource(notCompliantResources[0], " not compliant"))
|
|
||||||
}else if (notCompliantResources.length > 1) {
|
|
||||||
warnings.push(warningMessageOAuthResources(url, notCompliantResources, " not compliant"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("warnings:" + warnings)
|
|
||||||
oauth.declared_resource_servers_count = oauth.resource_servers.length
|
|
||||||
oauth.resource_servers = oauth.resource_servers.filter((resource) =>
|
|
||||||
!notReadyServers.includes(resource.oauth_provider_url) && !notCompliantServers.includes(resource.oauth_provider_url))
|
|
||||||
render_login_oauth(warnings)
|
|
||||||
start_app_login()
|
|
||||||
|
|
||||||
})
|
|
||||||
}else { // there are only idp_initiated resources
|
|
||||||
render_login_oauth()
|
|
||||||
start_app_login()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
start_app_login()
|
start_app_login()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function render_login_oauth(messages) {
|
function render_login_oauth(oauth, messages) {
|
||||||
let formatData = {}
|
let formatData = {}
|
||||||
formatData.warnings = []
|
formatData.warnings = []
|
||||||
formatData.notAuthorized = false
|
formatData.notAuthorized = false
|
||||||
|
@ -118,7 +53,6 @@ function render_login_oauth(messages) {
|
||||||
} else if (typeof messages == "string") {
|
} else if (typeof messages == "string") {
|
||||||
formatData.warnings = [messages]
|
formatData.warnings = [messages]
|
||||||
formatData.notAuthorized = messages == "Not authorized"
|
formatData.notAuthorized = messages == "Not authorized"
|
||||||
console.log("Single error message")
|
|
||||||
}
|
}
|
||||||
replace_content('outer', format('login_oauth', formatData))
|
replace_content('outer', format('login_oauth', formatData))
|
||||||
|
|
||||||
|
@ -127,13 +61,11 @@ function render_login_oauth(messages) {
|
||||||
$('#login').on('click', 'div.section h2, div.section-hidden h2', function() {
|
$('#login').on('click', 'div.section h2, div.section-hidden h2', function() {
|
||||||
toggle_visibility($(this));
|
toggle_visibility($(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
function renderWarningMessageInLoginStatus(message) {
|
function renderWarningMessageInLoginStatus(oauth, message) {
|
||||||
render_login_oauth(message)
|
render_login_oauth(oauth, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function dispatcher_add(fun) {
|
function dispatcher_add(fun) {
|
||||||
dispatcher_modules.push(fun);
|
dispatcher_modules.push(fun);
|
||||||
if (dispatcher_modules.length == extension_count) {
|
if (dispatcher_modules.length == extension_count) {
|
||||||
|
@ -187,9 +119,10 @@ function check_login () {
|
||||||
if (user == false || user.error) {
|
if (user == false || user.error) {
|
||||||
clear_auth();
|
clear_auth();
|
||||||
if (oauth.enabled) {
|
if (oauth.enabled) {
|
||||||
hide_popup_warn();
|
//hide_popup_warn();
|
||||||
renderWarningMessageInLoginStatus('Not authorized');
|
renderWarningMessageInLoginStatus(oauth, 'Not authorized');
|
||||||
} else {
|
} else {
|
||||||
|
//hide_popup_warn();
|
||||||
replace_content('login-status', '<p>Login failed</p>');
|
replace_content('login-status', '<p>Login failed</p>');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -323,6 +256,7 @@ function dynamic_load(filename) {
|
||||||
element.setAttribute('type', 'text/javascript');
|
element.setAttribute('type', 'text/javascript');
|
||||||
element.setAttribute('src', 'js/' + filename);
|
element.setAttribute('src', 'js/' + filename);
|
||||||
document.getElementsByTagName('head')[0].appendChild(element);
|
document.getElementsByTagName('head')[0].appendChild(element);
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_interval() {
|
function update_interval() {
|
||||||
|
@ -350,6 +284,10 @@ function update_interval() {
|
||||||
function go_to(url) {
|
function go_to(url) {
|
||||||
this.location = url;
|
this.location = url;
|
||||||
}
|
}
|
||||||
|
function go_to_home() {
|
||||||
|
// location.href = rabbit_path_prefix() + "/"
|
||||||
|
location.href = "/"
|
||||||
|
}
|
||||||
|
|
||||||
function set_timer_interval(interval) {
|
function set_timer_interval(interval) {
|
||||||
timer_interval = interval;
|
timer_interval = interval;
|
||||||
|
@ -1472,16 +1410,16 @@ function sync_req(type, params0, path_template, options) {
|
||||||
else
|
else
|
||||||
// rabbitmq/rabbitmq-management#732
|
// rabbitmq/rabbitmq-management#732
|
||||||
// https://developer.mozilla.org/en-US/docs/Glossary/Truthy
|
// https://developer.mozilla.org/en-US/docs/Glossary/Truthy
|
||||||
return {result: true, http_status: req.status, req_params: params};
|
return {result: true, http_status: req.status, req_params: params, responseText: req.responseText};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function initiate_logout(error = "") {
|
function initiate_logout(oauth, error = "") {
|
||||||
clear_pref('auth');
|
clear_pref('auth');
|
||||||
clear_cookie_value('auth');
|
clear_cookie_value('auth');
|
||||||
renderWarningMessageInLoginStatus(error);
|
renderWarningMessageInLoginStatus(oauth, error);
|
||||||
}
|
}
|
||||||
function check_bad_response(req, full_page_404) {
|
function check_bad_response(req, full_page_404) {
|
||||||
// 1223 == 204 - see https://www.enhanceie.com/ie/bugs.asp
|
// 1223 == 204 - see https://www.enhanceie.com/ie/bugs.asp
|
||||||
|
@ -1502,7 +1440,7 @@ function check_bad_response(req, full_page_404) {
|
||||||
|
|
||||||
if (error == 'bad_request' || error == 'not_found' || error == 'not_authorised' || error == 'not_authorized') {
|
if (error == 'bad_request' || error == 'not_found' || error == 'not_authorised' || error == 'not_authorized') {
|
||||||
if ((req.status == 401 || req.status == 403) && oauth.enabled) {
|
if ((req.status == 401 || req.status == 403) && oauth.enabled) {
|
||||||
initiate_logout(reason);
|
initiate_logout(oauth, reason);
|
||||||
} else {
|
} else {
|
||||||
show_popup('warn', fmt_escape_html(reason));
|
show_popup('warn', fmt_escape_html(reason));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import {oidc} from './oidc-client-ts.js';
|
||||||
|
|
||||||
var mgr;
|
var mgr;
|
||||||
var _management_logger;
|
var _management_logger;
|
||||||
|
@ -85,9 +86,61 @@ function auth_settings_apply_defaults(authSettings) {
|
||||||
return authSettings;
|
return authSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oauth_settings = { oauth_enabled : false}
|
||||||
|
|
||||||
|
export function set_oauth_settings(settings) {
|
||||||
|
oauth_settings = settings
|
||||||
|
}
|
||||||
|
function get_oauth_settings() {
|
||||||
|
return oauth_settings
|
||||||
|
}
|
||||||
|
|
||||||
|
export function oauth_initialize_if_required(state = "index") {
|
||||||
|
let oauth = oauth_initialize(get_oauth_settings())
|
||||||
|
if (!oauth.enabled) return oauth;
|
||||||
|
switch (state) {
|
||||||
|
case 'login-callback':
|
||||||
|
oauth_completeLogin(); break;
|
||||||
|
case 'logout-callback':
|
||||||
|
oauth_completeLogout(); break;
|
||||||
|
default:
|
||||||
|
oauth = oauth_initiate(oauth);
|
||||||
|
}
|
||||||
|
return oauth;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function oauth_initiate(oauth) {
|
||||||
|
if (oauth.enabled) {
|
||||||
|
if (!oauth.sp_initiated) {
|
||||||
|
oauth.logged_in = has_auth_credentials();
|
||||||
|
} else {
|
||||||
|
oauth_is_logged_in().then( status => {
|
||||||
|
if (status.loggedIn && !has_auth_credentials()) {
|
||||||
|
oauth.logged_in = false;
|
||||||
|
oauth_initiateLogout();
|
||||||
|
} else {
|
||||||
|
if (!status.loggedIn) {
|
||||||
|
clear_auth();
|
||||||
|
} else {
|
||||||
|
oauth.logged_in = true;
|
||||||
|
oauth.expiryDate = new Date(status.user.expires_at * 1000); // it is epoch in seconds
|
||||||
|
let current = new Date();
|
||||||
|
_management_logger.debug('token expires in ', (oauth.expiryDate-current)/1000,
|
||||||
|
'secs at : ', oauth.expiryDate );
|
||||||
|
oauth.user_name = status.user.profile['user_name'];
|
||||||
|
if (!oauth.user_name || oauth.user_name == '') {
|
||||||
|
oauth.user_name = status.user.profile['sub'];
|
||||||
|
}
|
||||||
|
oauth.scopes = status.user.scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oauth;
|
||||||
|
}
|
||||||
function oauth_initialize_user_manager(resource_server) {
|
function oauth_initialize_user_manager(resource_server) {
|
||||||
oidcSettings = {
|
let oidcSettings = {
|
||||||
userStore: new oidc.WebStorageStateStore({ store: window.localStorage }),
|
userStore: new oidc.WebStorageStateStore({ store: window.localStorage }),
|
||||||
authority: resource_server.oauth_provider_url,
|
authority: resource_server.oauth_provider_url,
|
||||||
client_id: resource_server.oauth_client_id,
|
client_id: resource_server.oauth_client_id,
|
||||||
|
@ -119,7 +172,7 @@ function oauth_initialize_user_manager(resource_server) {
|
||||||
oidc.Log.setLogger(console);
|
oidc.Log.setLogger(console);
|
||||||
|
|
||||||
mgr = new oidc.UserManager(oidcSettings);
|
mgr = new oidc.UserManager(oidcSettings);
|
||||||
oauth.readiness_url = mgr.settings.metadataUrl;
|
// oauth.readiness_url = mgr.settings.metadataUrl;
|
||||||
|
|
||||||
_management_logger = new oidc.Logger("Management");
|
_management_logger = new oidc.Logger("Management");
|
||||||
|
|
||||||
|
@ -133,15 +186,13 @@ function oauth_initialize_user_manager(resource_server) {
|
||||||
_management_logger.error("token expiring failed due to ", err);
|
_management_logger.error("token expiring failed due to ", err);
|
||||||
});
|
});
|
||||||
mgr.events.addUserLoaded(function(user) {
|
mgr.events.addUserLoaded(function(user) {
|
||||||
console.log("addUserLoaded setting oauth.access_token ")
|
set_token_auth(user.access_token)
|
||||||
oauth.access_token = user.access_token // DEPRECATED
|
|
||||||
set_token_auth(oauth.access_token)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
function oauth_initialize(authSettings) {
|
export function oauth_initialize(authSettings) {
|
||||||
authSettings = auth_settings_apply_defaults(authSettings);
|
authSettings = auth_settings_apply_defaults(authSettings);
|
||||||
oauth = {
|
let oauth = {
|
||||||
"logged_in": false,
|
"logged_in": false,
|
||||||
"enabled" : authSettings.oauth_enabled,
|
"enabled" : authSettings.oauth_enabled,
|
||||||
"resource_servers" : authSettings.resource_servers,
|
"resource_servers" : authSettings.resource_servers,
|
||||||
|
@ -149,12 +200,12 @@ function oauth_initialize(authSettings) {
|
||||||
}
|
}
|
||||||
if (!oauth.enabled) return oauth;
|
if (!oauth.enabled) return oauth;
|
||||||
|
|
||||||
resource_server = null
|
let resource_server = null;
|
||||||
|
|
||||||
if (oauth.resource_servers.length == 1) {
|
if (oauth.resource_servers.length == 1) {
|
||||||
resource_server = oauth.resource_servers[0]
|
resource_server = oauth.resource_servers[0]
|
||||||
} else if (has_auth_resource()) {
|
} else if (has_auth_resource()) {
|
||||||
resource_server = lookup_resource_server(get_auth_resource())
|
resource_server = lookup_resource_server(get_auth_resource(), oauth.resource_servers)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource_server) {
|
if (resource_server) {
|
||||||
|
@ -189,18 +240,18 @@ function oauth_is_logged_in() {
|
||||||
return { "user": user, "loggedIn": !user.expired };
|
return { "user": user, "loggedIn": !user.expired };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function lookup_resource_server(resource_server_id) {
|
function lookup_resource_server(resource_server_id, resource_servers) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
while (i < oauth.resource_servers.length && oauth.resource_servers[i].id != resource_server_id) {
|
while (i < resource_servers.length && resource_servers[i].id != resource_server_id) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i < oauth.resource_servers.length) return oauth.resource_servers[i]
|
if (i < resource_servers.length) return resource_servers[i]
|
||||||
else return null
|
else return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function oauth_initiateLogin(resource_server_id) {
|
export function oauth_initiateLogin(resource_server_id) {
|
||||||
resource_server = lookup_resource_server(resource_server_id)
|
let resource_server = lookup_resource_server(resource_server_id, oauth.resource_servers)
|
||||||
if (!resource_server) return;
|
if (!resource_server) return;
|
||||||
set_auth_resource(resource_server_id)
|
set_auth_resource(resource_server_id)
|
||||||
|
|
||||||
|
@ -220,19 +271,15 @@ function oauth_initiateLogin(resource_server_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function oauth_redirectToHome(oauth) {
|
function oauth_redirectToHome() {
|
||||||
set_token_auth(oauth.access_token)
|
let path = get_pref("oauth-return-to")
|
||||||
|
|
||||||
path = get_pref("oauth-return-to");
|
|
||||||
clear_pref("oauth-return-to")
|
clear_pref("oauth-return-to")
|
||||||
go_to(path)
|
go_to( !path ? "" : path)
|
||||||
}
|
}
|
||||||
function go_to(path) {
|
function go_to(path) {
|
||||||
location.href = rabbit_path_prefix() + "/" + path
|
location.href = rabbit_path_prefix() + "/" + path
|
||||||
}
|
}
|
||||||
function go_to_home() {
|
|
||||||
location.href = rabbit_path_prefix() + "/"
|
|
||||||
}
|
|
||||||
function go_to_authority() {
|
function go_to_authority() {
|
||||||
location.href = oauth.authority
|
location.href = oauth.authority
|
||||||
}
|
}
|
||||||
|
@ -242,14 +289,17 @@ function oauth_redirectToLogin(error) {
|
||||||
location.href = rabbit_path_prefix() + "/?error=" + error
|
location.href = rabbit_path_prefix() + "/?error=" + error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function oauth_completeLogin() {
|
export function oauth_completeLogin() {
|
||||||
mgr.signinRedirectCallback().then(user => oauth_redirectToHome(user)).catch(function(err) {
|
mgr.signinRedirectCallback().then(function(user) {
|
||||||
_management_logger.error(err)
|
set_token_auth(user.access_token);
|
||||||
oauth_redirectToLogin(err)
|
oauth_redirectToHome();
|
||||||
|
}).catch(function(err) {
|
||||||
|
_management_logger.error(err)
|
||||||
|
oauth_redirectToLogin(err)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function oauth_initiateLogout() {
|
export function oauth_initiateLogout() {
|
||||||
if (oauth.sp_initiated) {
|
if (oauth.sp_initiated) {
|
||||||
mgr.metadataService.getEndSessionEndpoint().then(endpoint => {
|
mgr.metadataService.getEndSessionEndpoint().then(endpoint => {
|
||||||
if (endpoint == undefined) {
|
if (endpoint == undefined) {
|
||||||
|
@ -268,7 +318,7 @@ function oauth_initiateLogout() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function oauth_completeLogout() {
|
export function oauth_completeLogout() {
|
||||||
clear_auth()
|
clear_auth()
|
||||||
mgr.signoutRedirectCallback().then(_ => oauth_redirectToLogin())
|
mgr.signoutRedirectCallback().then(_ => oauth_redirectToLogin())
|
||||||
}
|
}
|
||||||
|
@ -287,3 +337,74 @@ function validate_openid_configuration(payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function warningMessageOAuthResource(oauthResource, reason) {
|
||||||
|
return "OAuth resource [<b>" + (oauthResource["label"] != null ? oauthResource.label : oauthResource.id) +
|
||||||
|
"</b>] not available. OpenId Discovery endpoint " + readiness_url(oauthResource) + reason
|
||||||
|
}
|
||||||
|
function warningMessageOAuthResources(commonProviderURL, oauthResources, reason) {
|
||||||
|
return "OAuth resources [ <b>" + oauthResources.map(resource => resource["label"] != null ? resource.label : resource.id).join("</b>,<b>")
|
||||||
|
+ "</b>] not available. OpenId Discovery endpoint " + commonProviderURL + reason
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasAnyResourceServerReady(oauth, onReadyCallback) {
|
||||||
|
// Find out how many distinct oauthServers are configured
|
||||||
|
let oauthServers = removeDuplicates(oauth.resource_servers.filter((resource) => resource.sp_initiated))
|
||||||
|
oauthServers.forEach(function(entry) { console.log(readiness_url(entry)) })
|
||||||
|
if (oauthServers.length > 0) { // some resources are sp_initiated but there could be idp_initiated too
|
||||||
|
Promise.allSettled(oauthServers.map(oauthServer => fetch(readiness_url(oauthServer)).then(res => res.json())))
|
||||||
|
.then(results => {
|
||||||
|
results.forEach(function(entry) { console.log(entry) })
|
||||||
|
let notReadyServers = []
|
||||||
|
let notCompliantServers = []
|
||||||
|
|
||||||
|
for (let i = 0; i < results.length; i++) {
|
||||||
|
switch (results[i].status) {
|
||||||
|
case "fulfilled":
|
||||||
|
try {
|
||||||
|
validate_openid_configuration(results[i].value)
|
||||||
|
}catch(e) {
|
||||||
|
console.log("Unable to connect to " + oauthServers[i].oauth_provider_url + ". " + e)
|
||||||
|
notCompliantServers.push(oauthServers[i].oauth_provider_url)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "rejected":
|
||||||
|
notReadyServers.push(oauthServers[i].oauth_provider_url)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const spOauthServers = oauth.resource_servers.filter((resource) => resource.sp_initiated)
|
||||||
|
const groupByProviderURL = spOauthServers.reduce((group, oauthServer) => {
|
||||||
|
const { oauth_provider_url } = oauthServer;
|
||||||
|
group[oauth_provider_url] = group[oauth_provider_url] ?? [];
|
||||||
|
group[oauth_provider_url].push(oauthServer);
|
||||||
|
return group;
|
||||||
|
}, {})
|
||||||
|
let warnings = []
|
||||||
|
for(var url in groupByProviderURL){
|
||||||
|
console.log(url + ': ' + groupByProviderURL[url]);
|
||||||
|
const notReadyResources = groupByProviderURL[url].filter((oauthserver) => notReadyServers.includes(oauthserver.oauth_provider_url))
|
||||||
|
const notCompliantResources = groupByProviderURL[url].filter((oauthserver) => notCompliantServers.includes(oauthserver.oauth_provider_url))
|
||||||
|
if (notReadyResources.length == 1) {
|
||||||
|
warnings.push(warningMessageOAuthResource(notReadyResources[0], " not reachable"))
|
||||||
|
}else if (notReadyResources.length > 1) {
|
||||||
|
warnings.push(warningMessageOAuthResources(url, notReadyResources, " not reachable"))
|
||||||
|
}
|
||||||
|
if (notCompliantResources.length == 1) {
|
||||||
|
warnings.push(warningMessageOAuthResource(notCompliantResources[0], " not compliant"))
|
||||||
|
}else if (notCompliantResources.length > 1) {
|
||||||
|
warnings.push(warningMessageOAuthResources(url, notCompliantResources, " not compliant"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("warnings:" + warnings)
|
||||||
|
oauth.declared_resource_servers_count = oauth.resource_servers.length
|
||||||
|
oauth.resource_servers = oauth.resource_servers.filter((resource) =>
|
||||||
|
!notReadyServers.includes(resource.oauth_provider_url) && !notCompliantServers.includes(resource.oauth_provider_url))
|
||||||
|
|
||||||
|
onReadyCallback(oauth, warnings)
|
||||||
|
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
onReadyCallback(oauth, [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,12 +7,11 @@
|
||||||
<script src="../jquery-3.5.1.min.js"></script>
|
<script src="../jquery-3.5.1.min.js"></script>
|
||||||
<script src="../base64.js" type="text/javascript"></script>
|
<script src="../base64.js" type="text/javascript"></script>
|
||||||
<script src="../prefs.js" ></script>
|
<script src="../prefs.js" ></script>
|
||||||
<script src="./oidc-client-ts.js" ></script>
|
<script src="./bootstrap.js" type="module" ></script>
|
||||||
<script src="./helper.js"></script>
|
<script type="module">
|
||||||
<script src="./bootstrap.js"></script>
|
window.oauth = oauth_initialize_if_required("login-callback");
|
||||||
<script type="text/javascript">
|
|
||||||
|
</script>
|
||||||
|
|
||||||
if (oauth_initialize_if_required()) oauth_completeLogin()
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="./oidc-client-ts.js" ></script>
|
<script src="./bootstrap.js" type="module" ></script>
|
||||||
<script src="./helper.js"></script>
|
<script type="module">
|
||||||
<script src="./bootstrap.js"></script>
|
window.oauth = oauth_initialize_if_required("logout-callback");
|
||||||
<script type="text/javascript">
|
|
||||||
if (oauth_initialize_if_required()) {
|
</script>
|
||||||
oauth_completeLogout()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3180,3 +3180,4 @@ var oidc = (() => {
|
||||||
return __toCommonJS(src_exports);
|
return __toCommonJS(src_exports);
|
||||||
})();
|
})();
|
||||||
//# sourceMappingURL=oidc-client-ts.js.map
|
//# sourceMappingURL=oidc-client-ts.js.map
|
||||||
|
export {oidc};
|
|
@ -47,7 +47,7 @@ start_devkeycloak() {
|
||||||
|
|
||||||
wait_for_oidc_endpoint devkeycloak $DEVKEYCLOAK_URL $MOUNT_DEVKEYCLOAK_CONF_DIR/ca_certificate.pem
|
wait_for_oidc_endpoint devkeycloak $DEVKEYCLOAK_URL $MOUNT_DEVKEYCLOAK_CONF_DIR/ca_certificate.pem
|
||||||
end "devkeycloak is ready"
|
end "devkeycloak is ready"
|
||||||
print " Note: If you modify devkeycloak configuration. Make sure to run the following command to export the configuration."
|
print " Note: If you modify devkeycloak configuration, make sure to run the following command to export the configuration."
|
||||||
print " docker exec -it devkeycloak /opt/keycloak/bin/kc.sh export --users realm_file --realm test --dir /opt/keycloak/data/import/"
|
print " docker exec -it devkeycloak /opt/keycloak/bin/kc.sh export --users realm_file --realm test --dir /opt/keycloak/data/import/"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ start_prodkeycloak() {
|
||||||
|
|
||||||
wait_for_oidc_endpoint prodkeycloak $PRODKEYCLOAK_URL $MOUNT_PRODKEYCLOAK_CONF_DIR/ca_certificate.pem
|
wait_for_oidc_endpoint prodkeycloak $PRODKEYCLOAK_URL $MOUNT_PRODKEYCLOAK_CONF_DIR/ca_certificate.pem
|
||||||
end "prodkeycloak is ready"
|
end "prodkeycloak is ready"
|
||||||
print " Note: If you modify prodkeycloak configuration. Make sure to run the following command to export the configuration."
|
print " Note: If you modify prodkeycloak configuration, make sure to run the following command to export the configuration."
|
||||||
print " docker exec -it prodkeycloak /opt/keycloak/bin/kc.sh export --users realm_file --realm test --dir /opt/keycloak/data/import/"
|
print " docker exec -it prodkeycloak /opt/keycloak/bin/kc.sh export --users realm_file --realm test --dir /opt/keycloak/data/import/"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
authnz-mgt/basic-auth-behind-proxy.sh
|
authnz-mgt/basic-auth-behind-proxy.sh
|
||||||
authnz-mgt/basic-auth.sh
|
authnz-mgt/basic-auth.sh
|
||||||
|
authnz-mgt/basic-auth-with-mgt-prefix.sh
|
||||||
authnz-mgt/multi-oauth-with-basic-auth-when-idps-down.sh
|
authnz-mgt/multi-oauth-with-basic-auth-when-idps-down.sh
|
||||||
authnz-mgt/multi-oauth-with-basic-auth.sh
|
authnz-mgt/multi-oauth-with-basic-auth.sh
|
||||||
authnz-mgt/multi-oauth-without-basic-auth-and-resource-label-and-scopes.sh
|
authnz-mgt/multi-oauth-without-basic-auth-and-resource-label-and-scopes.sh
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chromedriver": "^123.0.0",
|
"chromedriver": "^125.0.0",
|
||||||
"ejs": "^3.1.8",
|
"ejs": "^3.1.8",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"geckodriver": "^3.0.2",
|
"geckodriver": "^3.0.2",
|
||||||
|
|
9
deps/rabbitmq_management/selenium/suites/authnz-mgt/basic-auth-with-mgt-prefix.sh
vendored
Executable file
9
deps/rabbitmq_management/selenium/suites/authnz-mgt/basic-auth-with-mgt-prefix.sh
vendored
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
TEST_CASES_PATH=/basic-auth
|
||||||
|
PROFILES="mgt-prefix"
|
||||||
|
|
||||||
|
source $SCRIPT/../../bin/suite_template $@
|
||||||
|
run
|
|
@ -44,6 +44,13 @@
|
||||||
"monitoring"
|
"monitoring"
|
||||||
],
|
],
|
||||||
"limits": {}
|
"limits": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rabbit_no_management",
|
||||||
|
"password_hash": "Joz9zzUBOrX10lB3GisWN5oTXK+wj0gxS/nyrfTYmBOuhps5",
|
||||||
|
"hashing_algorithm": "rabbit_password_hashing_sha256",
|
||||||
|
"tags": [ ],
|
||||||
|
"limits": {}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"vhosts": [
|
"vhosts": [
|
||||||
|
@ -65,6 +72,13 @@
|
||||||
"configure": ".*",
|
"configure": ".*",
|
||||||
"write": ".*",
|
"write": ".*",
|
||||||
"read": ".*"
|
"read": ".*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user": "rabbit_no_management",
|
||||||
|
"vhost": "/",
|
||||||
|
"configure": ".*",
|
||||||
|
"write": ".*",
|
||||||
|
"read": ".*"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
auth_backends.1 = rabbit_auth_backend_internal
|
auth_backends.1 = rabbit_auth_backend_internal
|
||||||
|
|
||||||
management.login_session_timeout = 150
|
management.login_session_timeout = 1
|
||||||
load_definitions = ${IMPORT_DIR}/users.json
|
load_definitions = ${IMPORT_DIR}/users.json
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
management.path_prefix = /my-prefix/another-prefix
|
|
@ -0,0 +1,39 @@
|
||||||
|
const { By, Key, until, Builder } = require('selenium-webdriver')
|
||||||
|
require('chromedriver')
|
||||||
|
const assert = require('assert')
|
||||||
|
const { buildDriver, goToHome, captureScreensFor, teardown, delay } = require('../utils')
|
||||||
|
|
||||||
|
const LoginPage = require('../pageobjects/LoginPage')
|
||||||
|
const OverviewPage = require('../pageobjects/OverviewPage')
|
||||||
|
|
||||||
|
describe('Once user is logged in', function () {
|
||||||
|
let homePage
|
||||||
|
let idpLogin
|
||||||
|
let overview
|
||||||
|
let captureScreen
|
||||||
|
this.timeout(65000) // hard-coded to 25secs because this test requires 35sec to run
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
driver = buildDriver()
|
||||||
|
await goToHome(driver)
|
||||||
|
login = new LoginPage(driver)
|
||||||
|
overview = new OverviewPage(driver)
|
||||||
|
captureScreen = captureScreensFor(driver, __filename)
|
||||||
|
await login.login('guest', 'guest')
|
||||||
|
await overview.isLoaded()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it has to login after the session expires', async function () {
|
||||||
|
|
||||||
|
await delay(60000)
|
||||||
|
await login.isLoaded()
|
||||||
|
await login.login('guest', 'guest')
|
||||||
|
await overview.isLoaded()
|
||||||
|
await overview.clickOnConnectionsTab() // and we can still interact with the ui
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await teardown(driver, this, captureScreen)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,59 @@
|
||||||
|
const { By, Key, until, Builder } = require('selenium-webdriver')
|
||||||
|
require('chromedriver')
|
||||||
|
const assert = require('assert')
|
||||||
|
const { buildDriver, goToHome, captureScreensFor, teardown, delay } = require('../utils')
|
||||||
|
|
||||||
|
const LoginPage = require('../pageobjects/LoginPage')
|
||||||
|
const OverviewPage = require('../pageobjects/OverviewPage')
|
||||||
|
|
||||||
|
describe('An user without management tag', function () {
|
||||||
|
let homePage
|
||||||
|
let idpLogin
|
||||||
|
let overview
|
||||||
|
let captureScreen
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
driver = buildDriver()
|
||||||
|
await goToHome(driver)
|
||||||
|
login = new LoginPage(driver)
|
||||||
|
overview = new OverviewPage(driver)
|
||||||
|
captureScreen = captureScreensFor(driver, __filename)
|
||||||
|
|
||||||
|
assert.ok(!await login.isPopupWarningDisplayed())
|
||||||
|
await login.login('rabbit_no_management', 'rabbit_no_management')
|
||||||
|
await !overview.isLoaded()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('cannot log in into the management ui', async function () {
|
||||||
|
const visible = await login.isWarningVisible()
|
||||||
|
assert.ok(visible)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get "Login failed" warning message', async function(){
|
||||||
|
assert.equal('Login failed', await login.getWarning())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get popup warning dialog', async function(){
|
||||||
|
assert.ok(login.isPopupWarningDisplayed())
|
||||||
|
assert.equal('Not_Authorized', await login.getPopupWarning())
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("After clicking on popup warning dialog button", function() {
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
await login.closePopupWarning()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should close popup warning', async function(){
|
||||||
|
await delay(1000)
|
||||||
|
const visible = await login.isPopupWarningDisplayed()
|
||||||
|
assert.ok(!visible)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await teardown(driver, this, captureScreen)
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,5 +1,5 @@
|
||||||
[accept,amqp10_client,amqp_client,base64url,cowboy,cowlib,eetcd,gun,jose,
|
[accept,amqp10_client,amqp_client,base64url,cowboy,cowlib,eetcd,gun,jose,
|
||||||
oauth2_client,prometheus,rabbitmq_auth_backend_cache,
|
oauth2_client,prometheus,rabbitmq_amqp1_0,rabbitmq_auth_backend_cache,
|
||||||
rabbitmq_auth_backend_http,rabbitmq_auth_backend_ldap,
|
rabbitmq_auth_backend_http,rabbitmq_auth_backend_ldap,
|
||||||
rabbitmq_auth_backend_oauth2,rabbitmq_auth_mechanism_ssl,rabbitmq_aws,
|
rabbitmq_auth_backend_oauth2,rabbitmq_auth_mechanism_ssl,rabbitmq_aws,
|
||||||
rabbitmq_consistent_hash_exchange,rabbitmq_event_exchange,
|
rabbitmq_consistent_hash_exchange,rabbitmq_event_exchange,
|
||||||
|
|
|
@ -44,6 +44,13 @@
|
||||||
"monitoring"
|
"monitoring"
|
||||||
],
|
],
|
||||||
"limits": {}
|
"limits": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rabbit_no_management",
|
||||||
|
"password_hash": "Joz9zzUBOrX10lB3GisWN5oTXK+wj0gxS/nyrfTYmBOuhps5",
|
||||||
|
"hashing_algorithm": "rabbit_password_hashing_sha256",
|
||||||
|
"tags": [ ],
|
||||||
|
"limits": {}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"vhosts": [
|
"vhosts": [
|
||||||
|
@ -65,6 +72,13 @@
|
||||||
"configure": ".*",
|
"configure": ".*",
|
||||||
"write": ".*",
|
"write": ".*",
|
||||||
"read": ".*"
|
"read": ".*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user": "rabbit_no_management",
|
||||||
|
"vhost": "/",
|
||||||
|
"configure": ".*",
|
||||||
|
"write": ".*",
|
||||||
|
"read": ".*"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
59
deps/rabbitmq_management/selenium/test/oauth/with-basic-auth/unauthorized.js
vendored
Normal file
59
deps/rabbitmq_management/selenium/test/oauth/with-basic-auth/unauthorized.js
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
const { By, Key, until, Builder } = require('selenium-webdriver')
|
||||||
|
require('chromedriver')
|
||||||
|
const assert = require('assert')
|
||||||
|
const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage } = require('../../utils')
|
||||||
|
|
||||||
|
const SSOHomePage = require('../../pageobjects/SSOHomePage')
|
||||||
|
const OverviewPage = require('../../pageobjects/OverviewPage')
|
||||||
|
|
||||||
|
describe('An user without management tag', function () {
|
||||||
|
let homePage
|
||||||
|
let idpLogin
|
||||||
|
let overview
|
||||||
|
let captureScreen
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
driver = buildDriver()
|
||||||
|
await goToHome(driver)
|
||||||
|
homePage = new SSOHomePage(driver)
|
||||||
|
idpLogin = idpLoginPage(driver)
|
||||||
|
overview = new OverviewPage(driver)
|
||||||
|
captureScreen = captureScreensFor(driver, __filename)
|
||||||
|
|
||||||
|
await homePage.clickToLogin()
|
||||||
|
await idpLogin.login('rabbit_no_management', 'rabbit_no_management')
|
||||||
|
if (!await homePage.isLoaded()) {
|
||||||
|
throw new Error('Failed to login')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('cannot log in into the management ui', async function () {
|
||||||
|
const visible = await homePage.isWarningVisible()
|
||||||
|
assert.ok(visible)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get "Not authorized" warning message', async function(){
|
||||||
|
assert.equal('Not authorized', await homePage.getWarning())
|
||||||
|
assert.equal('Click here to logout', await homePage.getLogoutButton())
|
||||||
|
assert.ok(!await homePage.isBasicAuthSectionVisible())
|
||||||
|
assert.ok(!await homePage.isOAuth2SectionVisible())
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("After clicking on logout button", function() {
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
await homePage.clickToLogout()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get redirected to home page again without error message', async function(){
|
||||||
|
const visible = await homePage.isWarningVisible()
|
||||||
|
assert.ok(!visible)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await teardown(driver, this, captureScreen)
|
||||||
|
})
|
||||||
|
})
|
|
@ -6,7 +6,7 @@ const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage } = req
|
||||||
const SSOHomePage = require('../../pageobjects/SSOHomePage')
|
const SSOHomePage = require('../../pageobjects/SSOHomePage')
|
||||||
const OverviewPage = require('../../pageobjects/OverviewPage')
|
const OverviewPage = require('../../pageobjects/OverviewPage')
|
||||||
|
|
||||||
describe('An user without administrator tag', function () {
|
describe('An user without management tag', function () {
|
||||||
let homePage
|
let homePage
|
||||||
let idpLogin
|
let idpLogin
|
||||||
let overview
|
let overview
|
||||||
|
|
|
@ -13,6 +13,9 @@ const EXCHANGES_TAB = By.css('div#menu ul#tabs li#exchanges')
|
||||||
const ADMIN_TAB = By.css('div#menu ul#tabs li#admin')
|
const ADMIN_TAB = By.css('div#menu ul#tabs li#admin')
|
||||||
const STREAM_CONNECTIONS_TAB = By.css('div#menu ul#tabs li#stream-connections')
|
const STREAM_CONNECTIONS_TAB = By.css('div#menu ul#tabs li#stream-connections')
|
||||||
|
|
||||||
|
const FORM_POPUP = By.css('div.form-popup-warn')
|
||||||
|
const FORM_POPUP_CLOSE_BUTTON = By.css('div.form-popup-warn span')
|
||||||
|
|
||||||
module.exports = class BasePage {
|
module.exports = class BasePage {
|
||||||
driver
|
driver
|
||||||
timeout
|
timeout
|
||||||
|
@ -24,7 +27,6 @@ module.exports = class BasePage {
|
||||||
this.timeout = parseInt(process.env.SELENIUM_TIMEOUT) || 1000 // max time waiting to locate an element. Should be less that test timeout
|
this.timeout = parseInt(process.env.SELENIUM_TIMEOUT) || 1000 // max time waiting to locate an element. Should be less that test timeout
|
||||||
this.polling = parseInt(process.env.SELENIUM_POLLING) || 500 // how frequent selenium searches for an element
|
this.polling = parseInt(process.env.SELENIUM_POLLING) || 500 // how frequent selenium searches for an element
|
||||||
this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy)
|
this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy)
|
||||||
console.log("Interaction Delay : " + this.interactionDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,7 +140,14 @@ module.exports = class BasePage {
|
||||||
return table_model
|
return table_model
|
||||||
}
|
}
|
||||||
async isPopupWarningDisplayed() {
|
async isPopupWarningDisplayed() {
|
||||||
const element = "form-popup-warn"
|
try {
|
||||||
|
let element = await driver.findElement(FORM_POPUP)
|
||||||
|
return element.isDisplayed()
|
||||||
|
} catch(e) {
|
||||||
|
return Promise.resolve(false)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
let element = await driver.findElement(FORM_POPUP)
|
||||||
return this.driver.wait(until.elementIsVisible(element), this.timeout / 2,
|
return this.driver.wait(until.elementIsVisible(element), this.timeout / 2,
|
||||||
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
||||||
this.polling / 2).then(function onWarningVisible(e) {
|
this.polling / 2).then(function onWarningVisible(e) {
|
||||||
|
@ -146,17 +155,20 @@ module.exports = class BasePage {
|
||||||
}, function onError(e) {
|
}, function onError(e) {
|
||||||
return Promise.resolve(false)
|
return Promise.resolve(false)
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
async getPopupWarning() {
|
async getPopupWarning() {
|
||||||
const element = "form-popup-warn"
|
let element = await driver.findElement(FORM_POPUP)
|
||||||
return this.driver.wait(until.elementIsVisible(element), this.timeout,
|
return this.driver.wait(until.elementIsVisible(element), this.timeout,
|
||||||
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
||||||
this.polling)
|
this.polling).getText().then((value) => value.substring(0, value.search('\n\nClose')))
|
||||||
|
}
|
||||||
|
async closePopupWarning() {
|
||||||
|
return this.click(FORM_POPUP_CLOSE_BUTTON)
|
||||||
}
|
}
|
||||||
|
|
||||||
async isDisplayed(locator) {
|
async isDisplayed(locator) {
|
||||||
try {
|
try {
|
||||||
element = await driver.findElement(locator)
|
let element = await driver.findElement(locator)
|
||||||
|
|
||||||
return this.driver.wait(until.elementIsVisible(element), this.timeout,
|
return this.driver.wait(until.elementIsVisible(element), this.timeout,
|
||||||
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
|
||||||
|
|
|
@ -6,6 +6,7 @@ const FORM = By.css('div#login form')
|
||||||
const USERNAME = By.css('input[name="username"]')
|
const USERNAME = By.css('input[name="username"]')
|
||||||
const PASSWORD = By.css('input[name="password"]')
|
const PASSWORD = By.css('input[name="password"]')
|
||||||
const LOGIN_BUTTON = By.css('div#outer div#login form input[type=submit]')
|
const LOGIN_BUTTON = By.css('div#outer div#login form input[type=submit]')
|
||||||
|
const WARNING = By.css('div#outer div#login div#login-status p')
|
||||||
|
|
||||||
module.exports = class LoginPage extends BasePage {
|
module.exports = class LoginPage extends BasePage {
|
||||||
async isLoaded () {
|
async isLoaded () {
|
||||||
|
@ -22,4 +23,26 @@ module.exports = class LoginPage extends BasePage {
|
||||||
async getLoginButton () {
|
async getLoginButton () {
|
||||||
return this.getValue(LOGIN_BUTTON)
|
return this.getValue(LOGIN_BUTTON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async isWarningVisible () {
|
||||||
|
try {
|
||||||
|
await this.waitForDisplayed(WARNING)
|
||||||
|
return Promise.resolve(true)
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.resolve(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getWarnings() {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return driver.findElements(WARNING)
|
||||||
|
} catch (NoSuchElement) {
|
||||||
|
return Promise.resolve([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getWarning () {
|
||||||
|
return this.getText(WARNING)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,28 +9,49 @@
|
||||||
|
|
||||||
-export([init/2]).
|
-export([init/2]).
|
||||||
|
|
||||||
-include_lib("amqp_client/include/amqp_client.hrl").
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
init(Req0, State) ->
|
init(Req0, State) ->
|
||||||
bootstrap_oauth(rabbit_mgmt_headers:set_no_cache_headers(
|
bootstrap_oauth(rabbit_mgmt_headers:set_no_cache_headers(
|
||||||
rabbit_mgmt_headers:set_common_permission_headers(Req0, ?MODULE), ?MODULE), State).
|
rabbit_mgmt_headers:set_common_permission_headers(Req0, ?MODULE), ?MODULE), State).
|
||||||
|
|
||||||
bootstrap_oauth(Req0, State) ->
|
bootstrap_oauth(Req0, State) ->
|
||||||
JSContent = oauth_initialize_if_required() ++ set_token_auth(Req0),
|
AuthSettings = rabbit_mgmt_wm_auth:authSettings(),
|
||||||
{ok, cowboy_req:reply(200, #{<<"content-type">> => <<"text/javascript; charset=utf-8">>}, JSContent, Req0), State}.
|
Dependencies = oauth_dependencies(),
|
||||||
|
JSContent = import_dependencies(Dependencies) ++
|
||||||
|
set_oauth_settings(AuthSettings) ++
|
||||||
|
set_token_auth(AuthSettings, Req0) ++
|
||||||
|
export_dependencies(Dependencies),
|
||||||
|
{ok, cowboy_req:reply(200, #{<<"content-type">> => <<"text/javascript; charset=utf-8">>},
|
||||||
|
JSContent, Req0), State}.
|
||||||
|
|
||||||
oauth_initialize_if_required() ->
|
set_oauth_settings(AuthSettings) ->
|
||||||
["function oauth_initialize_if_required() { return oauth_initialize(" ,
|
JsonAuthSettings = rabbit_json:encode(rabbit_mgmt_format:format_nulls(AuthSettings)),
|
||||||
rabbit_json:encode(rabbit_mgmt_format:format_nulls(rabbit_mgmt_wm_auth:authSettings())) , ") }" ].
|
["set_oauth_settings(", JsonAuthSettings, ");"].
|
||||||
|
|
||||||
set_token_auth(Req0) ->
|
set_token_auth(AuthSettings, Req0) ->
|
||||||
case application:get_env(rabbitmq_management, oauth_enabled, false) of
|
case proplists:get_value(oauth_enabled, AuthSettings, false) of
|
||||||
true ->
|
true ->
|
||||||
case cowboy_req:parse_header(<<"authorization">>, Req0) of
|
case cowboy_req:parse_header(<<"authorization">>, Req0) of
|
||||||
{bearer, Token} -> ["set_token_auth('", Token, "');"];
|
{bearer, Token} -> ["set_token_auth('", Token, "');"];
|
||||||
_ -> []
|
_ -> []
|
||||||
end;
|
end;
|
||||||
false -> []
|
false ->
|
||||||
end.
|
[]
|
||||||
|
end.
|
||||||
|
|
||||||
|
import_dependencies(Dependencies) ->
|
||||||
|
["import {", string:join(Dependencies, ","), "} from './helper.js';"].
|
||||||
|
|
||||||
|
oauth_dependencies() ->
|
||||||
|
["oauth_initialize_if_required",
|
||||||
|
"hasAnyResourceServerReady",
|
||||||
|
"oauth_initialize", "oauth_initiate",
|
||||||
|
"oauth_initiateLogin",
|
||||||
|
"oauth_initiateLogout",
|
||||||
|
"oauth_completeLogin",
|
||||||
|
"oauth_completeLogout",
|
||||||
|
"set_oauth_settings"].
|
||||||
|
|
||||||
|
export_dependencies(Dependencies) ->
|
||||||
|
[ io_lib:format("window.~s = ~s;", [Dep, Dep]) || Dep <- Dependencies ].
|
||||||
|
|
|
@ -444,7 +444,7 @@ auth_test(Config) ->
|
||||||
%% because user/password are ok, tags are not
|
%% because user/password are ok, tags are not
|
||||||
test_auth(Config, ?NOT_AUTHORISED, [auth_header("user", "user")]),
|
test_auth(Config, ?NOT_AUTHORISED, [auth_header("user", "user")]),
|
||||||
WrongAuthResponseHeaders = test_auth(Config, ?NOT_AUTHORISED, [auth_header("guest", "gust")]),
|
WrongAuthResponseHeaders = test_auth(Config, ?NOT_AUTHORISED, [auth_header("guest", "gust")]),
|
||||||
?assertEqual(true, lists:keymember("www-authenticate", 1, WrongAuthResponseHeaders)),
|
%?assertEqual(true, lists:keymember("www-authenticate", 1, WrongAuthResponseHeaders)),
|
||||||
test_auth(Config, ?OK, [auth_header("guest", "guest")]),
|
test_auth(Config, ?OK, [auth_header("guest", "guest")]),
|
||||||
http_delete(Config, "/users/user", {group, '2xx'}),
|
http_delete(Config, "/users/user", {group, '2xx'}),
|
||||||
passed.
|
passed.
|
||||||
|
|
|
@ -265,7 +265,9 @@ internal_user(User) ->
|
||||||
|
|
||||||
user(User) ->
|
user(User) ->
|
||||||
[{name, User#user.username},
|
[{name, User#user.username},
|
||||||
{tags, tags_as_binaries(User#user.tags)}].
|
{tags, tags_as_binaries(User#user.tags)},
|
||||||
|
{is_internal_user, lists:any(fun({Module,_}) -> Module == rabbit_auth_backend_internal end,
|
||||||
|
User#user.authz_backends)}].
|
||||||
|
|
||||||
tags_as_binaries(Tags) ->
|
tags_as_binaries(Tags) ->
|
||||||
[to_binary(T) || T <- Tags].
|
[to_binary(T) || T <- Tags].
|
||||||
|
|
|
@ -277,15 +277,8 @@ halt_response(Code, Type, Reason, ReqData, Context) ->
|
||||||
rabbit_json:encode(Json), ReqData),
|
rabbit_json:encode(Json), ReqData),
|
||||||
{stop, ReqData1, Context}.
|
{stop, ReqData1, Context}.
|
||||||
|
|
||||||
not_authenticated(Reason, ReqData, Context,
|
not_authenticated(Reason, ReqData, Context, _AuthConfig) ->
|
||||||
#auth_settings{auth_realm = AuthRealm} = AuthConfig) ->
|
halt_response(401, not_authorized, Reason, ReqData, Context).
|
||||||
case is_oauth2_enabled(AuthConfig) of
|
|
||||||
false ->
|
|
||||||
ReqData1 = cowboy_req:set_resp_header(<<"www-authenticate">>, AuthRealm, ReqData),
|
|
||||||
halt_response(401, not_authorized, Reason, ReqData1, Context);
|
|
||||||
true ->
|
|
||||||
halt_response(401, not_authorized, Reason, ReqData, Context)
|
|
||||||
end.
|
|
||||||
|
|
||||||
format_reason(Tuple) when is_tuple(Tuple) ->
|
format_reason(Tuple) when is_tuple(Tuple) ->
|
||||||
tuple(Tuple);
|
tuple(Tuple);
|
||||||
|
@ -366,6 +359,3 @@ log_access_control_result(NotOK) ->
|
||||||
|
|
||||||
is_basic_auth_disabled(#auth_settings{basic_auth_enabled = Enabled}) ->
|
is_basic_auth_disabled(#auth_settings{basic_auth_enabled = Enabled}) ->
|
||||||
not Enabled.
|
not Enabled.
|
||||||
|
|
||||||
is_oauth2_enabled(#auth_settings{oauth2_enabled = Enabled}) ->
|
|
||||||
Enabled.
|
|
||||||
|
|
Loading…
Reference in New Issue