diff --git a/.github/workflows/test-authnz.yaml b/.github/workflows/test-authnz.yaml index 75b6b74ced..c7ba3f22af 100644 --- a/.github/workflows/test-authnz.yaml +++ b/.github/workflows/test-authnz.yaml @@ -10,13 +10,8 @@ on: - 'deps/rabbitmq_auth_**' - 'deps/rabbitmq_management/src/**' - 'deps/rabbitmq_management/priv/**' - - 'deps/rabbitmq_management/selenium/**' + - 'selenium/**' - 'scripts/**' - - .bazelrc - - .bazelversion - - BUILD.* - - '*.bzl' - - '*.bazel' - .github/workflows/test-authnz.yaml pull_request: paths: diff --git a/.github/workflows/test-management-ui.yaml b/.github/workflows/test-management-ui.yaml index d1cde41f27..9ff82e615b 100644 --- a/.github/workflows/test-management-ui.yaml +++ b/.github/workflows/test-management-ui.yaml @@ -12,11 +12,6 @@ on: - 'deps/rabbitmq_management/priv/**' - 'deps/rabbitmq_web_dispatch/src/**' - 'scripts/**' - - .bazelrc - - .bazelversion - - BUILD.* - - '*.bzl' - - '*.bazel' - 'selenium/**' - .github/workflows/test-management-ui.yaml diff --git a/deps/oauth2_client/include/types.hrl b/deps/oauth2_client/include/types.hrl index 622cae2220..d86bbc90ef 100644 --- a/deps/oauth2_client/include/types.hrl +++ b/deps/oauth2_client/include/types.hrl @@ -20,6 +20,14 @@ }). -type openid_configuration() :: #openid_configuration{}. +-record(proxy_options, { + host :: string(), + port :: integer(), + username :: option(string() | binary()), + password :: option(string() | binary()) +}). +-type proxy_options() :: #proxy_options{}. + -record(oauth_provider, { id :: oauth_provider_id(), issuer :: option(uri_string:uri_string()), @@ -28,7 +36,8 @@ authorization_endpoint :: option(uri_string:uri_string()), end_session_endpoint :: option(uri_string:uri_string()), jwks_uri :: option(uri_string:uri_string()), - ssl_options :: option(list()) + ssl_options :: option(list()), + proxy_options :: option(proxy_options()) }). -type query_list() :: [{unicode:chardata(), unicode:chardata() | true}]. diff --git a/deps/oauth2_client/src/oauth2_client.erl b/deps/oauth2_client/src/oauth2_client.erl index c6e07c46c1..e05df68927 100644 --- a/deps/oauth2_client/src/oauth2_client.erl +++ b/deps/oauth2_client/src/oauth2_client.erl @@ -7,13 +7,18 @@ -module(oauth2_client). -export([get_access_token/2, get_expiration_time/1, refresh_access_token/2, + get_jwks/1, get_oauth_provider/1, get_oauth_provider/2, - get_openid_configuration/2, + get_openid_configuration/1, build_openid_discovery_endpoint/3, merge_openid_configuration/2, merge_oauth_provider/2, extract_ssl_options_as_list/1, - format_ssl_options/1, format_oauth_provider/1, format_oauth_provider_id/1 + map_proxy_auth_to_httpc_option/1, + map_proxy_to_httpc_option/1, + map_ssl_options_to_httpc_option/1, + map_timeout_to_httpc_option/1, + format_ssl_options/1, format_oauth_provider/1, format_oauth_provider_id/1 ]). -include("oauth2_client.hrl"). @@ -25,29 +30,82 @@ get_access_token(OAuthProvider, Request) -> rabbit_log:debug("get_access_token using OAuthProvider:~p and client_id:~p", [OAuthProvider, Request#access_token_request.client_id]), URL = OAuthProvider#oauth_provider.token_endpoint, + Id = OAuthProvider#oauth_provider.id, Header = [], Type = ?CONTENT_URLENCODED, Body = build_access_token_request_body(Request), - HTTPOptions = get_ssl_options_if_any(OAuthProvider) ++ - get_timeout_of_default(Request#access_token_request.timeout), - Options = [], - Response = httpc:request(post, {URL, Header, Type, Body}, HTTPOptions, Options), + HTTPOptions = + map_ssl_options_to_httpc_option(OAuthProvider#oauth_provider.ssl_options) ++ + map_timeout_to_httpc_option(Request#access_token_request.timeout), + Response = http_post(Id, URL, Header, Type, Body, HTTPOptions, + OAuthProvider#oauth_provider.proxy_options), parse_access_token_response(Response). -spec refresh_access_token(oauth_provider(), refresh_token_request()) -> {ok, successful_access_token_response()} | {error, unsuccessful_access_token_response() | any()}. refresh_access_token(OAuthProvider, Request) -> + Id = OAuthProvider#oauth_provider.id, URL = OAuthProvider#oauth_provider.token_endpoint, Header = [], Type = ?CONTENT_URLENCODED, Body = build_refresh_token_request_body(Request), - HTTPOptions = get_ssl_options_if_any(OAuthProvider) ++ - get_timeout_of_default(Request#refresh_token_request.timeout), - Options = [], - Response = httpc:request(post, {URL, Header, Type, Body}, HTTPOptions, Options), + HTTPOptions = + map_ssl_options_to_httpc_option(OAuthProvider#oauth_provider.ssl_options) ++ + map_timeout_to_httpc_option(Request#refresh_token_request.timeout), + Response = http_post(Id, URL, Header, Type, Body, HTTPOptions, + OAuthProvider#oauth_provider.proxy_options), parse_access_token_response(Response). +ensure_http_client_started(Id, ProxyOptions) -> + Profile = case Id of + root -> root; + _ -> binary_to_atom(Id) + end, + rabbit_log:debug("Starting http client ~p ...", [Profile]), + case inets:start(httpc, [{profile, Profile}]) of + {ok, _} -> + HttpProxyOptions = map_proxy_to_httpc_option(ProxyOptions), + case ensure_http_proxy_options_if_any(Profile, HttpProxyOptions) of + ok -> {ok, Profile}; + {error, _} = Error -> Error + end; + {error, {already_started, _}} -> + {ok, Profile}; + Error -> + rabbit_log:error("Failed to start httpc client: ~p", [Error]), + Error + end. +ensure_http_proxy_options_if_any(_Profile, []) -> + ok; +ensure_http_proxy_options_if_any(Profile, HttpProxyOptions) -> + case httpc:set_options(HttpProxyOptions, Profile) of + ok -> + rabbit_log:debug("Successfully set_options ~p on http client ~p", + [HttpProxyOptions, Profile]), + ok; + {error, _} = Error -> Error + end. + +http_post(Id, URL, Header, Type, Body, HTTPOptions, ProxyOptions) -> + http_request(Id, post, {URL, Header, Type, Body}, HTTPOptions, ProxyOptions). +http_get(Id, URL, HTTPOptions, ProxyOptions) -> + http_request(Id, get, {URL, []}, HTTPOptions, ProxyOptions). +http_request(Id, Method, Payload, HTTPOptions, ProxyOptions) -> + case ensure_http_client_started(Id, ProxyOptions) of + {ok, Profile} -> + case ProxyOptions of + undefined -> + httpc:request(Method, Payload, HTTPOptions, [], Profile); + _ -> + httpc:request(Method, Payload, + HTTPOptions ++ map_proxy_auth_to_httpc_option(ProxyOptions), + [], + Profile) + end; + {error, _} = Error -> Error + end. + append_paths(Path1, Path2) -> erlang:iolist_to_binary([Path1, Path2]). @@ -93,14 +151,27 @@ drop_trailing_path_separator(Path) when is_list(Path) -> _ -> Path end. --spec get_openid_configuration(DiscoveryEndpoint :: uri_string:uri_string(), - ssl:tls_option() | []) -> {ok, openid_configuration()} | {error, term()}. -get_openid_configuration(DiscoverEndpoint, TLSOptions) -> - rabbit_log:debug("get_openid_configuration from ~p (~p)", [DiscoverEndpoint, - format_ssl_options(TLSOptions)]), - Options = [], - Response = httpc:request(get, {DiscoverEndpoint, []}, TLSOptions, Options), +-spec get_openid_configuration(oauth_provider()) -> {ok, openid_configuration()} | {error, term()}. +get_openid_configuration(#oauth_provider{id = Id, discovery_endpoint = Endpoint, + ssl_options = SslOptions, proxy_options = ProxyOptions}) -> + rabbit_log:debug("get_openid_configuration from ~p (~p) [~p]", [Endpoint, + format_ssl_options(SslOptions), format_proxy_options(ProxyOptions)]), + HTTPOptions = + map_ssl_options_to_httpc_option(SslOptions) ++ + map_timeout_to_httpc_option(?DEFAULT_HTTP_TIMEOUT), + + Response = http_get(Id, Endpoint, HTTPOptions, ProxyOptions), parse_openid_configuration_response(Response). + +-spec get_jwks(oauth_provider()) -> {ok, term()} | {error, term()}. +get_jwks(#oauth_provider{id = Id, jwks_uri = JwksUrl, + ssl_options = SslOptions, proxy_options = ProxyOptions}) -> + rabbit_log:debug("get_jwks from ~p (~p) [~p]", [JwksUrl, + format_ssl_options(SslOptions), format_proxy_options(ProxyOptions)]), + HTTPOptions = + map_ssl_options_to_httpc_option(SslOptions) ++ + map_timeout_to_httpc_option(?DEFAULT_HTTP_TIMEOUT), + http_get(Id, JwksUrl, HTTPOptions, ProxyOptions). -spec merge_openid_configuration(openid_configuration(), oauth_provider()) -> oauth_provider(). @@ -283,7 +354,7 @@ download_oauth_provider(OAuthProvider) -> undefined -> {error, {missing_oauth_provider_attributes, [issuer]}}; URL -> rabbit_log:debug("Downloading oauth_provider using ~p ", [URL]), - case get_openid_configuration(URL, get_ssl_options_if_any(OAuthProvider)) of + case get_openid_configuration(OAuthProvider) of {ok, OpenIdConfiguration} -> {ok, update_oauth_provider_endpoints_configuration( merge_openid_configuration(OpenIdConfiguration, OAuthProvider))}; @@ -341,7 +412,6 @@ get_oauth_provider(OAuthProviderId, ListOfRequiredAttributes) [OAuthProviderId, Error0]), Error0; Config -> - rabbit_log:debug("Found oauth_provider configuration ~p", [Config]), OAuthProvider = map_to_oauth_provider(Config), rabbit_log:debug("Resolved oauth_provider ~p", [format_oauth_provider(OAuthProvider)]), case find_missing_attributes(OAuthProvider, ListOfRequiredAttributes) of @@ -395,8 +465,36 @@ lookup_root_oauth_provider() -> token_endpoint = get_env(token_endpoint), authorization_endpoint = get_env(authorization_endpoint), end_session_endpoint = get_env(end_session_endpoint), - ssl_options = extract_ssl_options_as_list(Map) + ssl_options = extract_ssl_options_as_list(Map), + proxy_options = extract_proxy_options(get_env(proxy, [])) }. + +-spec extract_proxy_options(#{atom() => any()}|list()) -> proxy_options() | undefined. +extract_proxy_options(List) when is_list(List) -> + case {proplists:get_value(host, List, undefined), + proplists:get_value(port, List, 0)} of + {undefined, _} -> undefined; + {_, 0} -> undefined; + {H, P} -> + #proxy_options{ + host = H, + port = P, + username = proplists:get_value(username, List, undefined), + password = proplists:get_value(password, List, undefined) + } + end; +extract_proxy_options(Map) -> + case {maps:get(host, Map, undefined), maps:get(port, Map, 0)} of + {undefined, _} -> undefined; + {_, 0} -> undefined; + {H, P} -> + #proxy_options{ + host = H, + port = P, + username = maps:get(username, Map, undefined), + password = maps:get(password, Map, undefined) + } + end. -spec extract_ssl_options_as_list(#{atom() => any()}) -> proplists:proplist(). extract_ssl_options_as_list(Map) -> @@ -522,15 +620,36 @@ append_extra_parameters(Request, QueryList) -> Params -> Params ++ QueryList end. -get_ssl_options_if_any(OAuthProvider) -> - case OAuthProvider#oauth_provider.ssl_options of +map_ssl_options_to_httpc_option(SslOptions) -> + case SslOptions of undefined -> []; - Options -> [{ssl, Options}] + Options -> [{ssl, Options}] end. -get_timeout_of_default(Timeout) -> + +map_timeout_to_httpc_option(Timeout) -> case Timeout of undefined -> [{timeout, ?DEFAULT_HTTP_TIMEOUT}]; - Timeout -> [{timeout, Timeout}] + Timeout -> [{timeout, Timeout}] + end. + +map_proxy_to_httpc_option(ProxyOptions) -> + case ProxyOptions of + undefined -> []; + Proxy -> case {Proxy#proxy_options.host, Proxy#proxy_options.port} of + {_, 0} -> []; + {Host, Port} -> P = {{Host, Port},[]}, + [{proxy, P}] + end + end. + +map_proxy_auth_to_httpc_option(ProxyOptions) -> + case ProxyOptions of + undefined -> []; + Proxy -> case {Proxy#proxy_options.username, Proxy#proxy_options.password} of + {undefined, _} -> []; + {_, undefined} -> []; + {_, _} = Auth -> [{proxy_auth, Auth}] + end end. is_json(?CONTENT_JSON) -> true; @@ -543,10 +662,8 @@ is_json(_) -> false. decode_body(_, []) -> []; decode_body(?CONTENT_JSON, Body) -> case rabbit_json:try_decode(rabbit_data_coercion:to_binary(Body)) of - {ok, Value} -> - Value; - {error, _} = Error -> - Error + {ok, Value} -> Value; + {error, _} = Error -> Error end; decode_body(MimeType, Body) -> Items = string:split(MimeType, ";"), @@ -588,14 +705,14 @@ map_to_oauth_provider(PropList) when is_list(PropList) -> proplists:get_value(jwks_uri, PropList, undefined), ssl_options = extract_ssl_options_as_list(maps:from_list( - proplists:get_value(https, PropList, []))) + proplists:get_value(https, PropList, []))), + proxy_options = + extract_proxy_options(proplists:get_value(proxy, PropList, [])) }. map_to_access_token_response(Code, Reason, Headers, Body) -> case decode_body(proplists:get_value("content-type", Headers, ?CONTENT_JSON), Body) of - {error, {error, InternalError}} -> - {error, InternalError}; - {error, _} = Error -> - Error; + {error, {error, InternalError}} -> {error, InternalError}; + {error, _} = Error -> Error; Value -> case Code of 200 -> {ok, map_to_successful_access_token_response(Value)}; @@ -626,6 +743,18 @@ format_ssl_options(TlsOptions) -> proplists:get_value(cacertfile, TlsOptions), CaCertsCount])). +-spec format_proxy_options(proxy_options()|undefined) -> string(). +format_proxy_options(undefined) -> + lists:flatten(io_lib:format("{no proxy}", [])); + +format_proxy_options(ProxyOptions) -> + lists:flatten(io_lib:format("{host: ~p, port: ~p, username: ~p, " ++ + "password: ~p }", [ + ProxyOptions#proxy_options.host, + ProxyOptions#proxy_options.port, + ProxyOptions#proxy_options.username, + ProxyOptions#proxy_options.password])). + format_oauth_provider_id(root) -> ""; format_oauth_provider_id(Id) -> binary_to_list(Id). @@ -634,7 +763,7 @@ format_oauth_provider(OAuthProvider) -> lists:flatten(io_lib:format("{id: ~p, issuer: ~p, discovery_endpoint: ~p, " ++ " token_endpoint: ~p, " ++ "authorization_endpoint: ~p, end_session_endpoint: ~p, " ++ - "jwks_uri: ~p, ssl_options: ~p }", [ + "jwks_uri: ~p, ssl_options: ~p, proxy_options: ~p}", [ format_oauth_provider_id(OAuthProvider#oauth_provider.id), OAuthProvider#oauth_provider.issuer, OAuthProvider#oauth_provider.discovery_endpoint, @@ -642,7 +771,8 @@ format_oauth_provider(OAuthProvider) -> OAuthProvider#oauth_provider.authorization_endpoint, OAuthProvider#oauth_provider.end_session_endpoint, OAuthProvider#oauth_provider.jwks_uri, - format_ssl_options(OAuthProvider#oauth_provider.ssl_options)])). + format_ssl_options(OAuthProvider#oauth_provider.ssl_options), + format_proxy_options(OAuthProvider#oauth_provider.proxy_options)])). get_env(Par) -> application:get_env(rabbitmq_auth_backend_oauth2, Par, undefined). diff --git a/deps/oauth2_client/test/system_SUITE.erl b/deps/oauth2_client/test/system_SUITE.erl index 67e4abf1ea..17379fbd68 100644 --- a/deps/oauth2_client/test/system_SUITE.erl +++ b/deps/oauth2_client/test/system_SUITE.erl @@ -322,13 +322,25 @@ build_openid_discovery_endpoint(Issuer, Path) -> get_openid_configuration(Config) -> ExpectedOAuthProvider = ?config(oauth_provider, Config), - SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}], {ok, ActualOpenId} = oauth2_client:get_openid_configuration( - build_openid_discovery_endpoint(build_issuer("https")), - SslOptions), + ensure_discovery_endpoint(ExpectedOAuthProvider)), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), assertOpenIdConfiguration(ExpectedOpenId, ActualOpenId). +ensure_issuer(OAuthProvider, IssuerURL) -> + OAuthProvider#oauth_provider{ + issuer = IssuerURL + }. +ensure_discovery_endpoint(OAuthProvider) -> + OAuthProvider#oauth_provider{ + discovery_endpoint = build_openid_discovery_endpoint(OAuthProvider#oauth_provider.issuer) + }. +ensure_discovery_endpoint(OAuthProvider, DiscoveryEndpointPath) -> + OAuthProvider#oauth_provider{ + discovery_endpoint = build_openid_discovery_endpoint( + OAuthProvider#oauth_provider.issuer, + DiscoveryEndpointPath) + }. map_oauth_provider_to_openid_configuration(OAuthProvider) -> #openid_configuration{ issuer = OAuthProvider#oauth_provider.issuer, @@ -344,35 +356,30 @@ get_openid_configuration_returns_partial_payload(Config) -> token_endpoint = ExpectedOAuthProvider0#oauth_provider.token_endpoint, jwks_uri = ExpectedOAuthProvider0#oauth_provider.jwks_uri}, - SslOptions = [{ssl, ExpectedOAuthProvider0#oauth_provider.ssl_options}], {ok, Actual} = oauth2_client:get_openid_configuration( - build_openid_discovery_endpoint(build_issuer("https")), - SslOptions), + ensure_discovery_endpoint(ExpectedOAuthProvider0)), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), assertOpenIdConfiguration(ExpectedOpenId, Actual). get_openid_configuration_using_path(Config) -> ExpectedOAuthProvider = ?config(oauth_provider, Config), - SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}], - {ok, Actual} = oauth2_client:get_openid_configuration( - build_openid_discovery_endpoint(build_issuer("https", ?ISSUER_PATH)), - SslOptions), + {ok, Actual} = oauth2_client:get_openid_configuration( + ensure_discovery_endpoint( + ensure_issuer(ExpectedOAuthProvider, build_issuer("https", ?ISSUER_PATH)))), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), assertOpenIdConfiguration(ExpectedOpenId,Actual). get_openid_configuration_using_path_and_custom_endpoint(Config) -> - ExpectedOAuthProvider = ?config(oauth_provider, Config), - SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}], + ExpectedOAuthProvider = ?config(oauth_provider, Config), {ok, Actual} = oauth2_client:get_openid_configuration( - build_openid_discovery_endpoint(build_issuer("https", ?ISSUER_PATH), - ?CUSTOM_OPENID_CONFIGURATION_ENDPOINT), SslOptions), + ensure_discovery_endpoint( + ensure_issuer(ExpectedOAuthProvider, build_issuer("https", ?ISSUER_PATH)), + ?CUSTOM_OPENID_CONFIGURATION_ENDPOINT)), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), assertOpenIdConfiguration(ExpectedOpenId, Actual). get_openid_configuration_using_custom_endpoint(Config) -> ExpectedOAuthProvider = ?config(oauth_provider, Config), - SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}], {ok, Actual} = oauth2_client:get_openid_configuration( - build_openid_discovery_endpoint(build_issuer("https"), - ?CUSTOM_OPENID_CONFIGURATION_ENDPOINT), SslOptions), + ensure_discovery_endpoint(ExpectedOAuthProvider, ?CUSTOM_OPENID_CONFIGURATION_ENDPOINT)), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), assertOpenIdConfiguration(ExpectedOpenId, Actual). diff --git a/deps/rabbitmq_auth_backend_oauth2/priv/schema/rabbitmq_auth_backend_oauth2.schema b/deps/rabbitmq_auth_backend_oauth2/priv/schema/rabbitmq_auth_backend_oauth2.schema index 222b1dedfb..2d67d88c03 100644 --- a/deps/rabbitmq_auth_backend_oauth2/priv/schema/rabbitmq_auth_backend_oauth2.schema +++ b/deps/rabbitmq_auth_backend_oauth2/priv/schema/rabbitmq_auth_backend_oauth2.schema @@ -220,6 +220,26 @@ rabbit_oauth2_schema:translate_oauth_providers(Conf) end}. +{mapping, + "auth_oauth2.proxy.host", + "rabbitmq_auth_backend_oauth2.proxy.host", + [{datatype, string}]}. + +{mapping, + "auth_oauth2.proxy.port", + "rabbitmq_auth_backend_oauth2.proxy.port", + [{datatype, integer}]}. + +{mapping, + "auth_oauth2.proxy.username", + "rabbitmq_auth_backend_oauth2.proxy.username", + [{datatype, string}]}. + +{mapping, + "auth_oauth2.proxy.password", + "rabbitmq_auth_backend_oauth2.proxy.password", + [{datatype, string}]}. + {mapping, "auth_oauth2.https.peer_verification", "rabbitmq_auth_backend_oauth2.key_config.peer_verification", @@ -322,6 +342,26 @@ "rabbitmq_auth_backend_oauth2.oauth_providers", [{datatype, integer}]}. +{mapping, + "auth_oauth2.oauth_providers.$name.proxy.host", + "rabbitmq_auth_backend_oauth2.oauth_providers", + [{datatype, string}]}. + +{mapping, + "auth_oauth2.oauth_providers.$name.proxy.port", + "rabbitmq_auth_backend_oauth2.oauth_providers", + [{datatype, integer}]}. + +{mapping, + "auth_oauth2.oauth_providers.$name.proxy.username", + "rabbitmq_auth_backend_oauth2.oauth_providers", + [{datatype, string}]}. + +{mapping, + "auth_oauth2.oauth_providers.$name.proxy.password", + "rabbitmq_auth_backend_oauth2.oauth_providers", + [{datatype, string}]}. + {mapping, "auth_oauth2.oauth_providers.$name.https.hostname_verification", "rabbitmq_auth_backend_oauth2.oauth_providers", diff --git a/deps/rabbitmq_auth_backend_oauth2/src/rabbit_oauth2_schema.erl b/deps/rabbitmq_auth_backend_oauth2/src/rabbit_oauth2_schema.erl index eb34e4b341..57335ca715 100644 --- a/deps/rabbitmq_auth_backend_oauth2/src/rabbit_oauth2_schema.erl +++ b/deps/rabbitmq_auth_backend_oauth2/src/rabbit_oauth2_schema.erl @@ -158,6 +158,7 @@ translate_oauth_providers(Conf) -> Settings), extract_oauth_providers_algorithm(Settings), extract_oauth_providers_https(Settings), + extract_oauth_providers_proxy(Settings), extract_oauth_providers_signing_keys(Settings) ]). @@ -264,6 +265,15 @@ mapOauthProviderProperty({Key, Value}) -> _ -> Value end}. +extract_oauth_providers_proxy(Settings) -> + ExtractProviderNameFun = fun extract_key_as_binary/1, + AttributesPerProvider = [{Name, mapProxyProperty({list_to_atom(Key), V})} || + {[?AUTH_OAUTH2, ?OAUTH_PROVIDERS, Name, "proxy", Key], V} <- Settings ], + + maps:map(fun(_K,V)-> [{proxy, V}] end, + maps:groups_from_list(ExtractProviderNameFun, fun({_, V}) -> V end, + AttributesPerProvider)). + extract_oauth_providers_https(Settings) -> ExtractProviderNameFun = fun extract_key_as_binary/1, @@ -280,6 +290,9 @@ mapHttpProperty({Key, Value}) -> _ -> Value end}. +mapProxyProperty({Key, Value}) -> + {Key, Value}. + extract_oauth_providers_algorithm(Settings) -> KeyFun = fun extract_key_as_binary/1, diff --git a/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwks.erl b/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwks.erl deleted file mode 100644 index fd6c0b1cfc..0000000000 --- a/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwks.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(uaa_jwks). --export([get/2]). - --spec get(uri_string:uri_string(), list()) -> {ok, term()} | {error, term()}. -get(JwksUrl, SslOptions) -> - Options = [{timeout, 60000}] ++ [{ssl, SslOptions}], - httpc:request(get, {JwksUrl, []}, Options, []). diff --git a/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwt.erl b/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwt.erl index d95e74ee5c..2e1ee024dc 100644 --- a/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwt.erl +++ b/deps/rabbitmq_auth_backend_oauth2/src/uaa_jwt.erl @@ -42,11 +42,10 @@ add_signing_key(KeyId, Type, Value) -> end. -spec update_jwks_signing_keys(oauth_provider()) -> ok | {error, term()}. -update_jwks_signing_keys(#oauth_provider{id = Id, jwks_uri = JwksUrl, - ssl_options = SslOptions}) -> - rabbit_log:debug("Downloading signing keys from ~tp (TLS options: ~p)", - [JwksUrl, format_ssl_options(SslOptions)]), - case uaa_jwks:get(JwksUrl, SslOptions) of +update_jwks_signing_keys(#oauth_provider{id = Id} = OAuthProvider) -> + rabbit_log:debug("Downloading signing keys from OauthProvider: ~tp", + [Id]), + case oauth2_client:get_jwks(OAuthProvider) of {ok, {_, _, JwksBody}} -> KeyList = maps:get(<<"keys">>, jose:decode(erlang:iolist_to_binary(JwksBody)), []), diff --git a/deps/rabbitmq_auth_backend_oauth2/test/config_schema_SUITE_data/rabbitmq_auth_backend_oauth2.snippets b/deps/rabbitmq_auth_backend_oauth2/test/config_schema_SUITE_data/rabbitmq_auth_backend_oauth2.snippets index 7b6b148b59..8f3ebde2d3 100644 --- a/deps/rabbitmq_auth_backend_oauth2/test/config_schema_SUITE_data/rabbitmq_auth_backend_oauth2.snippets +++ b/deps/rabbitmq_auth_backend_oauth2/test/config_schema_SUITE_data/rabbitmq_auth_backend_oauth2.snippets @@ -316,5 +316,37 @@ } ]} ], [] + }, + {proxy, + "auth_oauth2.proxy.host = localproxy + auth_oauth2.proxy.port = 8080 + auth_oauth2.proxy.username = proxyuser + auth_oauth2.proxy.password = proxypwd + auth_oauth2.oauth_providers.keycloak.proxy.host = localproxy2 + auth_oauth2.oauth_providers.keycloak.proxy.port = 8080 + auth_oauth2.oauth_providers.keycloak.proxy.username = proxyuser2 + auth_oauth2.oauth_providers.keycloak.proxy.password = proxypwd2", + [ + {rabbitmq_auth_backend_oauth2, [ + {proxy, [ + {host, "localproxy"}, + {password, "proxypwd"}, + {port, 8080}, + {username, "proxyuser"} + ]}, + {oauth_providers, + #{ + <<"keycloak">> => [ + {proxy, [ + {password, "proxypwd2"}, + {username, "proxyuser2"}, + {port, 8080}, + {host, "localproxy2"} + ]} + ] + } + } + ]} + ], [] } ]. diff --git a/deps/rabbitmq_auth_backend_oauth2/test/rabbit_oauth2_provider_SUITE.erl b/deps/rabbitmq_auth_backend_oauth2/test/rabbit_oauth2_provider_SUITE.erl index ac3ca2b67e..81bdeebe73 100644 --- a/deps/rabbitmq_auth_backend_oauth2/test/rabbit_oauth2_provider_SUITE.erl +++ b/deps/rabbitmq_auth_backend_oauth2/test/rabbit_oauth2_provider_SUITE.erl @@ -65,6 +65,9 @@ verify_provider() -> [ ]}, {oauth_provider_with_issuer, [], [ get_oauth_provider_has_jwks_uri + ]} + ,{oauth_provider_with_proxy, [], [ + get_oauth_provider_has_proxy ]} ]. @@ -149,6 +152,27 @@ init_per_group(with_resource_server_id, Config) -> set_env(resource_server_id, ?RABBITMQ), Config; +init_per_group(oauth_provider_with_proxy, Config) -> + Proxy = [ + {host, "idp"}, + {port, 8080}, + {username, <<"user1">>}, + {password, <<"pwd1">>} + ], + case ?config(oauth_provider_id, Config) of + root -> + set_env(proxy, Proxy); + Id -> + OAuthProviders = get_env(oauth_providers, #{}), + OAuthProvider = maps:get(Id, OAuthProviders, []), + set_env(oauth_providers, maps:put(Id, + [{proxy, Proxy}] ++ OAuthProvider, OAuthProviders)) + end, + [{proxy_hostname, "idp"}, + {proxy_port, 8080}, + {proxy_username, <<"user1">>}, + {proxy_password, <<"pwd1">>}] ++ Config; + init_per_group(with_algorithms, Config) -> KeyConfig = get_env(key_config, []), set_env(key_config, KeyConfig ++ [{algorithms, [<<"HS256">>, <<"RS256">>]}]), @@ -190,6 +214,16 @@ init_per_group(_any, Config) -> end_per_group(with_rabbitmq_node, Config) -> rabbit_ct_helpers:run_steps(Config, rabbit_ct_broker_helpers:teardown_steps()); +end_per_group(oauth_provider_with_proxy, Config) -> + case ?config(oauth_provider_id, Config) of + root -> + unset_env(proxy); + Id -> + unset_oauth_provider_properties(Id, + [host, port, username, password]) + end, + Config; + end_per_group(with_root_static_signing_keys, Config) -> KeyConfig = call_get_env(Config, key_config, []), call_set_env(Config, key_config, KeyConfig), @@ -407,10 +441,22 @@ get_oauth_provider_with_jwks_uri_returns_error(Config) -> get_oauth_provider_has_jwks_uri(Config) -> {ok, OAuthProvider} = get_oauth_provider( - ?config(oauth_provider_id, Config), [jwks_uri]), - ct:log("OAuthProvider: ~p", [OAuthProvider]), + ?config(oauth_provider_id, Config), [jwks_uri]), ?assertEqual(?config(jwks_uri, Config), OAuthProvider#oauth_provider.jwks_uri). +get_oauth_provider_has_proxy(Config) -> + {ok, OAuthProvider} = get_oauth_provider( + ?config(oauth_provider_id, Config), [jwks_uri]), + + ?assertEqual(?config(proxy_port, Config), + OAuthProvider#oauth_provider.proxy_options#proxy_options.port), + ?assertEqual(?config(proxy_hostname, Config), + OAuthProvider#oauth_provider.proxy_options#proxy_options.host), + ?assertEqual(?config(proxy_username, Config), + OAuthProvider#oauth_provider.proxy_options#proxy_options.username), + ?assertEqual(?config(proxy_password, Config), + OAuthProvider#oauth_provider.proxy_options#proxy_options.password). + %% ---- Utility functions diff --git a/selenium/bin/components/devkeycloak-proxy b/selenium/bin/components/devkeycloak-proxy new file mode 100644 index 0000000000..65b15f419f --- /dev/null +++ b/selenium/bin/components/devkeycloak-proxy @@ -0,0 +1,46 @@ + +HTTPD_DOCKER_IMAGE=httpd:latest + +ensure_devkeycloak-proxy() { + if docker ps | grep devkeycloak-proxy &> /dev/null; then + print "devkeycloak-proxy already running ..." + else + start_devkeycloak-proxy + fi +} +init_devkeycloak-proxy() { + HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/devkeycloak-proxy + PROXY_HOSTNAME=devkeycloak-proxy + PROXY_PORT=9092 + + print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}" + print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}" + print "> PROXY_PORT: ${PROXY_PORT}" + +} + +start_devkeycloak-proxy() { + begin "Starting devkeycloak-proxy ..." + + init_devkeycloak-proxy + kill_container_if_exist devkeycloak-proxy + + MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd + + mkdir -p $MOUNT_HTTPD_CONFIG_DIR + ${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf + print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf" + cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR + + docker run \ + --detach \ + --name devkeycloak-proxy \ + --net ${DOCKER_NETWORK} \ + --publish 9092:9092 \ + --mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \ + ${HTTPD_DOCKER_IMAGE} + + #wait_for_url $OAUTH_PROVIDER_URL ${FORWARD_PROXY_URL} + wait_for_message devkeycloak-proxy "initializing worker proxy:forward local" + end "devkeycloak-proxy is ready" +} diff --git a/selenium/bin/components/forward-proxy b/selenium/bin/components/forward-proxy new file mode 100644 index 0000000000..ccc21a756a --- /dev/null +++ b/selenium/bin/components/forward-proxy @@ -0,0 +1,47 @@ + +HTTPD_DOCKER_IMAGE=httpd:latest + +ensure_forward-proxy() { + if docker ps | grep forward-proxy &> /dev/null; then + print "forward-proxy already running ..." + else + start_forward-proxy + fi +} +init_forward-proxy() { + HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/forward-proxy + PROXY_HOSTNAME=forward-proxy + PROXY_PORT=9092 + + print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}" + print "> OAUTH_PROVIDER_URL: ${OAUTH_PROVIDER_URL}" + print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}" + print "> PROXY_PORT: ${PROXY_PORT}" + +} + +start_forward-proxy() { + begin "Starting forward-proxy ..." + + init_forward-proxy + kill_container_if_exist forward-proxy + + MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd + + mkdir -p $MOUNT_HTTPD_CONFIG_DIR + ${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf + print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf" + cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR + + docker run \ + --detach \ + --name forward-proxy \ + --net ${DOCKER_NETWORK} \ + --publish 9092:9092 \ + --mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \ + ${HTTPD_DOCKER_IMAGE} + + #wait_for_url $OAUTH_PROVIDER_URL ${FORWARD_PROXY_URL} + wait_for_message forward-proxy "initializing worker proxy:forward local" + end "forward-proxy is ready" +} diff --git a/selenium/bin/components/keycloak b/selenium/bin/components/keycloak index f77df9f6f1..01adc577f6 100644 --- a/selenium/bin/components/keycloak +++ b/selenium/bin/components/keycloak @@ -12,8 +12,7 @@ ensure_keycloak() { init_keycloak() { KEYCLOAK_CONFIG_PATH=${KEYCLOAK_CONFIG_PATH:-oauth/keycloak} KEYCLOAK_CONFIG_DIR=$(realpath ${TEST_DIR}/${KEYCLOAK_CONFIG_PATH}) - KEYCLOAK_URL=${OAUTH_PROVIDER_URL} - + print "> KEYCLOAK_CONFIG_DIR: ${KEYCLOAK_CONFIG_DIR}" print "> KEYCLOAK_URL: ${KEYCLOAK_URL}" print "> KEYCLOAK_DOCKER_IMAGE: ${KEYCLOAK_DOCKER_IMAGE}" @@ -42,8 +41,9 @@ start_keycloak() { --publish 8443:8443 \ --env KEYCLOAK_ADMIN=admin \ --env KEYCLOAK_ADMIN_PASSWORD=admin \ + --env QUARKUS_HTTP_ACCESS_LOG_ENABLED=true \ -v ${MOUNT_KEYCLOAK_CONF_DIR}:/opt/keycloak/data/import/ \ - ${KEYCLOAK_DOCKER_IMAGE} start-dev --import-realm \ + ${KEYCLOAK_DOCKER_IMAGE} start-dev --import-realm --log-level=INFO \ --https-certificate-file=/opt/keycloak/data/import/server_keycloak_certificate.pem \ --https-certificate-key-file=/opt/keycloak/data/import/server_keycloak_key.pem diff --git a/selenium/bin/components/prodkeycloak-proxy b/selenium/bin/components/prodkeycloak-proxy new file mode 100644 index 0000000000..f358a38454 --- /dev/null +++ b/selenium/bin/components/prodkeycloak-proxy @@ -0,0 +1,45 @@ + +HTTPD_DOCKER_IMAGE=httpd:latest + +ensure_prodkeycloak-proxy() { + if docker ps | grep prodkeycloak-proxy &> /dev/null; then + print "prodkeycloak-proxy already running ..." + else + start_prodkeycloak-proxy + fi +} +init_prodkeycloak-proxy() { + HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/prodkeycloak-proxy + PROXY_HOSTNAME=prodkeycloak-proxy + PROXY_PORT=9091 + + print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}" + print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}" + print "> PROXY_PORT: ${PROXY_PORT}" + +} + +start_prodkeycloak-proxy() { + begin "Starting prodkeycloak-proxy ..." + + init_prodkeycloak-proxy + kill_container_if_exist prodkeycloak-proxy + + MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd + + mkdir -p $MOUNT_HTTPD_CONFIG_DIR + ${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf + print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf" + cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR + + docker run \ + --detach \ + --name prodkeycloak-proxy \ + --net ${DOCKER_NETWORK} \ + --publish 9091:9091 \ + --mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \ + ${HTTPD_DOCKER_IMAGE} + + wait_for_message prodkeycloak-proxy "initializing worker proxy:forward local" + end "prodkeycloak-proxy is ready" +} diff --git a/selenium/bin/suite_template b/selenium/bin/suite_template index 33566190cb..d5aee0a9ee 100644 --- a/selenium/bin/suite_template +++ b/selenium/bin/suite_template @@ -214,20 +214,37 @@ wait_for_oidc_endpoint_docker() { calculate_rabbitmq_url() { echo "${RABBITMQ_SCHEME:-http}://$1${PUBLIC_RABBITMQ_PATH:-$RABBITMQ_PATH}" } - +calculate_forward_proxy_url() { + PROXIED_URL=$1 + PROXY_HOSTNAME=$2 + PROXY_PORT=$3 + SCHEME=$(echo "$PROXIED_URL" | cut -d: -f1) + PATH=$(echo "$PROXIED_URL" | cut -d/ -f4-) + echo "$SCHEME://$PROXY_HOSTNAME:$PROXY_PORT/$PATH" +} wait_for_url() { - BASE_URL=$1 + BASE_URL=$1 if [[ $BASE_URL == *"localhost"** ]]; then - wait_for_url_local $BASE_URL + wait_for_url_local $@ else - wait_for_url_docker $BASE_URL + wait_for_url_docker $@ fi } wait_for_url_local() { url=$1 + proxy=${2:-none} + proxy_user=${3:-none} + proxy_pass=$4 + curl_args="-L -f -v" max_retry=10 counter=0 - until (curl -L -f -v $url >/dev/null 2>&1) + if [[ "$proxy" != "none" && "$proxy" != "" ]]; then + curl_args="--proxy ${proxy} ${curl_args}" + fi + if [[ "$proxy_user" != "none" && "$proxy_user" != "" ]]; then + curl_args="--proxy-user ${proxy_user}:${proxy_pass} ${curl_args}" + fi + until (curl $curl_args $url >/dev/null 2>&1) do print "Waiting for $url to start (local)" sleep 5 @@ -240,7 +257,14 @@ wait_for_url_docker() { url=$1 max_retry=10 counter=0 - until (docker run --net ${DOCKER_NETWORK} --rm curlimages/curl:7.85.0 -L -f -v $url >/dev/null 2>&1) + curl_args="-L -f -v" + if [[ "$proxy" != "none" && "$proxy" != "" ]]; then + curl_args="--proxy ${proxy} ${curl_args}" + fi + if [[ "$proxy_user" != "none" && "$proxy_user" != "" ]]; then + curl_args="--proxy-user ${proxy_user}:${proxy_pass} ${curl_args}" + fi + until (docker run --net ${DOCKER_NETWORK} --rm curlimages/curl:7.85.0 $curl_args $url >/dev/null 2>&1) do print "Waiting for $url to start (docker)" sleep 5 @@ -373,7 +397,8 @@ profiles_with_local_or_docker() { generate_env_file() { begin "Generating env file ..." mkdir -p $CONF_DIR - ${BIN_DIR}/gen-env-file $TEST_CONFIG_DIR $ENV_FILE + ${BIN_DIR}/gen-env-file $TEST_CONFIG_DIR ${ENV_FILE}.tmp + grep -v '^#' ${ENV_FILE}.tmp > $ENV_FILE source $ENV_FILE end "Finished generating env file." } @@ -541,7 +566,7 @@ run_on_docker_with() { build_mocha_image start_selenium - trap teardown_components EXIT + trap "teardown_components" EXIT start_components test @@ -622,7 +647,6 @@ start_components() { $start done } - teardown_components() { skip_rabbitmq=${1:-false} diff --git a/selenium/full-suite-management-ui b/selenium/full-suite-management-ui index 16ae3233eb..ac0a8a8c90 100644 --- a/selenium/full-suite-management-ui +++ b/selenium/full-suite-management-ui @@ -5,12 +5,14 @@ authnz-mgt/multi-oauth-with-basic-auth-when-idps-down.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.sh +authnz-mgt/multi-oauth-via-proxies.sh authnz-mgt/oauth-and-basic-auth.sh authnz-mgt/oauth-idp-initiated-with-uaa-and-prefix-via-proxy.sh authnz-mgt/oauth-idp-initiated-with-uaa-and-prefix.sh authnz-mgt/oauth-idp-initiated-with-uaa-via-proxy.sh authnz-mgt/oauth-idp-initiated-with-uaa.sh authnz-mgt/oauth-with-keycloak.sh +authnz-mgt/oauth-with-keycloak-via-forward-proxy.sh authnz-mgt/oauth-with-keycloak-with-verify-none.sh authnz-mgt/oauth-with-uaa-down-but-with-basic-auth.sh authnz-mgt/oauth-with-uaa-down.sh diff --git a/selenium/suites/authnz-mgt/multi-oauth-via-proxies.sh b/selenium/suites/authnz-mgt/multi-oauth-via-proxies.sh new file mode 100755 index 0000000000..1065803f53 --- /dev/null +++ b/selenium/suites/authnz-mgt/multi-oauth-via-proxies.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +TEST_CASES_PATH=/multi-oauth/without-basic-auth +TEST_CONFIG_PATH=/multi-oauth +PROFILES="devkeycloak prodkeycloak with-resource-label with-resource-scopes tls devkeycloak-proxy prodkeycloak-proxy" + +source $SCRIPT/../../bin/suite_template $@ +runWith devkeycloak prodkeycloak devkeycloak-proxy prodkeycloak-proxy diff --git a/selenium/suites/authnz-mgt/oauth-with-keycloak-via-forward-proxy.sh b/selenium/suites/authnz-mgt/oauth-with-keycloak-via-forward-proxy.sh new file mode 100755 index 0000000000..71bc4aece8 --- /dev/null +++ b/selenium/suites/authnz-mgt/oauth-with-keycloak-via-forward-proxy.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +TEST_CASES_PATH=/oauth/with-sp-initiated +TEST_CONFIG_PATH=/oauth +PROFILES="forward-proxy keycloak forward-proxy-oauth-provider keycloak-mgt-oauth-provider tls" + +source $SCRIPT/../../bin/suite_template $@ +runWith keycloak forward-proxy diff --git a/selenium/test/authnz-msg-protocols/amqp10.js b/selenium/test/authnz-msg-protocols/amqp10.js index 163dec0020..073649eace 100644 --- a/selenium/test/authnz-msg-protocols/amqp10.js +++ b/selenium/test/authnz-msg-protocols/amqp10.js @@ -3,16 +3,12 @@ const { tokenFor, openIdConfiguration } = require('../utils') const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend') const { open: openAmqp, once: onceAmqp, on: onAmqp, close: closeAmqp } = require('../amqp') -var receivedAmqpMessageCount = 0 var untilConnectionEstablished = new Promise((resolve, reject) => { onAmqp('connection_open', function(context) { resolve() }) }) -onAmqp('message', function (context) { - receivedAmqpMessageCount++ -}) onceAmqp('sendable', function (context) { context.sender.send({body:'first message'}) }) @@ -52,16 +48,21 @@ describe('Having AMQP 1.0 protocol enabled and the following auth_backends: ' + }) it('can open an AMQP 1.0 connection', async function () { + var untilFirstMessageReceived = new Promise((resolve, reject) => { + onAmqp('message', function(context) { + resolve() + }) + }) amqp = openAmqp() await untilConnectionEstablished - var untilMessageReceived = new Promise((resolve, reject) => { + await untilFirstMessageReceived + var untilSecondMessageReceived = new Promise((resolve, reject) => { onAmqp('message', function(context) { resolve() }) }) amqp.sender.send({body:'second message'}) - await untilMessageReceived - assert.equal(2, receivedAmqpMessageCount) + await untilSecondMessageReceived }) after(function () { diff --git a/selenium/test/basic-auth/ac-management.js b/selenium/test/basic-auth/ac-management.js index a07484d0f0..d2baa16cd6 100644 --- a/selenium/test/basic-auth/ac-management.js +++ b/selenium/test/basic-auth/ac-management.js @@ -27,35 +27,32 @@ describe('management user with vhosts permissions', function () { it('can access overview tab', async function () { await overview.clickOnOverviewTab() await overview.waitForOverviewTab() - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('can access connections tab', async function () { await overview.clickOnConnectionsTab() await overview.waitForConnectionsTab() - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('can access channels tab', async function () { await overview.clickOnChannelsTab() await overview.waitForChannelsTab() - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('can access exchanges tab', async function () { await overview.clickOnExchangesTab() await overview.waitForExchangesTab() - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('can access queues and streams tab', async function () { await overview.clickOnQueuesTab() await overview.waitForQueuesTab() - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('can access limited options in admin tab', async function () { - console.log("before clickOnAdminTab") await overview.clickOnAdminTab() - console.log("before waitForAdminTab") await overview.waitForAdminTab() - console.log("after waitForAdminTab") - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) }) it('cannot add/update user limits', async function () { diff --git a/selenium/test/basic-auth/unauthorized.js b/selenium/test/basic-auth/unauthorized.js index ceae65d8b1..7d9269613f 100644 --- a/selenium/test/basic-auth/unauthorized.js +++ b/selenium/test/basic-auth/unauthorized.js @@ -19,7 +19,6 @@ describe('An user without management tag', function () { overview = new OverviewPage(driver) captureScreen = captureScreensFor(driver, __filename) - //assert.ok(!await login.isPopupWarningDisplayed()) await login.login('rabbit_no_management', 'guest') }) @@ -45,8 +44,8 @@ describe('An user without management tag', function () { it('should close popup warning', async function(){ await delay(1000) - const visible = await login.isPopupWarningDisplayed() - assert.ok(!visible) + const visible = + assert.ok(await login.isPopupWarningNotDisplayed()) }) }) diff --git a/selenium/test/multi-oauth/devkeycloak-proxy/.htpasswd b/selenium/test/multi-oauth/devkeycloak-proxy/.htpasswd new file mode 100644 index 0000000000..1a63893732 --- /dev/null +++ b/selenium/test/multi-oauth/devkeycloak-proxy/.htpasswd @@ -0,0 +1 @@ +guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA= diff --git a/selenium/test/multi-oauth/devkeycloak-proxy/httpd.conf b/selenium/test/multi-oauth/devkeycloak-proxy/httpd.conf new file mode 100644 index 0000000000..9d78f4b9e8 --- /dev/null +++ b/selenium/test/multi-oauth/devkeycloak-proxy/httpd.conf @@ -0,0 +1,147 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so "logs/access_log" +# with ServerRoot set to "/usr/local/apache2" will be interpreted by the +# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" +# will be interpreted as '/logs/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/usr/local/apache2" + +# +# Mutex: Allows you to set the mutex mechanism and mutex file directory +# for individual mutexes, or change the global defaults +# +# Uncomment and change the directory if mutexes are file-based and the default +# mutex file directory is not on a local disk or is not appropriate for some +# other reason. +# +# Mutex default:logs + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 9092 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# + +LoadModule mpm_event_module modules/mod_mpm_event.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule proxy_module modules/mod_proxy.so +LoadModule proxy_connect_module modules/mod_proxy_connect.so +LoadModule proxy_http_module modules/mod_proxy_http.so +LoadModule ssl_module modules/mod_ssl.so +LoadModule unixd_module modules/mod_unixd.so + + +User www-data +Group www-data + + + +ServerAdmin you@example.com + +ServerName devkeycloak-proxy + +ErrorLog /proc/self/fd/2 + +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + CustomLog logs/access_log common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + #CustomLog "logs/access_log" combined + + + + ProxyRequests On + ProxyVia On + + Allow from all + + + + + + AllowCONNECT 8442 + + ProxyRequests On + ProxyVia On + LogLevel debug + ErrorLog /dev/stderr + CustomLog /dev/stdout combined + + + Allow from all + + + + diff --git a/selenium/test/multi-oauth/env.docker.devkeycloak-proxy b/selenium/test/multi-oauth/env.docker.devkeycloak-proxy new file mode 100644 index 0000000000..23532304aa --- /dev/null +++ b/selenium/test/multi-oauth/env.docker.devkeycloak-proxy @@ -0,0 +1,2 @@ +export DEVKEYCLOAK_PROXY_HOST=devkeycloak-proxy +export DEVKEYCLOAK_PROXY_PORT=9092 diff --git a/selenium/test/multi-oauth/env.docker.prodkeycloak-proxy b/selenium/test/multi-oauth/env.docker.prodkeycloak-proxy new file mode 100644 index 0000000000..410b2e15e9 --- /dev/null +++ b/selenium/test/multi-oauth/env.docker.prodkeycloak-proxy @@ -0,0 +1,4 @@ +export PRODKEYCLOAK_PROXY_HOST=prodkeycloak-proxy +export PRODKEYCLOAK_PROXY_PORT=9091 +export PRODKEYCLOAK_PROXY_USERNAME=guest +export PRODKEYCLOAK_PROXY_PASSWORD=guest diff --git a/selenium/test/multi-oauth/env.local.devkeycloak-proxy b/selenium/test/multi-oauth/env.local.devkeycloak-proxy new file mode 100644 index 0000000000..23532304aa --- /dev/null +++ b/selenium/test/multi-oauth/env.local.devkeycloak-proxy @@ -0,0 +1,2 @@ +export DEVKEYCLOAK_PROXY_HOST=devkeycloak-proxy +export DEVKEYCLOAK_PROXY_PORT=9092 diff --git a/selenium/test/multi-oauth/env.local.prodkeycloak-proxy b/selenium/test/multi-oauth/env.local.prodkeycloak-proxy new file mode 100644 index 0000000000..410b2e15e9 --- /dev/null +++ b/selenium/test/multi-oauth/env.local.prodkeycloak-proxy @@ -0,0 +1,4 @@ +export PRODKEYCLOAK_PROXY_HOST=prodkeycloak-proxy +export PRODKEYCLOAK_PROXY_PORT=9091 +export PRODKEYCLOAK_PROXY_USERNAME=guest +export PRODKEYCLOAK_PROXY_PASSWORD=guest diff --git a/selenium/test/multi-oauth/prodkeycloak-proxy/.htpasswd b/selenium/test/multi-oauth/prodkeycloak-proxy/.htpasswd new file mode 100644 index 0000000000..1a63893732 --- /dev/null +++ b/selenium/test/multi-oauth/prodkeycloak-proxy/.htpasswd @@ -0,0 +1 @@ +guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA= diff --git a/selenium/test/multi-oauth/prodkeycloak-proxy/httpd.conf b/selenium/test/multi-oauth/prodkeycloak-proxy/httpd.conf new file mode 100644 index 0000000000..514689a934 --- /dev/null +++ b/selenium/test/multi-oauth/prodkeycloak-proxy/httpd.conf @@ -0,0 +1,151 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so "logs/access_log" +# with ServerRoot set to "/usr/local/apache2" will be interpreted by the +# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" +# will be interpreted as '/logs/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/usr/local/apache2" + +# +# Mutex: Allows you to set the mutex mechanism and mutex file directory +# for individual mutexes, or change the global defaults +# +# Uncomment and change the directory if mutexes are file-based and the default +# mutex file directory is not on a local disk or is not appropriate for some +# other reason. +# +# Mutex default:logs + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 9091 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# + +LoadModule mpm_event_module modules/mod_mpm_event.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule proxy_module modules/mod_proxy.so +LoadModule proxy_connect_module modules/mod_proxy_connect.so +LoadModule proxy_http_module modules/mod_proxy_http.so +LoadModule ssl_module modules/mod_ssl.so +LoadModule unixd_module modules/mod_unixd.so + + +User www-data +Group www-data + + + +ServerAdmin you@example.com + +ServerName prodkeycloak-proxy + +ErrorLog /proc/self/fd/2 + +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + CustomLog logs/access_log common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + #CustomLog "logs/access_log" combined + + + + ProxyRequests On + ProxyVia On + + Allow from all + + + + + + AllowCONNECT 8443 + + ProxyRequests On + ProxyVia On + LogLevel debug + ErrorLog /dev/stderr + CustomLog /dev/stdout combined + + + Allow from all + AuthType Basic + AuthName "Restricted Site" + AuthBasicProvider file + AuthUserFile /usr/local/apache2/conf/.htpasswd + Require valid-user + + + diff --git a/selenium/test/multi-oauth/rabbitmq.devkeycloak-proxy.conf b/selenium/test/multi-oauth/rabbitmq.devkeycloak-proxy.conf new file mode 100644 index 0000000000..2a262e65fc --- /dev/null +++ b/selenium/test/multi-oauth/rabbitmq.devkeycloak-proxy.conf @@ -0,0 +1,2 @@ +auth_oauth2.oauth_providers.devkeycloak.proxy.host = ${DEVKEYCLOAK_PROXY_HOST} +auth_oauth2.oauth_providers.devkeycloak.proxy.port = ${DEVKEYCLOAK_PROXY_PORT} diff --git a/selenium/test/multi-oauth/rabbitmq.prodkeycloak-proxy.conf b/selenium/test/multi-oauth/rabbitmq.prodkeycloak-proxy.conf new file mode 100644 index 0000000000..d4047c6dcd --- /dev/null +++ b/selenium/test/multi-oauth/rabbitmq.prodkeycloak-proxy.conf @@ -0,0 +1,4 @@ +auth_oauth2.oauth_providers.prodkeycloak.proxy.host = ${PRODKEYCLOAK_PROXY_HOST} +auth_oauth2.oauth_providers.prodkeycloak.proxy.port = ${PRODKEYCLOAK_PROXY_PORT} +auth_oauth2.oauth_providers.prodkeycloak.proxy.username = ${PRODKEYCLOAK_PROXY_USERNAME} +auth_oauth2.oauth_providers.prodkeycloak.proxy.password = ${PRODKEYCLOAK_PROXY_PASSWORD} diff --git a/selenium/test/multi-oauth/with-basic-auth-idps-down/landing.js b/selenium/test/multi-oauth/with-basic-auth-idps-down/landing.js index 30bc40a443..7e27ee7cb3 100644 --- a/selenium/test/multi-oauth/with-basic-auth-idps-down/landing.js +++ b/selenium/test/multi-oauth/with-basic-auth-idps-down/landing.js @@ -33,9 +33,7 @@ describe('When basic authentication is enabled but both Idps are down', function it('should not be presented oauth2 section', async function () { await homePage.isLoaded() - if (await homePage.isOAuth2SectionVisible()) { - throw new Error('OAuth2 section should not be present') - } + assert.ok(await homePage.isOAuth2SectionNotVisible()) }) after(async function () { diff --git a/selenium/test/multi-oauth/with-basic-auth/landing.js b/selenium/test/multi-oauth/with-basic-auth/landing.js index df286b7c63..971b416c2f 100644 --- a/selenium/test/multi-oauth/with-basic-auth/landing.js +++ b/selenium/test/multi-oauth/with-basic-auth/landing.js @@ -45,8 +45,7 @@ describe('Given two oauth resources and basic auth enabled, an unauthenticated u }) it('should not have a warning message', async function () { - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) diff --git a/selenium/test/multi-oauth/without-basic-auth/happy-login.js b/selenium/test/multi-oauth/without-basic-auth/happy-login.js index da8915b57a..d91fc747dc 100644 --- a/selenium/test/multi-oauth/without-basic-auth/happy-login.js +++ b/selenium/test/multi-oauth/without-basic-auth/happy-login.js @@ -32,7 +32,7 @@ describe('Given there are three oauth resources but two enabled', function () { if (!await overview.isLoaded()) { throw new Error('Failed to login') } - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) await overview.logout() }) it('prod_user registered in prodkeycloak can log in using RabbitMQ Development OAuth 2.0 resource', async function () { @@ -46,7 +46,7 @@ describe('Given there are three oauth resources but two enabled', function () { if (!await overview.isLoaded()) { throw new Error('Failed to login') } - assert.ok(!await overview.isPopupWarningDisplayed()) + assert.ok(await overview.isPopupWarningNotDisplayed()) await overview.logout() }) diff --git a/selenium/test/multi-oauth/without-basic-auth/landing.js b/selenium/test/multi-oauth/without-basic-auth/landing.js index 662bb09c1c..b27064fe41 100644 --- a/selenium/test/multi-oauth/without-basic-auth/landing.js +++ b/selenium/test/multi-oauth/without-basic-auth/landing.js @@ -39,11 +39,11 @@ describe('Given three oauth resources but only two enabled, an unauthenticated u }) it('should not be presented with a login button to log in using Basic Auth', async function () { - assert.ok(!await homePage.isBasicAuthSectionVisible()) + assert.ok(await homePage.isBasicAuthSectionNotVisible()) }) it('should not have a warning message', async function () { - assert.ok(!await homePage.isWarningVisible()) + assert.ok(await homePage.isWarningNotVisible()) }) diff --git a/selenium/test/oauth/env.docker.forward-proxy b/selenium/test/oauth/env.docker.forward-proxy new file mode 100644 index 0000000000..c9fb1277bb --- /dev/null +++ b/selenium/test/oauth/env.docker.forward-proxy @@ -0,0 +1,6 @@ +export FORWARD_PROXY_HOST=forward-proxy +export FORWARD_PROXY_PORT=9092 +export FORWARD_PROXY_USERNAME=guest +export FORWARD_PROXY_PASSWORD=guest +export OAUTH_PROVIDER_URL=${KEYCLOAK_URL} +export OAUTH_PROVIDER_CA_CERT=${KEYCLOAK_CA_CERT} \ No newline at end of file diff --git a/selenium/test/oauth/env.docker.keycloak b/selenium/test/oauth/env.docker.keycloak index b293b57bc2..5d9ae18a8e 100644 --- a/selenium/test/oauth/env.docker.keycloak +++ b/selenium/test/oauth/env.docker.keycloak @@ -1,3 +1,2 @@ export KEYCLOAK_URL=https://keycloak:8443/realms/test -export OAUTH_PROVIDER_URL=https://keycloak:8443/realms/test -export OAUTH_PROVIDER_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem +export KEYCLOAK_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem diff --git a/selenium/test/oauth/env.keycloak-oauth-provider b/selenium/test/oauth/env.keycloak-oauth-provider index 74d6e94ad0..d0632325bc 100644 --- a/selenium/test/oauth/env.keycloak-oauth-provider +++ b/selenium/test/oauth/env.keycloak-oauth-provider @@ -1 +1,2 @@ -# export OAUTH_PROVIDER_URL=${KEYCLOAK_URL} +export OAUTH_PROVIDER_URL=${KEYCLOAK_URL} +export OAUTH_PROVIDER_CA_CERT=${OAUTH_SERVER_CONFIG_DIR}/ca_keycloak_certificate.pem diff --git a/selenium/test/oauth/env.local.forward-proxy b/selenium/test/oauth/env.local.forward-proxy new file mode 100644 index 0000000000..c9fb1277bb --- /dev/null +++ b/selenium/test/oauth/env.local.forward-proxy @@ -0,0 +1,6 @@ +export FORWARD_PROXY_HOST=forward-proxy +export FORWARD_PROXY_PORT=9092 +export FORWARD_PROXY_USERNAME=guest +export FORWARD_PROXY_PASSWORD=guest +export OAUTH_PROVIDER_URL=${KEYCLOAK_URL} +export OAUTH_PROVIDER_CA_CERT=${KEYCLOAK_CA_CERT} \ No newline at end of file diff --git a/selenium/test/oauth/env.local.keycloak b/selenium/test/oauth/env.local.keycloak index ccad940e24..522a9e3a78 100644 --- a/selenium/test/oauth/env.local.keycloak +++ b/selenium/test/oauth/env.local.keycloak @@ -1,3 +1,2 @@ -export KEYCLOAK_URL=https://localhost:8443/realms/test -export OAUTH_PROVIDER_URL=https://localhost:8443/realms/test -export OAUTH_PROVIDER_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem +export KEYCLOAK_URL=https://keycloak:8443/realms/test +export KEYCLOAK_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem diff --git a/selenium/test/oauth/forward-proxy/.htpasswd b/selenium/test/oauth/forward-proxy/.htpasswd new file mode 100644 index 0000000000..1a63893732 --- /dev/null +++ b/selenium/test/oauth/forward-proxy/.htpasswd @@ -0,0 +1 @@ +guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA= diff --git a/selenium/test/oauth/forward-proxy/httpd.conf b/selenium/test/oauth/forward-proxy/httpd.conf new file mode 100644 index 0000000000..3ff43b2472 --- /dev/null +++ b/selenium/test/oauth/forward-proxy/httpd.conf @@ -0,0 +1,165 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so "logs/access_log" +# with ServerRoot set to "/usr/local/apache2" will be interpreted by the +# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" +# will be interpreted as '/logs/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/usr/local/apache2" + +# +# Mutex: Allows you to set the mutex mechanism and mutex file directory +# for individual mutexes, or change the global defaults +# +# Uncomment and change the directory if mutexes are file-based and the default +# mutex file directory is not on a local disk or is not appropriate for some +# other reason. +# +# Mutex default:logs + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 9092 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# + +LoadModule mpm_event_module modules/mod_mpm_event.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule proxy_module modules/mod_proxy.so +LoadModule proxy_connect_module modules/mod_proxy_connect.so +LoadModule proxy_http_module modules/mod_proxy_http.so +LoadModule ssl_module modules/mod_ssl.so +LoadModule unixd_module modules/mod_unixd.so + + +User www-data +Group www-data + + + +ServerAdmin you@example.com + +ServerName forward-proxy + +ErrorLog /proc/self/fd/2 + +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + CustomLog logs/access_log common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + #CustomLog "logs/access_log" combined + + + + ProxyRequests On + ProxyVia On + + Allow from all + + + + + +# SSLEngine on +# SSLCertificateKeyFile /usr/local/apache2/conf/server_forward-proxy_key.pem +# SSLCertificateFile /usr/local/apache2/conf/server_forward-proxy_certificate.pem +# SSLCertificateChainFile /usr/local/apache2/conf/ca_keycloak_certificate.pem +# SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +# SSLProxyVerify none + AllowCONNECT 8443 + +# SSLProxyEngine On + +# SSLProxyVerify none +# SSLProxyCheckPeerCN off +# SSLProxyCheckPeerName off +# SSLProxyCheckPeerExpire off +# SSLProxyProtocol +TLSv1.2 + + ProxyRequests On + ProxyVia On + LogLevel debug + ErrorLog /dev/stderr + CustomLog /dev/stdout combined + + + Allow from all + AuthType Basic + AuthName "Restricted Site" + AuthBasicProvider file + AuthUserFile /usr/local/apache2/conf/.htpasswd + Require valid-user + + + diff --git a/selenium/test/oauth/imports/users.json b/selenium/test/oauth/imports/users.json index e6b99e3b2b..696ab08f35 100644 --- a/selenium/test/oauth/imports/users.json +++ b/selenium/test/oauth/imports/users.json @@ -56,6 +56,9 @@ "vhosts": [ { "name": "/" + }, + { + "name": "other" } ], "permissions": [ diff --git a/selenium/test/oauth/rabbitmq.forward-proxy-oauth-provider.conf b/selenium/test/oauth/rabbitmq.forward-proxy-oauth-provider.conf new file mode 100644 index 0000000000..66f30392f5 --- /dev/null +++ b/selenium/test/oauth/rabbitmq.forward-proxy-oauth-provider.conf @@ -0,0 +1,6 @@ +auth_oauth2.issuer = ${OAUTH_PROVIDER_URL} +auth_oauth2.https.cacertfile = ${KEYCLOAK_CA_CERT} +auth_oauth2.proxy.host = ${FORWARD_PROXY_HOST} +auth_oauth2.proxy.port = ${FORWARD_PROXY_PORT} +auth_oauth2.proxy.username = ${FORWARD_PROXY_USERNAME} +auth_oauth2.proxy.password = ${FORWARD_PROXY_PASSWORD} diff --git a/selenium/test/oauth/rabbitmq.keycloak-mgt-oauth-provider.conf b/selenium/test/oauth/rabbitmq.keycloak-mgt-oauth-provider.conf index b9e65845d5..1007e5ee94 100644 --- a/selenium/test/oauth/rabbitmq.keycloak-mgt-oauth-provider.conf +++ b/selenium/test/oauth/rabbitmq.keycloak-mgt-oauth-provider.conf @@ -1,3 +1,3 @@ # uaa requires a secret in order to renew tokens -management.oauth_provider_url = ${KEYCLOAK_URL} +#management.oauth_provider_url = ${KEYCLOAK_URL} management.oauth_authorization_endpoint_params.resource = rabbitmq diff --git a/selenium/test/oauth/rabbitmq.keycloak-oauth-provider.conf b/selenium/test/oauth/rabbitmq.keycloak-oauth-provider.conf index 69adfc409a..f775f4ec93 100644 --- a/selenium/test/oauth/rabbitmq.keycloak-oauth-provider.conf +++ b/selenium/test/oauth/rabbitmq.keycloak-oauth-provider.conf @@ -1,2 +1,2 @@ -auth_oauth2.issuer = ${OAUTH_PROVIDER_URL} -auth_oauth2.https.cacertfile = ${OAUTH_PROVIDER_CA_CERT} +auth_oauth2.issuer = ${KEYCLOAK_URL} +auth_oauth2.https.cacertfile = ${KEYCLOAK_CA_CERT} diff --git a/selenium/test/oauth/rabbitmq.keycloak-verify-none-oauth-provider.conf b/selenium/test/oauth/rabbitmq.keycloak-verify-none-oauth-provider.conf index 6017206237..624227d384 100644 --- a/selenium/test/oauth/rabbitmq.keycloak-verify-none-oauth-provider.conf +++ b/selenium/test/oauth/rabbitmq.keycloak-verify-none-oauth-provider.conf @@ -1,2 +1,2 @@ -auth_oauth2.issuer = ${OAUTH_PROVIDER_URL} +auth_oauth2.issuer = ${KEYCLOAK_URL} auth_oauth2.https.peer_verification = verify_none diff --git a/selenium/test/oauth/rabbitmq.uaa-mgt-oauth-provider.conf b/selenium/test/oauth/rabbitmq.uaa-mgt-oauth-provider.conf index e50200cbee..ae55fc8d45 100644 --- a/selenium/test/oauth/rabbitmq.uaa-mgt-oauth-provider.conf +++ b/selenium/test/oauth/rabbitmq.uaa-mgt-oauth-provider.conf @@ -1,2 +1,4 @@ # uaa requires a secret in order to renew tokens management.oauth_provider_url = ${UAA_URL} +# uaa requires a secret in order to renew tokens +management.oauth_client_secret = ${OAUTH_CLIENT_SECRET} diff --git a/selenium/test/oauth/rabbitmq.uaa-oauth-provider.conf b/selenium/test/oauth/rabbitmq.uaa-oauth-provider.conf index 46f67a598b..9ab0b0ef1c 100644 --- a/selenium/test/oauth/rabbitmq.uaa-oauth-provider.conf +++ b/selenium/test/oauth/rabbitmq.uaa-oauth-provider.conf @@ -1,5 +1,3 @@ -# uaa requires a secret in order to renew tokens -management.oauth_client_secret = ${OAUTH_CLIENT_SECRET} # configure static signing keys and the oauth provider used by the plugin auth_oauth2.default_key = ${OAUTH_SIGNING_KEY_ID} diff --git a/selenium/test/oauth/with-basic-auth-idp-down/happy-login.js b/selenium/test/oauth/with-basic-auth-idp-down/happy-login.js index 3a7d2baafb..9180fa955d 100644 --- a/selenium/test/oauth/with-basic-auth-idp-down/happy-login.js +++ b/selenium/test/oauth/with-basic-auth-idp-down/happy-login.js @@ -21,7 +21,7 @@ describe('When basic authentication is enabled but UAA is down', function () { it('can log in with Basic Auth', async function () { await homePage.toggleBasicAuthSection() - assert.ok(await homePage.isLoginButtonVisible) + assert.ok(await homePage.getBasicAuthLoginButton()) await homePage.basicAuthLogin('guest', 'guest') await overview.isLoaded() assert.equal(await overview.getUser(), 'User guest') diff --git a/selenium/test/oauth/with-basic-auth-idp-down/landing.js b/selenium/test/oauth/with-basic-auth-idp-down/landing.js index 5a0b6bc130..8038f08688 100644 --- a/selenium/test/oauth/with-basic-auth-idp-down/landing.js +++ b/selenium/test/oauth/with-basic-auth-idp-down/landing.js @@ -20,15 +20,13 @@ describe('When basic authentication is enabled but UAA is down', function () { it('should display warning message that UAA is down', async function () { await homePage.isLoaded() const message = await homePage.getWarning() - assert.equal(true, message.startsWith('OAuth resource [rabbitmq] not available')) - assert.equal(true, message.endsWith(' not reachable')) + assert.ok(message.startsWith('OAuth resource [rabbitmq] not available')) + assert.ok(message.endsWith(' not reachable')) }) it('should not be presented oauth2 section', async function () { await homePage.isLoaded() - if (await homePage.isOAuth2SectionVisible()) { - throw new Error('OAuth2 section should not be present') - } + assert.ok(await homePage.isOAuth2SectionNotVisible()) }) after(async function () { diff --git a/selenium/test/oauth/with-basic-auth/landing.js b/selenium/test/oauth/with-basic-auth/landing.js index 508b5f0555..f0848737ef 100644 --- a/selenium/test/oauth/with-basic-auth/landing.js +++ b/selenium/test/oauth/with-basic-auth/landing.js @@ -30,8 +30,7 @@ describe('A user which accesses any protected URL without a session where basic }) it('should not have a warning message', async function () { - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) diff --git a/selenium/test/oauth/with-basic-auth/unauthorized.js b/selenium/test/oauth/with-basic-auth/unauthorized.js index fec2757f0a..baf6c71b0f 100644 --- a/selenium/test/oauth/with-basic-auth/unauthorized.js +++ b/selenium/test/oauth/with-basic-auth/unauthorized.js @@ -28,15 +28,14 @@ describe('An user without management tag', function () { }) it('cannot log in into the management ui', async function () { - const visible = await homePage.isWarningVisible() - assert.ok(visible) + assert.ok(await homePage.isWarningVisible()) }) 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()) + assert.ok(await homePage.isBasicAuthSectionNotVisible()) + assert.ok(await homePage.isOAuth2SectionNotVisible()) }) describe("After clicking on logout button", function() { @@ -46,8 +45,7 @@ describe('An user without management tag', function () { }) it('should get redirected to home page again without error message', async function(){ - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) }) diff --git a/selenium/test/oauth/with-idp-down/landing.js b/selenium/test/oauth/with-idp-down/landing.js index 5e23e8df80..7dfbc3ac09 100644 --- a/selenium/test/oauth/with-idp-down/landing.js +++ b/selenium/test/oauth/with-idp-down/landing.js @@ -20,13 +20,13 @@ describe('When UAA is down', function () { it('should display warning message that UAA is down', async function () { await homePage.isLoaded() const message = await homePage.getWarning() - assert.equal(true, message.startsWith('OAuth resource [rabbitmq] not available')) - assert.equal(true, message.endsWith(' not reachable')) + assert.ok(message.startsWith('OAuth resource [rabbitmq] not available')) + assert.ok(message.endsWith(' not reachable')) }) it('should not be presented with a login button to log in', async function () { await homePage.isLoaded() - assert.equal(false, await homePage.isLoginButtonVisible()) + assert.ok(await homePage.isLoginButtonNotVisible()) }) after(async function () { diff --git a/selenium/test/oauth/with-idp-initiated-via-proxy/happy-login.js b/selenium/test/oauth/with-idp-initiated-via-proxy/happy-login.js index dc281b13f1..ccbeec0357 100644 --- a/selenium/test/oauth/with-idp-initiated-via-proxy/happy-login.js +++ b/selenium/test/oauth/with-idp-initiated-via-proxy/happy-login.js @@ -1,16 +1,14 @@ const { By, Key, until, Builder } = require('selenium-webdriver') require('chromedriver') const assert = require('assert') -const { buildDriver, goToLogin, goToHome, captureScreensFor, teardown } = require('../../utils') +const { buildDriver, goToHome, captureScreensFor, teardown } = require('../../utils') const OverviewPage = require('../../pageobjects/OverviewPage') describe('A user with a JWT token', function () { let overview let captureScreen - let token - let fakePortal - + before(async function () { driver = buildDriver() overview = new OverviewPage(driver) diff --git a/selenium/test/oauth/with-idp-initiated/landing.js b/selenium/test/oauth/with-idp-initiated/landing.js index ef102f876d..7aa2e26ae5 100644 --- a/selenium/test/oauth/with-idp-initiated/landing.js +++ b/selenium/test/oauth/with-idp-initiated/landing.js @@ -21,14 +21,12 @@ describe('A user which accesses any protected URL without a session', function ( it('should be presented with a login button to log in', async function () { await homePage.isLoaded() - const value = await homePage.getLoginButton() - assert.equal(value, 'Click here to log in') + assert.equal(await homePage.getLoginButton(), 'Click here to log in') }) it('should not have a warning message', async function () { await homePage.isLoaded() - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) it('login button should redirect to the configured oauth_provider_url', async function () { diff --git a/selenium/test/oauth/with-idp-initiated/token-expires.js b/selenium/test/oauth/with-idp-initiated/token-expires.js index 50094027d9..7baa1a7e04 100644 --- a/selenium/test/oauth/with-idp-initiated/token-expires.js +++ b/selenium/test/oauth/with-idp-initiated/token-expires.js @@ -36,8 +36,7 @@ describe('Once user logs in with its own token', function () { it('user should be presented with a login button to log in', async function () { await homePage.isLoaded() - const value = await homePage.getLoginButton() - assert.equal(value, 'Click here to log in') + assert.equal(await homePage.getLoginButton(), 'Click here to log in') }) after(async function () { diff --git a/selenium/test/oauth/with-idp-initiated/unauthorized.js b/selenium/test/oauth/with-idp-initiated/unauthorized.js index f26daba016..74fc58c837 100644 --- a/selenium/test/oauth/with-idp-initiated/unauthorized.js +++ b/selenium/test/oauth/with-idp-initiated/unauthorized.js @@ -24,12 +24,10 @@ describe('A user who accesses the /login URL with a token without scopes for the }) it('should get a warning message', async function () { - const message = await homePage.getWarning() - assert.equal('Not_Authorized', message) + assert.equal(await homePage.getWarning(), 'Not_Authorized') }) it('should be presented with a login button to log in', async function () { - const value = await homePage.getLoginButton() - assert.equal(value, 'Click here to log in') + assert.equal(await homePage.getLoginButton(), 'Click here to log in') }) after(async function () { diff --git a/selenium/test/oauth/with-multi-resources/landing.js b/selenium/test/oauth/with-multi-resources/landing.js index ce74f527bd..76a970f52b 100644 --- a/selenium/test/oauth/with-multi-resources/landing.js +++ b/selenium/test/oauth/with-multi-resources/landing.js @@ -29,14 +29,12 @@ describe('A user which accesses any protected URL without a session', function ( assert.equal("rabbit_x", resources[2].value) assert.equal("RabbitMQ X_Idp", resources[2].text) - const value = await homePage.getLoginButton() - assert.equal(value, 'Click here to log in') + assert.equal(await homePage.getLoginButton(), 'Click here to log in') }) it('should not have a warning message', async function () { await homePage.isLoaded() - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) after(async function () { diff --git a/selenium/test/oauth/with-sp-initiated/landing.js b/selenium/test/oauth/with-sp-initiated/landing.js index 6a600a7477..ce545c251a 100644 --- a/selenium/test/oauth/with-sp-initiated/landing.js +++ b/selenium/test/oauth/with-sp-initiated/landing.js @@ -18,14 +18,12 @@ describe('A user which accesses any protected URL without a session', function ( it('should be presented with a login button to log in', async function () { await homePage.isLoaded() - const value = await homePage.getLoginButton() - assert.equal(value, 'Click here to log in') + assert.equal(await homePage.getLoginButton(), 'Click here to log in') }) it('should not have a warning message', async function () { await homePage.isLoaded() - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + assert.ok(await homePage.isWarningNotVisible()) }) after(async function () { diff --git a/selenium/test/oauth/with-sp-initiated/redirection-after-login.js b/selenium/test/oauth/with-sp-initiated/redirection-after-login.js index eb9d49b9d6..0c966525d0 100644 --- a/selenium/test/oauth/with-sp-initiated/redirection-after-login.js +++ b/selenium/test/oauth/with-sp-initiated/redirection-after-login.js @@ -26,14 +26,11 @@ describe('A user which accesses a protected URL without a session', function () it('redirect to previous accessed page after login ', async function () { await homePage.clickToLogin() - await idpLogin.login('rabbit_admin', 'rabbit_admin') - if (!await exchanges.isLoaded()) { throw new Error('Failed to login') } - - assert.equal("All exchanges (8)", await exchanges.getPagingSectionHeaderText()) + await exchanges.getPagingSectionHeaderText() }) diff --git a/selenium/test/oauth/with-sp-initiated/unauthorized.js b/selenium/test/oauth/with-sp-initiated/unauthorized.js index 5a81f6e18a..e7068608fc 100644 --- a/selenium/test/oauth/with-sp-initiated/unauthorized.js +++ b/selenium/test/oauth/with-sp-initiated/unauthorized.js @@ -29,15 +29,14 @@ describe('An user without management tag', function () { if (!await homePage.isLoaded()) { throw new Error('Failed to login') } - const visible = await homePage.isWarningVisible() - assert.ok(visible) + assert.ok(await homePage.isWarningVisible()) }) it('should get "Not authorized" warning message and logout button but no login button', 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()) + assert.ok(await homePage.isBasicAuthSectionNotVisible()) + assert.ok(await homePage.isOAuth2SectionNotVisible()) }) describe("After clicking on logout button", function() { @@ -47,9 +46,8 @@ describe('An user without management tag', function () { }) it('should get redirected to home page again without error message', async function(){ - await driver.sleep(250) - const visible = await homePage.isWarningVisible() - assert.ok(!visible) + await driver.sleep(250) + assert.ok(await homePage.isWarningNotVisible()) }) }) diff --git a/selenium/test/pageobjects/BasePage.js b/selenium/test/pageobjects/BasePage.js index b543115208..b8c64c8b5d 100644 --- a/selenium/test/pageobjects/BasePage.js +++ b/selenium/test/pageobjects/BasePage.js @@ -146,18 +146,12 @@ module.exports = class BasePage { 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, - 'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element, - this.polling / 2).then(function onWarningVisible(e) { - return Promise.resolve(true) - }, function onError(e) { - return Promise.resolve(false) - }) - */ + } } + async isPopupWarningNotDisplayed() { + return this.waitForNotDisplayed(FORM_POPUP) + } + async getPopupWarning() { let element = await driver.findElement(FORM_POPUP) return this.driver.wait(until.elementIsVisible(element), this.timeout, @@ -208,14 +202,37 @@ module.exports = class BasePage { async waitForDisplayed (locator) { if (this.interactionDelay && this.interactionDelay > 0) await this.driver.sleep(this.interactionDelay) - try { - return this.waitForVisible(await this.waitForLocated(locator)) - }catch(error) { - if (!error.name.includes("NoSuchSessionError")) { - console.error("Failed to waitForDisplayed " + locator + " due to " + error) + let times = 1 + do { + try { + return this.waitForVisible(await this.waitForLocated(locator)) + }catch(error) { + if (!error.name.includes("NoSuchSessionError")) { + console.error("Failed to waitForDisplayed " + locator + " due to " + error) + } + if (times > 0 && error.name.includes("StaleElementReference")) { + times-- + this.driver.sleep(50) + } else { + throw error + } } - throw error - } + } while (true) + + } + + async waitForNotDisplayed (locator) { + let times = 5 + do { + try { + await driver.findElement(locator) + times-- + this.driver.sleep(50) + }catch(error) { + return Promise.resolve(true) + } + } while(times > 0) + return Promise.resolve(false) } async getText (locator) { diff --git a/selenium/test/pageobjects/SSOHomePage.js b/selenium/test/pageobjects/SSOHomePage.js index 38ef6f3af3..b14d40d206 100644 --- a/selenium/test/pageobjects/SSOHomePage.js +++ b/selenium/test/pageobjects/SSOHomePage.js @@ -51,6 +51,9 @@ module.exports = class SSOHomePage extends BasePage { async getOAuthResourceOptions () { return this.getSelectableOptions(SELECT_RESOURCES) } + async isLoginButtonNotVisible() { + return this.waitForNotDisplayed(OAUTH2_LOGIN_BUTTON) + } async isLoginButtonVisible() { try { await this.waitForDisplayed(OAUTH2_LOGIN_BUTTON) @@ -71,12 +74,18 @@ module.exports = class SSOHomePage extends BasePage { async isOAuth2SectionVisible() { return this.isDisplayed(SECTION_LOGIN_WITH_OAUTH) } + async isOAuth2SectionNotVisible() { + return this.waitForNotDisplayed(SECTION_LOGIN_WITH_OAUTH) + } async getOAuth2Section() { return this.waitForDisplayed(SECTION_LOGIN_WITH_OAUTH) } async isBasicAuthSectionVisible() { return this.isDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH) } + async isBasicAuthSectionNotVisible() { + return this.waitForNotDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH) + } async getBasicAuthSection() { return this.waitForDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH) } @@ -104,6 +113,9 @@ module.exports = class SSOHomePage extends BasePage { return Promise.resolve(false) } } + async isWarningNotVisible () { + return this.waitForNotDisplayed(WARNING) + } async getWarnings() { try { diff --git a/selenium/test/utils.js b/selenium/test/utils.js index c71ab1a13d..0666c66def 100644 --- a/selenium/test/utils.js +++ b/selenium/test/utils.js @@ -3,15 +3,17 @@ const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest const fsp = fs.promises const path = require('path') const { By, Key, until, Builder, logging, Capabilities } = require('selenium-webdriver') +const proxy = require('selenium-webdriver/proxy') require('chromedriver') const UAALoginPage = require('./pageobjects/UAALoginPage') const KeycloakLoginPage = require('./pageobjects/KeycloakLoginPage') const assert = require('assert') +const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false' const uaaUrl = process.env.UAA_URL || 'http://localhost:8080' const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL) || 'http://localhost:15672/' +//const proxyUrl = calculateProxyUrl(baseUrl) const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost' -const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false' const seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444' const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens' const profiles = process.env.PROFILES || '' @@ -23,6 +25,19 @@ function randomly_pick_baseurl(baseUrl) { function getRandomInt(max) { return Math.floor(Math.random() * max); } +/* +function calculateProxyUrl(baseUrl) { + if (baseUrl.includes("localhost")) { + return undefined + } + if (process.env.FORWARD_PROXY_HOST && process.env.FORWARD_PROXY_PORT) { + return 'http://' + process.env.FORWARD_PROXY_HOST + ':' + process.env.FORWARD_PROXY_PORT + }else { + console.log("There are no proxy setup : " + JSON.stringify(process.env)) + return undefined + } +} +*/ class CaptureScreenshot { driver test @@ -64,10 +79,19 @@ module.exports = { "--disable-search-engine-choice-screen" ] }); - driver = builder + + builder = builder .forBrowser('chrome') .withCapabilities(chromeCapabilities) - .build() +/* + if (proxyUrl) { + console.log("Using proxy " + proxyUrl) + builder = builder.setProxy(proxy.manual({https: proxyUrl})) + }else { + console.log("Not Using proxy . runLocal: " + runLocal) + } +*/ + driver = builder.build() driver.manage().setTimeouts( { pageLoad: 35000 } ) return driver },