From 18740c273c23ad4e8c6950173b3878d146c5c160 Mon Sep 17 00:00:00 2001 From: Marcial Rosales Date: Mon, 1 Dec 2025 09:44:56 +0100 Subject: [PATCH 1/5] Preserve config order --- .../src/rabbit_mgmt_schema.erl | 2 ++ .../test/rabbit_mgmt_schema_SUITE.erl | 23 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl b/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl index bbcf62181b0d..3a92c8e32773 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl @@ -7,6 +7,7 @@ -module(rabbit_mgmt_schema). +-include_lib("kernel/include/logger.hrl"). -export([ translate_oauth_resource_servers/1, @@ -54,6 +55,7 @@ extract_resource_server_properties(Settings) -> OAuthResourceServers = [{Name, {list_to_atom(Key), convert_list_to_binary(V)}} || {["management","oauth_resource_servers", Name, Key], V} <- Settings ], + ?LOG_DEBUG("OAuthResourceServers: ~p", [OAuthResourceServers]), maps:groups_from_list(KeyFun, ValueFun, OAuthResourceServers). diff --git a/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl b/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl index 86ea4f14f907..d47c62c154fa 100644 --- a/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl +++ b/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl @@ -19,7 +19,8 @@ all() -> test_invalid_endpoint_params, test_translate_endpoint_params, test_with_one_resource_server, - test_with_many_resource_servers + test_with_many_resource_servers, + test_preserve_order_when_using_many_resource_servers ]. @@ -67,6 +68,26 @@ test_with_many_resource_servers(_) -> ] } = translate_oauth_resource_servers(Conf). +test_preserve_order_when_using_many_resource_servers(_) -> + Conf = [ + {["management","oauth_resource_servers","uaa","label"],"Uaa"}, + {["management","oauth_resource_servers","spring","label"],"Spring"}, + {["management","oauth_resource_servers","keycloak","label"],"Keycloak"} + ], + #{ + <<"uaa">> := [ + {label, <<"Uaa">>}, + {id, <<"uaa">>} + ], + <<"spring">> := [ + {label, <<"Spring">>}, + {id, <<"spring">>} + ], + <<"keycloak">> := [ + {label, <<"Keycloak">>}, + {id, <<"keycloak">>} + ] + } = translate_oauth_resource_servers(Conf). cert_filename(Conf) -> string:concat(?config(data_dir, Conf), "certs/cert.pem"). From 2ebcc860cd678364ddbb9b9279b6ac1c804351af Mon Sep 17 00:00:00 2001 From: Marcial Rosales Date: Wed, 3 Dec 2025 10:51:08 +0100 Subject: [PATCH 2/5] Annotate oauth_resource_server with index attribute --- .../priv/www/js/oidc-oauth/helper.js | 7 ++-- .../src/rabbit_mgmt_schema.erl | 26 ++++++++---- .../src/rabbit_mgmt_wm_auth.erl | 2 + .../test/rabbit_mgmt_schema_SUITE.erl | 37 ++++++++++++----- selenium/Dockerfile | 1 + selenium/README.md | 41 +++++++++++++++++++ selenium/bin/components/devkeycloak | 2 +- selenium/bin/components/prodkeycloak | 2 +- .../multi-oauth/without-basic-auth/landing.js | 19 +++++---- 9 files changed, 105 insertions(+), 32 deletions(-) diff --git a/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js b/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js index be84377e22d6..695dc871bc24 100644 --- a/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js +++ b/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js @@ -392,11 +392,12 @@ export function hasAnyResourceServerReady(oauth, onReadyCallback) { warnings.push(warningMessageOAuthResources(url, notCompliantResources, " not compliant")) } } - oauth.declared_resource_servers_count = oauth.resource_servers.length + 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)) + !notReadyServers.includes(resource.oauth_provider_url) && !notCompliantServers.includes(resource.oauth_provider_url)); + oauth.resource_servers.sort((a, b) => a.index - b.index); - onReadyCallback(oauth, warnings) + onReadyCallback(oauth, warnings) }) }else { diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl b/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl index 3a92c8e32773..f1f52ad1dbfd 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_schema.erl @@ -15,17 +15,22 @@ ]). extract_key_as_binary({Name,_}) -> list_to_binary(Name). -extract_value({_Name,V}) -> V. -spec translate_oauth_resource_servers([{list(), binary()}]) -> map(). translate_oauth_resource_servers(Conf) -> + %% Note: Conf must be reversed because cuttlefish_generator:transform_datatypes + %% reverse the order of the configuration from rabbitmq.conf. + %% Exactly on this line: `{[{Variable, NewValue}|Acc], ErrorAcc};` + Settings = cuttlefish_variable:filter_by_prefix( - "management.oauth_resource_servers", Conf), + "management.oauth_resource_servers", lists:reverse(Conf)), + Map = merge_list_of_maps([ extract_resource_server_properties(Settings), extract_resource_server_endpoint_params(oauth_authorization_endpoint_params, Settings), extract_resource_server_endpoint_params(oauth_token_endpoint_params, Settings) ]), + ?LOG_DEBUG("translate_oauth_resource_servers: ~p", [Map]), Map0 = maps:map(fun(K,V) -> case proplists:get_value(id, V) of undefined -> V ++ [{id, K}]; @@ -49,15 +54,18 @@ convert_list_to_binary(V) when is_list(V) -> convert_list_to_binary(V) -> V. -extract_resource_server_properties(Settings) -> - KeyFun = fun extract_key_as_binary/1, - ValueFun = fun extract_value/1, - +extract_resource_server_properties(Settings) -> OAuthResourceServers = [{Name, {list_to_atom(Key), convert_list_to_binary(V)}} || {["management","oauth_resource_servers", Name, Key], V} <- Settings ], - ?LOG_DEBUG("OAuthResourceServers: ~p", [OAuthResourceServers]), - maps:groups_from_list(KeyFun, ValueFun, OAuthResourceServers). - + OAuthResourceServers1 = lists:foldl(fun ({K, Value}, Acc) -> + Key = list_to_binary(K), + Attrs = case maps:get(Key, Acc, []) of + [] -> [] ++ [{index, maps:size(Acc)+1}, Value]; + List -> List ++ [Value] + end, + maps:put(Key, Attrs, Acc) end, #{}, OAuthResourceServers), + ct:log("OAuthResourceServers1: ~p", [OAuthResourceServers1]), + OAuthResourceServers1. extract_resource_server_endpoint_params(Variable, Settings) -> KeyFun = fun extract_key_as_binary/1, diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_wm_auth.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_auth.erl index 26ff40a319a8..18a3c0a0005f 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_wm_auth.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_auth.erl @@ -13,6 +13,7 @@ -include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). -include_lib("oauth2_client/include/oauth2_client.hrl"). +-include_lib("kernel/include/logger.hrl"). %%-------------------------------------------------------------------- @@ -119,6 +120,7 @@ buildRootResourceServerIfAny(Id, Props) -> authSettings() -> ManagementProps = application:get_all_env(rabbitmq_management), + ?LOG_DEBUG("ManagementProps: ~p", [ManagementProps]), OAuth2BackendProps = application:get_all_env(rabbitmq_auth_backend_oauth2), EnableOAUTH = proplists:get_value(oauth_enabled, ManagementProps, false), case EnableOAUTH of diff --git a/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl b/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl index d47c62c154fa..59d3762f9044 100644 --- a/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl +++ b/deps/rabbitmq_management/test/rabbit_mgmt_schema_SUITE.erl @@ -48,6 +48,7 @@ test_with_one_resource_server(_) -> ], #{ <<"rabbitmq1">> := [ + {index, 1}, {id, <<"rabbitmq1">>} ] } = translate_oauth_resource_servers(Conf). @@ -59,10 +60,12 @@ test_with_many_resource_servers(_) -> ], #{ <<"keycloak">> := [ + {index, 1}, {label, <<"Keycloak">>}, {id, <<"keycloak">>} ], <<"uaa">> := [ + {index, 2}, {label, <<"Uaa">>}, {id, <<"uaa">>} ] @@ -71,23 +74,35 @@ test_with_many_resource_servers(_) -> test_preserve_order_when_using_many_resource_servers(_) -> Conf = [ {["management","oauth_resource_servers","uaa","label"],"Uaa"}, + {["management","oauth_resource_servers","uaa","oauth_client_id"],"uaa-client"}, {["management","oauth_resource_servers","spring","label"],"Spring"}, - {["management","oauth_resource_servers","keycloak","label"],"Keycloak"} + {["management","oauth_resource_servers","spring","oauth_client_id"],"spring-client"}, + {["management","oauth_resource_servers","keycloak","label"],"Keycloak"}, + {["management","oauth_resource_servers","keycloak","oauth_client_id"],"keycloak-client"} ], - #{ - <<"uaa">> := [ + SortByIndex = fun({_, A}, {_, B}) -> + proplists:get_value(index, A) =< proplists:get_value(index, B) end, + + [ + {<<"uaa">>, [ + {index, 1}, {label, <<"Uaa">>}, + {oauth_client_id, <<"uaa-client">>}, {id, <<"uaa">>} - ], - <<"spring">> := [ + ]}, + {<<"spring">>, [ + {index, 2}, {label, <<"Spring">>}, - {id, <<"spring">>} - ], - <<"keycloak">> := [ + {oauth_client_id, <<"spring-client">>}, + {id, <<"spring">>} + ]}, + {<<"keycloak">>, [ + {index, 3}, {label, <<"Keycloak">>}, - {id, <<"keycloak">>} - ] - } = translate_oauth_resource_servers(Conf). + {oauth_client_id, <<"keycloak-client">>}, + {id, <<"keycloak">>} + ]} + ] = lists:sort(SortByIndex, maps:to_list(translate_oauth_resource_servers(Conf))). cert_filename(Conf) -> string:concat(?config(data_dir, Conf), "certs/cert.pem"). diff --git a/selenium/Dockerfile b/selenium/Dockerfile index a1da5b0fc6b2..9f8acb36469c 100644 --- a/selenium/Dockerfile +++ b/selenium/Dockerfile @@ -3,6 +3,7 @@ FROM node:24 AS base WORKDIR /code COPY package.json package.json +COPY .npmrc .npmrc FROM base AS test RUN npm install --verbose diff --git a/selenium/README.md b/selenium/README.md index 6bec54a14fad..cc19c891b1ef 100644 --- a/selenium/README.md +++ b/selenium/README.md @@ -236,3 +236,44 @@ following command: MOCHA_DOCKER_FILE=\location\of\my\Dockerfile ./run-suites.sh ``` +## How to solve : NPM packages are blocked by network firewalls + +This network issue manifests in two stages. One stage is when you run the tests +interactively, i.e. using `npm` directly in the host machine. The steps below configures +npm, in the host machine, so that it is not blocked by network firewalls. + +1. Make sure you are connected to the VPN in Full Tunnel mode. Artifactory returns an HTTP 403 forbidden error from anywhere outside the full corporate network. +2. `cd selenium` +3. `npm config set registry https://usw1.packages.broadcom.com/artifactory/api/npm/tds-rabbitmq-npm-virtual/ -L project` +4. `npm login --auth-type=web` +5. After you run the last command you should see the folowing sentence +`Login at: +https://usw1.packages.broadcom.com/ui/auth-provider/npm?uuid=JEGSj5dC8X4S8TGKPL2CbSPR3CSnVgvz5r3hMZAbioQy9o98Y7hKvQ7NjA7pxZ21upVkiP1pWkRjpb4CDUDRur4UFwdGhndcas5JexreDXpykBtGsy6 +Press ENTER to open in the browser... +` +6. Press enter so that it opens on a browser +7. JFrog loads and it prompts you if you are loging in. You accept you are logging. +8. You should get the message `Login performed successfully. Redirecting to home page.` + +For further information, checkout https://github.gwd.broadcom.net/TNZ/rabbitmq-private-docs/wiki/Artifactory-NPM. + +If you need to build a `mocha-test` image because you want to run the tests in +silent mode, i.e. in the background, you need to configure NPM in docker. +Follow these steps: + +1. Navigate to https://usw1.packages.broadcom.com/ +2. Log in with your Broadcom credentials +3. Click on your username in the top-right corner +4. Select "Edit Profile" +5. In the left sidebar, click "Generate an Identity Token" +6. Copy the generated token +7. Edit file selenium/.npmrc and make sure it has this format. +``` +registry=https://usw1.packages.broadcom.com/artifactory/api/npm/tds-rabbitmq-npm-virtual/ +//usw1.packages.broadcom.com/artifactory/api/npm/tds-rabbitmq-npm-virtual/:_authToken= +``` +Note: The `Dockerfile` copies the .npmrc into the image. + +For further information, check out https://github.gwd.broadcom.net/TNZ/rabbitmq-private-docs/wiki/Artifactory-Docker#step-1-generate-artifactory-token. + +Note: You will notice that building the mocha-image takes far longer now. \ No newline at end of file diff --git a/selenium/bin/components/devkeycloak b/selenium/bin/components/devkeycloak index dbd2d368af6a..51acb8c4dd39 100644 --- a/selenium/bin/components/devkeycloak +++ b/selenium/bin/components/devkeycloak @@ -48,7 +48,7 @@ start_devkeycloak() { --https-certificate-key-file=/opt/keycloak/data/import/server_devkeycloak_key.pem \ --hostname=devkeycloak --hostname-admin=devkeycloak --https-port=8442 - 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_devkeycloak_certificate.pem end "devkeycloak is ready" 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/" diff --git a/selenium/bin/components/prodkeycloak b/selenium/bin/components/prodkeycloak index 462d16b3e4b8..8dd2d6aa84f9 100644 --- a/selenium/bin/components/prodkeycloak +++ b/selenium/bin/components/prodkeycloak @@ -47,7 +47,7 @@ start_prodkeycloak() { --https-certificate-key-file=/opt/keycloak/data/import/server_prodkeycloak_key.pem \ --hostname=prodkeycloak --hostname-admin=prodkeycloak --https-port=8443 - 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_prodkeycloak_certificate.pem end "prodkeycloak is ready" 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/" diff --git a/selenium/test/multi-oauth/without-basic-auth/landing.js b/selenium/test/multi-oauth/without-basic-auth/landing.js index 662bb09c1cdf..01a7cb73efdb 100644 --- a/selenium/test/multi-oauth/without-basic-auth/landing.js +++ b/selenium/test/multi-oauth/without-basic-auth/landing.js @@ -27,15 +27,20 @@ describe('Given three oauth resources but only two enabled, an unauthenticated u resources = await homePage.getOAuthResourceOptions() if (hasProfile("with-resource-label")) { assertAllOptions([ - { value : "rabbit_dev", text : "RabbitMQ Development" }, - { value : "rabbit_prod", text : "RabbitMQ Production" } - ], resources) + { value : "rabbit_prod", text : "RabbitMQ Production" }, + { value : "rabbit_dev", text : "RabbitMQ Development" } + ], resources); + // assert resources are rendered in the same order they are configured : prod and then dev + assert.equal("RabbitMQ Production", resources[0].text); + assert.equal("RabbitMQ Development", resources[1].text); }else { assertAllOptions([ - { value : "rabbit_dev", text : "rabbit_dev" }, - { value : "rabbit_prod", text : "rabbit_prod" } - ], resources) - } + { value : "rabbit_prod", text : "rabbit_prod" }, + { value : "rabbit_dev", text : "rabbit_dev" } + ], resources); + assert.equal("rabbit_prod", resources[0].text); + assert.equal("rabbit_dev", resources[1].text); + } }) it('should not be presented with a login button to log in using Basic Auth', async function () { From 99aaa053f82d69a58a04165e19067a6332866766 Mon Sep 17 00:00:00 2001 From: Marcial Rosales Date: Tue, 9 Dec 2025 15:00:24 +0100 Subject: [PATCH 3/5] /login endpoint accepts login preferences --- .../include/rabbit_mgmt.hrl | 6 +- deps/rabbitmq_management/priv/www/js/main.js | 17 +- .../priv/www/js/oidc-oauth/helper.js | 12 +- .../priv/www/js/tmpl/login_oauth.ejs | 29 +++- .../src/rabbit_mgmt_login.erl | 145 +++++++++++++++--- .../src/rabbit_mgmt_oauth_bootstrap.erl | 86 ++++++++++- .../src/rabbit_mgmt_schema.erl | 7 +- .../src/rabbit_mgmt_wm_auth.erl | 1 - .../rabbitmq_management.snippets | 17 +- .../test/rabbit_mgmt_http_SUITE.erl | 30 ---- .../test/rabbit_mgmt_schema_SUITE.erl | 8 +- selenium/Dockerfile | 1 - selenium/Dockerfile.local | 12 ++ selenium/README.md | 41 ----- .../multi-oauth/without-basic-auth/landing.js | 17 +- 15 files changed, 285 insertions(+), 144 deletions(-) create mode 100644 selenium/Dockerfile.local diff --git a/deps/rabbitmq_management/include/rabbit_mgmt.hrl b/deps/rabbitmq_management/include/rabbit_mgmt.hrl index 53f83c001810..be0a3dfdca65 100644 --- a/deps/rabbitmq_management/include/rabbit_mgmt.hrl +++ b/deps/rabbitmq_management/include/rabbit_mgmt.hrl @@ -14,5 +14,7 @@ -define(MANAGEMENT_DEFAULT_HTTP_MAX_BODY_SIZE, 20000000). --define(OAUTH2_ACCESS_TOKEN_COOKIE_NAME, <<"access_token">>). --define(OAUTH2_ACCESS_TOKEN_COOKIE_PATH, <<"js/oidc-oauth/bootstrap.js">>). +-define(OAUTH2_ACCESS_TOKEN, <<"access_token">>). +-define(OAUTH2_BOOTSTRAP_PATH, <<"js/oidc-oauth/bootstrap.js">>). +-define(MANAGEMENT_LOGIN_STRICT_AUTH_MECHANISM, <<"strict_auth_mechanism">>). +-define(MANAGEMENT_LOGIN_PREFERRED_AUTH_MECHANISM, <<"preferred_auth_mechanism">>). diff --git a/deps/rabbitmq_management/priv/www/js/main.js b/deps/rabbitmq_management/priv/www/js/main.js index 7e910978ed12..6604555e057a 100644 --- a/deps/rabbitmq_management/priv/www/js/main.js +++ b/deps/rabbitmq_management/priv/www/js/main.js @@ -41,12 +41,14 @@ function startWithOAuthLogin (oauth) { } } function render_login_oauth(oauth, messages) { - let formatData = {} - formatData.warnings = [] - formatData.notAuthorized = false - formatData.resource_servers = oauth.resource_servers - formatData.declared_resource_servers_count = oauth.declared_resource_servers_count - formatData.oauth_disable_basic_auth = oauth.oauth_disable_basic_auth + let formatData = {}; + formatData.warnings = []; + formatData.notAuthorized = false; + formatData.resource_servers = oauth.resource_servers; + formatData.declared_resource_servers_count = oauth.declared_resource_servers_count; + formatData.oauth_disable_basic_auth = oauth.oauth_disable_basic_auth; + formatData.strict_auth_mechanism = oauth.strict_auth_mechanism; + formatData.preferred_auth_mechanism = oauth.preferred_auth_mechanism; if (Array.isArray(messages)) { formatData.warnings = messages @@ -1133,6 +1135,9 @@ function update_truncate() { function setup_visibility() { $('div.section,div.section-hidden').each(function(_index) { + if ($(this).hasClass("disable-pref")) { + return; + } var pref = section_pref(current_template, $(this).children('h2').text()); var show = get_pref(pref); diff --git a/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js b/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js index 695dc871bc24..5a2248bfb50e 100644 --- a/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js +++ b/deps/rabbitmq_management/priv/www/js/oidc-oauth/helper.js @@ -193,16 +193,24 @@ function oauth_initialize_user_manager(resource_server) { }); } + export function oauth_initialize(authSettings) { authSettings = auth_settings_apply_defaults(authSettings); let oauth = { "logged_in": false, "enabled" : authSettings.oauth_enabled, "resource_servers" : authSettings.resource_servers, - "oauth_disable_basic_auth" : authSettings.oauth_disable_basic_auth + "oauth_disable_basic_auth" : authSettings.oauth_disable_basic_auth, } if (!oauth.enabled) return oauth; - + + if (authSettings.resource_servers.length > 1 || !authSettings.oauth_disable_basic_auth) { + if (authSettings.strict_auth_mechanism) { + oauth["strict_auth_mechanism"] = authSettings.strict_auth_mechanism; + }else if (authSettings.preferred_auth_mechanism) { + oauth["preferred_auth_mechanism"] = authSettings.preferred_auth_mechanism; + } + } let resource_server = null; if (oauth.resource_servers.length == 1) { diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs index 0e6f46be873c..06fb142a419d 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs @@ -12,14 +12,22 @@ <% } %> <% if (!notAuthorized) { %> - <% if ((typeof resource_servers == 'object' && resource_servers.length == 1) && oauth_disable_basic_auth) { %> + <% if (strict_auth_mechanism !== undefined && strict_auth_mechanism.type === "oauth2") { %> + + <% } else if ((typeof resource_servers == 'object' && resource_servers.length == 1) && oauth_disable_basic_auth) { %> - <% } else if (typeof resource_servers == 'object' && resource_servers.length >= 1) { %> + <% } else if (typeof resource_servers == 'object' && resource_servers.length >= 1 && strict_auth_mechanism == undefined) { %> Login with :

+ <% const OAuth2Visible = (strict_auth_mechanism === undefined || strict_auth_mechanism.type === "oauth2") || + (preferred_auth_mechanism === undefined || preferred_auth_mechanism === "oauth2"); %> + <% const OAuth2Invisible = (preferred_auth_mechanism !== undefined && preferred_auth_mechanism.type !== "oauth2"); %> + <% const OAuth2Hidden = (strict_auth_mechanism !== undefined && strict_auth_mechanism.type !== "oauth2"); %> + <% const preferredResourceId = preferred_auth_mechanism !== undefined && preferred_auth_mechanism.type === "oauth2" ? preferred_auth_mechanism.resource_id : null; %> -

+ <% if (!OAuth2Hidden) { %> +

OAuth 2.0

@@ -27,10 +35,10 @@ <% } else { %>
- +