Support explicit foward proxy from oauth2 plugin

This commit is contained in:
Marcial Rosales 2024-12-19 17:31:34 +01:00
parent 68de3fdb77
commit b5be85ffab
66 changed files with 1175 additions and 202 deletions

View File

@ -10,13 +10,8 @@ on:
- 'deps/rabbitmq_auth_**' - 'deps/rabbitmq_auth_**'
- 'deps/rabbitmq_management/src/**' - 'deps/rabbitmq_management/src/**'
- 'deps/rabbitmq_management/priv/**' - 'deps/rabbitmq_management/priv/**'
- 'deps/rabbitmq_management/selenium/**' - 'selenium/**'
- 'scripts/**' - 'scripts/**'
- .bazelrc
- .bazelversion
- BUILD.*
- '*.bzl'
- '*.bazel'
- .github/workflows/test-authnz.yaml - .github/workflows/test-authnz.yaml
pull_request: pull_request:
paths: paths:

View File

@ -12,11 +12,6 @@ on:
- 'deps/rabbitmq_management/priv/**' - 'deps/rabbitmq_management/priv/**'
- 'deps/rabbitmq_web_dispatch/src/**' - 'deps/rabbitmq_web_dispatch/src/**'
- 'scripts/**' - 'scripts/**'
- .bazelrc
- .bazelversion
- BUILD.*
- '*.bzl'
- '*.bazel'
- 'selenium/**' - 'selenium/**'
- .github/workflows/test-management-ui.yaml - .github/workflows/test-management-ui.yaml

View File

@ -20,6 +20,14 @@
}). }).
-type openid_configuration() :: #openid_configuration{}. -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, { -record(oauth_provider, {
id :: oauth_provider_id(), id :: oauth_provider_id(),
issuer :: option(uri_string:uri_string()), issuer :: option(uri_string:uri_string()),
@ -28,7 +36,8 @@
authorization_endpoint :: option(uri_string:uri_string()), authorization_endpoint :: option(uri_string:uri_string()),
end_session_endpoint :: option(uri_string:uri_string()), end_session_endpoint :: option(uri_string:uri_string()),
jwks_uri :: 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}]. -type query_list() :: [{unicode:chardata(), unicode:chardata() | true}].

View File

@ -7,13 +7,18 @@
-module(oauth2_client). -module(oauth2_client).
-export([get_access_token/2, get_expiration_time/1, -export([get_access_token/2, get_expiration_time/1,
refresh_access_token/2, refresh_access_token/2,
get_jwks/1,
get_oauth_provider/1, get_oauth_provider/2, get_oauth_provider/1, get_oauth_provider/2,
get_openid_configuration/2, get_openid_configuration/1,
build_openid_discovery_endpoint/3, build_openid_discovery_endpoint/3,
merge_openid_configuration/2, merge_openid_configuration/2,
merge_oauth_provider/2, merge_oauth_provider/2,
extract_ssl_options_as_list/1, 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"). -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", rabbit_log:debug("get_access_token using OAuthProvider:~p and client_id:~p",
[OAuthProvider, Request#access_token_request.client_id]), [OAuthProvider, Request#access_token_request.client_id]),
URL = OAuthProvider#oauth_provider.token_endpoint, URL = OAuthProvider#oauth_provider.token_endpoint,
Id = OAuthProvider#oauth_provider.id,
Header = [], Header = [],
Type = ?CONTENT_URLENCODED, Type = ?CONTENT_URLENCODED,
Body = build_access_token_request_body(Request), Body = build_access_token_request_body(Request),
HTTPOptions = get_ssl_options_if_any(OAuthProvider) ++ HTTPOptions =
get_timeout_of_default(Request#access_token_request.timeout), map_ssl_options_to_httpc_option(OAuthProvider#oauth_provider.ssl_options) ++
Options = [], map_timeout_to_httpc_option(Request#access_token_request.timeout),
Response = httpc:request(post, {URL, Header, Type, Body}, HTTPOptions, Options), Response = http_post(Id, URL, Header, Type, Body, HTTPOptions,
OAuthProvider#oauth_provider.proxy_options),
parse_access_token_response(Response). parse_access_token_response(Response).
-spec refresh_access_token(oauth_provider(), refresh_token_request()) -> -spec refresh_access_token(oauth_provider(), refresh_token_request()) ->
{ok, successful_access_token_response()} | {ok, successful_access_token_response()} |
{error, unsuccessful_access_token_response() | any()}. {error, unsuccessful_access_token_response() | any()}.
refresh_access_token(OAuthProvider, Request) -> refresh_access_token(OAuthProvider, Request) ->
Id = OAuthProvider#oauth_provider.id,
URL = OAuthProvider#oauth_provider.token_endpoint, URL = OAuthProvider#oauth_provider.token_endpoint,
Header = [], Header = [],
Type = ?CONTENT_URLENCODED, Type = ?CONTENT_URLENCODED,
Body = build_refresh_token_request_body(Request), Body = build_refresh_token_request_body(Request),
HTTPOptions = get_ssl_options_if_any(OAuthProvider) ++ HTTPOptions =
get_timeout_of_default(Request#refresh_token_request.timeout), map_ssl_options_to_httpc_option(OAuthProvider#oauth_provider.ssl_options) ++
Options = [], map_timeout_to_httpc_option(Request#refresh_token_request.timeout),
Response = httpc:request(post, {URL, Header, Type, Body}, HTTPOptions, Options), Response = http_post(Id, URL, Header, Type, Body, HTTPOptions,
OAuthProvider#oauth_provider.proxy_options),
parse_access_token_response(Response). 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) -> append_paths(Path1, Path2) ->
erlang:iolist_to_binary([Path1, Path2]). erlang:iolist_to_binary([Path1, Path2]).
@ -93,14 +151,27 @@ drop_trailing_path_separator(Path) when is_list(Path) ->
_ -> Path _ -> Path
end. end.
-spec get_openid_configuration(DiscoveryEndpoint :: uri_string:uri_string(), -spec get_openid_configuration(oauth_provider()) -> {ok, openid_configuration()} | {error, term()}.
ssl:tls_option() | []) -> {ok, openid_configuration()} | {error, term()}. get_openid_configuration(#oauth_provider{id = Id, discovery_endpoint = Endpoint,
get_openid_configuration(DiscoverEndpoint, TLSOptions) -> ssl_options = SslOptions, proxy_options = ProxyOptions}) ->
rabbit_log:debug("get_openid_configuration from ~p (~p)", [DiscoverEndpoint, rabbit_log:debug("get_openid_configuration from ~p (~p) [~p]", [Endpoint,
format_ssl_options(TLSOptions)]), format_ssl_options(SslOptions), format_proxy_options(ProxyOptions)]),
Options = [], HTTPOptions =
Response = httpc:request(get, {DiscoverEndpoint, []}, TLSOptions, Options), 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). 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()) -> -spec merge_openid_configuration(openid_configuration(), oauth_provider()) ->
oauth_provider(). oauth_provider().
@ -283,7 +354,7 @@ download_oauth_provider(OAuthProvider) ->
undefined -> {error, {missing_oauth_provider_attributes, [issuer]}}; undefined -> {error, {missing_oauth_provider_attributes, [issuer]}};
URL -> URL ->
rabbit_log:debug("Downloading oauth_provider using ~p ", [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, OpenIdConfiguration} ->
{ok, update_oauth_provider_endpoints_configuration( {ok, update_oauth_provider_endpoints_configuration(
merge_openid_configuration(OpenIdConfiguration, OAuthProvider))}; merge_openid_configuration(OpenIdConfiguration, OAuthProvider))};
@ -341,7 +412,6 @@ get_oauth_provider(OAuthProviderId, ListOfRequiredAttributes)
[OAuthProviderId, Error0]), [OAuthProviderId, Error0]),
Error0; Error0;
Config -> Config ->
rabbit_log:debug("Found oauth_provider configuration ~p", [Config]),
OAuthProvider = map_to_oauth_provider(Config), OAuthProvider = map_to_oauth_provider(Config),
rabbit_log:debug("Resolved oauth_provider ~p", [format_oauth_provider(OAuthProvider)]), rabbit_log:debug("Resolved oauth_provider ~p", [format_oauth_provider(OAuthProvider)]),
case find_missing_attributes(OAuthProvider, ListOfRequiredAttributes) of case find_missing_attributes(OAuthProvider, ListOfRequiredAttributes) of
@ -395,8 +465,36 @@ lookup_root_oauth_provider() ->
token_endpoint = get_env(token_endpoint), token_endpoint = get_env(token_endpoint),
authorization_endpoint = get_env(authorization_endpoint), authorization_endpoint = get_env(authorization_endpoint),
end_session_endpoint = get_env(end_session_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(). -spec extract_ssl_options_as_list(#{atom() => any()}) -> proplists:proplist().
extract_ssl_options_as_list(Map) -> extract_ssl_options_as_list(Map) ->
@ -522,15 +620,36 @@ append_extra_parameters(Request, QueryList) ->
Params -> Params ++ QueryList Params -> Params ++ QueryList
end. end.
get_ssl_options_if_any(OAuthProvider) -> map_ssl_options_to_httpc_option(SslOptions) ->
case OAuthProvider#oauth_provider.ssl_options of case SslOptions of
undefined -> []; undefined -> [];
Options -> [{ssl, Options}] Options -> [{ssl, Options}]
end. end.
get_timeout_of_default(Timeout) ->
map_timeout_to_httpc_option(Timeout) ->
case Timeout of case Timeout of
undefined -> [{timeout, ?DEFAULT_HTTP_TIMEOUT}]; 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. end.
is_json(?CONTENT_JSON) -> true; is_json(?CONTENT_JSON) -> true;
@ -543,10 +662,8 @@ is_json(_) -> false.
decode_body(_, []) -> []; decode_body(_, []) -> [];
decode_body(?CONTENT_JSON, Body) -> decode_body(?CONTENT_JSON, Body) ->
case rabbit_json:try_decode(rabbit_data_coercion:to_binary(Body)) of case rabbit_json:try_decode(rabbit_data_coercion:to_binary(Body)) of
{ok, Value} -> {ok, Value} -> Value;
Value; {error, _} = Error -> Error
{error, _} = Error ->
Error
end; end;
decode_body(MimeType, Body) -> decode_body(MimeType, Body) ->
Items = string:split(MimeType, ";"), Items = string:split(MimeType, ";"),
@ -588,14 +705,14 @@ map_to_oauth_provider(PropList) when is_list(PropList) ->
proplists:get_value(jwks_uri, PropList, undefined), proplists:get_value(jwks_uri, PropList, undefined),
ssl_options = ssl_options =
extract_ssl_options_as_list(maps:from_list( 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) -> map_to_access_token_response(Code, Reason, Headers, Body) ->
case decode_body(proplists:get_value("content-type", Headers, ?CONTENT_JSON), Body) of case decode_body(proplists:get_value("content-type", Headers, ?CONTENT_JSON), Body) of
{error, {error, InternalError}} -> {error, {error, InternalError}} -> {error, InternalError};
{error, InternalError}; {error, _} = Error -> Error;
{error, _} = Error ->
Error;
Value -> Value ->
case Code of case Code of
200 -> {ok, map_to_successful_access_token_response(Value)}; 200 -> {ok, map_to_successful_access_token_response(Value)};
@ -626,6 +743,18 @@ format_ssl_options(TlsOptions) ->
proplists:get_value(cacertfile, TlsOptions), proplists:get_value(cacertfile, TlsOptions),
CaCertsCount])). 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) -> "<from keyconfig>"; format_oauth_provider_id(root) -> "<from keyconfig>";
format_oauth_provider_id(Id) -> binary_to_list(Id). 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, " ++ lists:flatten(io_lib:format("{id: ~p, issuer: ~p, discovery_endpoint: ~p, " ++
" token_endpoint: ~p, " ++ " token_endpoint: ~p, " ++
"authorization_endpoint: ~p, end_session_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), format_oauth_provider_id(OAuthProvider#oauth_provider.id),
OAuthProvider#oauth_provider.issuer, OAuthProvider#oauth_provider.issuer,
OAuthProvider#oauth_provider.discovery_endpoint, OAuthProvider#oauth_provider.discovery_endpoint,
@ -642,7 +771,8 @@ format_oauth_provider(OAuthProvider) ->
OAuthProvider#oauth_provider.authorization_endpoint, OAuthProvider#oauth_provider.authorization_endpoint,
OAuthProvider#oauth_provider.end_session_endpoint, OAuthProvider#oauth_provider.end_session_endpoint,
OAuthProvider#oauth_provider.jwks_uri, 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) -> get_env(Par) ->
application:get_env(rabbitmq_auth_backend_oauth2, Par, undefined). application:get_env(rabbitmq_auth_backend_oauth2, Par, undefined).

View File

@ -322,13 +322,25 @@ build_openid_discovery_endpoint(Issuer, Path) ->
get_openid_configuration(Config) -> get_openid_configuration(Config) ->
ExpectedOAuthProvider = ?config(oauth_provider, Config), ExpectedOAuthProvider = ?config(oauth_provider, Config),
SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}],
{ok, ActualOpenId} = oauth2_client:get_openid_configuration( {ok, ActualOpenId} = oauth2_client:get_openid_configuration(
build_openid_discovery_endpoint(build_issuer("https")), ensure_discovery_endpoint(ExpectedOAuthProvider)),
SslOptions),
ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider),
assertOpenIdConfiguration(ExpectedOpenId, ActualOpenId). 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) -> map_oauth_provider_to_openid_configuration(OAuthProvider) ->
#openid_configuration{ #openid_configuration{
issuer = OAuthProvider#oauth_provider.issuer, issuer = OAuthProvider#oauth_provider.issuer,
@ -344,35 +356,30 @@ get_openid_configuration_returns_partial_payload(Config) ->
token_endpoint = ExpectedOAuthProvider0#oauth_provider.token_endpoint, token_endpoint = ExpectedOAuthProvider0#oauth_provider.token_endpoint,
jwks_uri = ExpectedOAuthProvider0#oauth_provider.jwks_uri}, jwks_uri = ExpectedOAuthProvider0#oauth_provider.jwks_uri},
SslOptions = [{ssl, ExpectedOAuthProvider0#oauth_provider.ssl_options}],
{ok, Actual} = oauth2_client:get_openid_configuration( {ok, Actual} = oauth2_client:get_openid_configuration(
build_openid_discovery_endpoint(build_issuer("https")), ensure_discovery_endpoint(ExpectedOAuthProvider0)),
SslOptions),
ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider),
assertOpenIdConfiguration(ExpectedOpenId, Actual). assertOpenIdConfiguration(ExpectedOpenId, Actual).
get_openid_configuration_using_path(Config) -> get_openid_configuration_using_path(Config) ->
ExpectedOAuthProvider = ?config(oauth_provider, Config), ExpectedOAuthProvider = ?config(oauth_provider, Config),
SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}], {ok, Actual} = oauth2_client:get_openid_configuration(
{ok, Actual} = oauth2_client:get_openid_configuration( ensure_discovery_endpoint(
build_openid_discovery_endpoint(build_issuer("https", ?ISSUER_PATH)), ensure_issuer(ExpectedOAuthProvider, build_issuer("https", ?ISSUER_PATH)))),
SslOptions),
ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider),
assertOpenIdConfiguration(ExpectedOpenId,Actual). assertOpenIdConfiguration(ExpectedOpenId,Actual).
get_openid_configuration_using_path_and_custom_endpoint(Config) -> get_openid_configuration_using_path_and_custom_endpoint(Config) ->
ExpectedOAuthProvider = ?config(oauth_provider, Config), ExpectedOAuthProvider = ?config(oauth_provider, Config),
SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}],
{ok, Actual} = oauth2_client:get_openid_configuration( {ok, Actual} = oauth2_client:get_openid_configuration(
build_openid_discovery_endpoint(build_issuer("https", ?ISSUER_PATH), ensure_discovery_endpoint(
?CUSTOM_OPENID_CONFIGURATION_ENDPOINT), SslOptions), ensure_issuer(ExpectedOAuthProvider, build_issuer("https", ?ISSUER_PATH)),
?CUSTOM_OPENID_CONFIGURATION_ENDPOINT)),
ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider),
assertOpenIdConfiguration(ExpectedOpenId, Actual). assertOpenIdConfiguration(ExpectedOpenId, Actual).
get_openid_configuration_using_custom_endpoint(Config) -> get_openid_configuration_using_custom_endpoint(Config) ->
ExpectedOAuthProvider = ?config(oauth_provider, Config), ExpectedOAuthProvider = ?config(oauth_provider, Config),
SslOptions = [{ssl, ExpectedOAuthProvider#oauth_provider.ssl_options}],
{ok, Actual} = oauth2_client:get_openid_configuration( {ok, Actual} = oauth2_client:get_openid_configuration(
build_openid_discovery_endpoint(build_issuer("https"), ensure_discovery_endpoint(ExpectedOAuthProvider, ?CUSTOM_OPENID_CONFIGURATION_ENDPOINT)),
?CUSTOM_OPENID_CONFIGURATION_ENDPOINT), SslOptions),
ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider), ExpectedOpenId = map_oauth_provider_to_openid_configuration(ExpectedOAuthProvider),
assertOpenIdConfiguration(ExpectedOpenId, Actual). assertOpenIdConfiguration(ExpectedOpenId, Actual).

View File

@ -220,6 +220,26 @@
rabbit_oauth2_schema:translate_oauth_providers(Conf) rabbit_oauth2_schema:translate_oauth_providers(Conf)
end}. 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, {mapping,
"auth_oauth2.https.peer_verification", "auth_oauth2.https.peer_verification",
"rabbitmq_auth_backend_oauth2.key_config.peer_verification", "rabbitmq_auth_backend_oauth2.key_config.peer_verification",
@ -322,6 +342,26 @@
"rabbitmq_auth_backend_oauth2.oauth_providers", "rabbitmq_auth_backend_oauth2.oauth_providers",
[{datatype, integer}]}. [{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, {mapping,
"auth_oauth2.oauth_providers.$name.https.hostname_verification", "auth_oauth2.oauth_providers.$name.https.hostname_verification",
"rabbitmq_auth_backend_oauth2.oauth_providers", "rabbitmq_auth_backend_oauth2.oauth_providers",

View File

@ -158,6 +158,7 @@ translate_oauth_providers(Conf) ->
Settings), Settings),
extract_oauth_providers_algorithm(Settings), extract_oauth_providers_algorithm(Settings),
extract_oauth_providers_https(Settings), extract_oauth_providers_https(Settings),
extract_oauth_providers_proxy(Settings),
extract_oauth_providers_signing_keys(Settings) extract_oauth_providers_signing_keys(Settings)
]). ]).
@ -264,6 +265,15 @@ mapOauthProviderProperty({Key, Value}) ->
_ -> Value _ -> Value
end}. 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) -> extract_oauth_providers_https(Settings) ->
ExtractProviderNameFun = fun extract_key_as_binary/1, ExtractProviderNameFun = fun extract_key_as_binary/1,
@ -280,6 +290,9 @@ mapHttpProperty({Key, Value}) ->
_ -> Value _ -> Value
end}. end}.
mapProxyProperty({Key, Value}) ->
{Key, Value}.
extract_oauth_providers_algorithm(Settings) -> extract_oauth_providers_algorithm(Settings) ->
KeyFun = fun extract_key_as_binary/1, KeyFun = fun extract_key_as_binary/1,

View File

@ -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, []).

View File

@ -42,11 +42,10 @@ add_signing_key(KeyId, Type, Value) ->
end. end.
-spec update_jwks_signing_keys(oauth_provider()) -> ok | {error, term()}. -spec update_jwks_signing_keys(oauth_provider()) -> ok | {error, term()}.
update_jwks_signing_keys(#oauth_provider{id = Id, jwks_uri = JwksUrl, update_jwks_signing_keys(#oauth_provider{id = Id} = OAuthProvider) ->
ssl_options = SslOptions}) -> rabbit_log:debug("Downloading signing keys from OauthProvider: ~tp",
rabbit_log:debug("Downloading signing keys from ~tp (TLS options: ~p)", [Id]),
[JwksUrl, format_ssl_options(SslOptions)]), case oauth2_client:get_jwks(OAuthProvider) of
case uaa_jwks:get(JwksUrl, SslOptions) of
{ok, {_, _, JwksBody}} -> {ok, {_, _, JwksBody}} ->
KeyList = maps:get(<<"keys">>, KeyList = maps:get(<<"keys">>,
jose:decode(erlang:iolist_to_binary(JwksBody)), []), jose:decode(erlang:iolist_to_binary(JwksBody)), []),

View File

@ -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"}
]}
]
}
}
]}
], []
} }
]. ].

View File

@ -65,6 +65,9 @@ verify_provider() -> [
]}, ]},
{oauth_provider_with_issuer, [], [ {oauth_provider_with_issuer, [], [
get_oauth_provider_has_jwks_uri 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), set_env(resource_server_id, ?RABBITMQ),
Config; 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) -> init_per_group(with_algorithms, Config) ->
KeyConfig = get_env(key_config, []), KeyConfig = get_env(key_config, []),
set_env(key_config, KeyConfig ++ [{algorithms, [<<"HS256">>, <<"RS256">>]}]), set_env(key_config, KeyConfig ++ [{algorithms, [<<"HS256">>, <<"RS256">>]}]),
@ -190,6 +214,16 @@ init_per_group(_any, Config) ->
end_per_group(with_rabbitmq_node, Config) -> end_per_group(with_rabbitmq_node, Config) ->
rabbit_ct_helpers:run_steps(Config, rabbit_ct_broker_helpers:teardown_steps()); 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) -> end_per_group(with_root_static_signing_keys, Config) ->
KeyConfig = call_get_env(Config, key_config, []), KeyConfig = call_get_env(Config, key_config, []),
call_set_env(Config, key_config, KeyConfig), 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) -> get_oauth_provider_has_jwks_uri(Config) ->
{ok, OAuthProvider} = get_oauth_provider( {ok, OAuthProvider} = get_oauth_provider(
?config(oauth_provider_id, Config), [jwks_uri]), ?config(oauth_provider_id, Config), [jwks_uri]),
ct:log("OAuthProvider: ~p", [OAuthProvider]),
?assertEqual(?config(jwks_uri, Config), OAuthProvider#oauth_provider.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 %% ---- Utility functions

View File

@ -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"
}

View File

@ -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"
}

View File

@ -12,8 +12,7 @@ ensure_keycloak() {
init_keycloak() { init_keycloak() {
KEYCLOAK_CONFIG_PATH=${KEYCLOAK_CONFIG_PATH:-oauth/keycloak} KEYCLOAK_CONFIG_PATH=${KEYCLOAK_CONFIG_PATH:-oauth/keycloak}
KEYCLOAK_CONFIG_DIR=$(realpath ${TEST_DIR}/${KEYCLOAK_CONFIG_PATH}) KEYCLOAK_CONFIG_DIR=$(realpath ${TEST_DIR}/${KEYCLOAK_CONFIG_PATH})
KEYCLOAK_URL=${OAUTH_PROVIDER_URL}
print "> KEYCLOAK_CONFIG_DIR: ${KEYCLOAK_CONFIG_DIR}" print "> KEYCLOAK_CONFIG_DIR: ${KEYCLOAK_CONFIG_DIR}"
print "> KEYCLOAK_URL: ${KEYCLOAK_URL}" print "> KEYCLOAK_URL: ${KEYCLOAK_URL}"
print "> KEYCLOAK_DOCKER_IMAGE: ${KEYCLOAK_DOCKER_IMAGE}" print "> KEYCLOAK_DOCKER_IMAGE: ${KEYCLOAK_DOCKER_IMAGE}"
@ -42,8 +41,9 @@ start_keycloak() {
--publish 8443:8443 \ --publish 8443:8443 \
--env KEYCLOAK_ADMIN=admin \ --env KEYCLOAK_ADMIN=admin \
--env KEYCLOAK_ADMIN_PASSWORD=admin \ --env KEYCLOAK_ADMIN_PASSWORD=admin \
--env QUARKUS_HTTP_ACCESS_LOG_ENABLED=true \
-v ${MOUNT_KEYCLOAK_CONF_DIR}:/opt/keycloak/data/import/ \ -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-file=/opt/keycloak/data/import/server_keycloak_certificate.pem \
--https-certificate-key-file=/opt/keycloak/data/import/server_keycloak_key.pem --https-certificate-key-file=/opt/keycloak/data/import/server_keycloak_key.pem

View File

@ -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"
}

View File

@ -214,20 +214,37 @@ wait_for_oidc_endpoint_docker() {
calculate_rabbitmq_url() { calculate_rabbitmq_url() {
echo "${RABBITMQ_SCHEME:-http}://$1${PUBLIC_RABBITMQ_PATH:-$RABBITMQ_PATH}" 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() { wait_for_url() {
BASE_URL=$1 BASE_URL=$1
if [[ $BASE_URL == *"localhost"** ]]; then if [[ $BASE_URL == *"localhost"** ]]; then
wait_for_url_local $BASE_URL wait_for_url_local $@
else else
wait_for_url_docker $BASE_URL wait_for_url_docker $@
fi fi
} }
wait_for_url_local() { wait_for_url_local() {
url=$1 url=$1
proxy=${2:-none}
proxy_user=${3:-none}
proxy_pass=$4
curl_args="-L -f -v"
max_retry=10 max_retry=10
counter=0 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 do
print "Waiting for $url to start (local)" print "Waiting for $url to start (local)"
sleep 5 sleep 5
@ -240,7 +257,14 @@ wait_for_url_docker() {
url=$1 url=$1
max_retry=10 max_retry=10
counter=0 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 do
print "Waiting for $url to start (docker)" print "Waiting for $url to start (docker)"
sleep 5 sleep 5
@ -373,7 +397,8 @@ profiles_with_local_or_docker() {
generate_env_file() { generate_env_file() {
begin "Generating env file ..." begin "Generating env file ..."
mkdir -p $CONF_DIR 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 source $ENV_FILE
end "Finished generating env file." end "Finished generating env file."
} }
@ -541,7 +566,7 @@ run_on_docker_with() {
build_mocha_image build_mocha_image
start_selenium start_selenium
trap teardown_components EXIT trap "teardown_components" EXIT
start_components start_components
test test
@ -622,7 +647,6 @@ start_components() {
$start $start
done done
} }
teardown_components() { teardown_components() {
skip_rabbitmq=${1:-false} skip_rabbitmq=${1:-false}

View File

@ -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-with-basic-auth.sh
authnz-mgt/multi-oauth-without-basic-auth-and-resource-label-and-scopes.sh authnz-mgt/multi-oauth-without-basic-auth-and-resource-label-and-scopes.sh
authnz-mgt/multi-oauth-without-basic-auth.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-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-via-proxy.sh
authnz-mgt/oauth-idp-initiated-with-uaa-and-prefix.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-via-proxy.sh
authnz-mgt/oauth-idp-initiated-with-uaa.sh authnz-mgt/oauth-idp-initiated-with-uaa.sh
authnz-mgt/oauth-with-keycloak.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-keycloak-with-verify-none.sh
authnz-mgt/oauth-with-uaa-down-but-with-basic-auth.sh authnz-mgt/oauth-with-uaa-down-but-with-basic-auth.sh
authnz-mgt/oauth-with-uaa-down.sh authnz-mgt/oauth-with-uaa-down.sh

View File

@ -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

View File

@ -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

View File

@ -3,16 +3,12 @@ const { tokenFor, openIdConfiguration } = require('../utils')
const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend') const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend')
const { open: openAmqp, once: onceAmqp, on: onAmqp, close: closeAmqp } = require('../amqp') const { open: openAmqp, once: onceAmqp, on: onAmqp, close: closeAmqp } = require('../amqp')
var receivedAmqpMessageCount = 0
var untilConnectionEstablished = new Promise((resolve, reject) => { var untilConnectionEstablished = new Promise((resolve, reject) => {
onAmqp('connection_open', function(context) { onAmqp('connection_open', function(context) {
resolve() resolve()
}) })
}) })
onAmqp('message', function (context) {
receivedAmqpMessageCount++
})
onceAmqp('sendable', function (context) { onceAmqp('sendable', function (context) {
context.sender.send({body:'first message'}) 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 () { it('can open an AMQP 1.0 connection', async function () {
var untilFirstMessageReceived = new Promise((resolve, reject) => {
onAmqp('message', function(context) {
resolve()
})
})
amqp = openAmqp() amqp = openAmqp()
await untilConnectionEstablished await untilConnectionEstablished
var untilMessageReceived = new Promise((resolve, reject) => { await untilFirstMessageReceived
var untilSecondMessageReceived = new Promise((resolve, reject) => {
onAmqp('message', function(context) { onAmqp('message', function(context) {
resolve() resolve()
}) })
}) })
amqp.sender.send({body:'second message'}) amqp.sender.send({body:'second message'})
await untilMessageReceived await untilSecondMessageReceived
assert.equal(2, receivedAmqpMessageCount)
}) })
after(function () { after(function () {

View File

@ -27,35 +27,32 @@ describe('management user with vhosts permissions', function () {
it('can access overview tab', async function () { it('can access overview tab', async function () {
await overview.clickOnOverviewTab() await overview.clickOnOverviewTab()
await overview.waitForOverviewTab() await overview.waitForOverviewTab()
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
}) })
it('can access connections tab', async function () { it('can access connections tab', async function () {
await overview.clickOnConnectionsTab() await overview.clickOnConnectionsTab()
await overview.waitForConnectionsTab() await overview.waitForConnectionsTab()
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
}) })
it('can access channels tab', async function () { it('can access channels tab', async function () {
await overview.clickOnChannelsTab() await overview.clickOnChannelsTab()
await overview.waitForChannelsTab() await overview.waitForChannelsTab()
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
}) })
it('can access exchanges tab', async function () { it('can access exchanges tab', async function () {
await overview.clickOnExchangesTab() await overview.clickOnExchangesTab()
await overview.waitForExchangesTab() await overview.waitForExchangesTab()
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
}) })
it('can access queues and streams tab', async function () { it('can access queues and streams tab', async function () {
await overview.clickOnQueuesTab() await overview.clickOnQueuesTab()
await overview.waitForQueuesTab() await overview.waitForQueuesTab()
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
}) })
it('can access limited options in admin tab', async function () { it('can access limited options in admin tab', async function () {
console.log("before clickOnAdminTab")
await overview.clickOnAdminTab() await overview.clickOnAdminTab()
console.log("before waitForAdminTab")
await overview.waitForAdminTab() await overview.waitForAdminTab()
console.log("after waitForAdminTab") assert.ok(await overview.isPopupWarningNotDisplayed())
assert.ok(!await overview.isPopupWarningDisplayed())
}) })
it('cannot add/update user limits', async function () { it('cannot add/update user limits', async function () {

View File

@ -19,7 +19,6 @@ describe('An user without management tag', function () {
overview = new OverviewPage(driver) overview = new OverviewPage(driver)
captureScreen = captureScreensFor(driver, __filename) captureScreen = captureScreensFor(driver, __filename)
//assert.ok(!await login.isPopupWarningDisplayed())
await login.login('rabbit_no_management', 'guest') 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(){ it('should close popup warning', async function(){
await delay(1000) await delay(1000)
const visible = await login.isPopupWarningDisplayed() const visible =
assert.ok(!visible) assert.ok(await login.isPopupWarningNotDisplayed())
}) })
}) })

View File

@ -0,0 +1 @@
guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA=

View File

@ -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 <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
# 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 <VirtualHost>
# 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
<IfModule unixd_module>
User www-data
Group www-data
</IfModule>
ServerAdmin you@example.com
ServerName devkeycloak-proxy
ErrorLog /proc/self/fd/2
LogLevel warn
<IfModule log_config_module>
#
# 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
<IfModule logio_module>
# 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
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> 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
</IfModule>
<IfModule proxy_module>
ProxyRequests On
ProxyVia On
<Proxy *>
Allow from all
</Proxy>
</IfModule>
<VirtualHost *:9092>
AllowCONNECT 8442
ProxyRequests On
ProxyVia On
LogLevel debug
ErrorLog /dev/stderr
CustomLog /dev/stdout combined
<Proxy "*">
Allow from all
</Proxy>
</VirtualHost>

View File

@ -0,0 +1,2 @@
export DEVKEYCLOAK_PROXY_HOST=devkeycloak-proxy
export DEVKEYCLOAK_PROXY_PORT=9092

View File

@ -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

View File

@ -0,0 +1,2 @@
export DEVKEYCLOAK_PROXY_HOST=devkeycloak-proxy
export DEVKEYCLOAK_PROXY_PORT=9092

View File

@ -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

View File

@ -0,0 +1 @@
guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA=

View File

@ -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 <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
# 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 <VirtualHost>
# 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
<IfModule unixd_module>
User www-data
Group www-data
</IfModule>
ServerAdmin you@example.com
ServerName prodkeycloak-proxy
ErrorLog /proc/self/fd/2
LogLevel warn
<IfModule log_config_module>
#
# 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
<IfModule logio_module>
# 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
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> 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
</IfModule>
<IfModule proxy_module>
ProxyRequests On
ProxyVia On
<Proxy *>
Allow from all
</Proxy>
</IfModule>
<VirtualHost *:9091>
AllowCONNECT 8443
ProxyRequests On
ProxyVia On
LogLevel debug
ErrorLog /dev/stderr
CustomLog /dev/stdout combined
<Proxy "*">
Allow from all
AuthType Basic
AuthName "Restricted Site"
AuthBasicProvider file
AuthUserFile /usr/local/apache2/conf/.htpasswd
Require valid-user
</Proxy>
</VirtualHost>

View File

@ -0,0 +1,2 @@
auth_oauth2.oauth_providers.devkeycloak.proxy.host = ${DEVKEYCLOAK_PROXY_HOST}
auth_oauth2.oauth_providers.devkeycloak.proxy.port = ${DEVKEYCLOAK_PROXY_PORT}

View File

@ -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}

View File

@ -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 () { it('should not be presented oauth2 section', async function () {
await homePage.isLoaded() await homePage.isLoaded()
if (await homePage.isOAuth2SectionVisible()) { assert.ok(await homePage.isOAuth2SectionNotVisible())
throw new Error('OAuth2 section should not be present')
}
}) })
after(async function () { after(async function () {

View File

@ -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 () { it('should not have a warning message', async function () {
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })

View File

@ -32,7 +32,7 @@ describe('Given there are three oauth resources but two enabled', function () {
if (!await overview.isLoaded()) { if (!await overview.isLoaded()) {
throw new Error('Failed to login') throw new Error('Failed to login')
} }
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
await overview.logout() await overview.logout()
}) })
it('prod_user registered in prodkeycloak can log in using RabbitMQ Development OAuth 2.0 resource', async function () { 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()) { if (!await overview.isLoaded()) {
throw new Error('Failed to login') throw new Error('Failed to login')
} }
assert.ok(!await overview.isPopupWarningDisplayed()) assert.ok(await overview.isPopupWarningNotDisplayed())
await overview.logout() await overview.logout()
}) })

View File

@ -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 () { 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 () { it('should not have a warning message', async function () {
assert.ok(!await homePage.isWarningVisible()) assert.ok(await homePage.isWarningNotVisible())
}) })

View File

@ -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}

View File

@ -1,3 +1,2 @@
export KEYCLOAK_URL=https://keycloak:8443/realms/test export KEYCLOAK_URL=https://keycloak:8443/realms/test
export OAUTH_PROVIDER_URL=https://keycloak:8443/realms/test export KEYCLOAK_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem
export OAUTH_PROVIDER_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem

View File

@ -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

View File

@ -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}

View File

@ -1,3 +1,2 @@
export KEYCLOAK_URL=https://localhost:8443/realms/test export KEYCLOAK_URL=https://keycloak:8443/realms/test
export OAUTH_PROVIDER_URL=https://localhost:8443/realms/test export KEYCLOAK_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem
export OAUTH_PROVIDER_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem

View File

@ -0,0 +1 @@
guest:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA=

View File

@ -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 <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
# 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 <VirtualHost>
# 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
<IfModule unixd_module>
User www-data
Group www-data
</IfModule>
ServerAdmin you@example.com
ServerName forward-proxy
ErrorLog /proc/self/fd/2
LogLevel warn
<IfModule log_config_module>
#
# 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
<IfModule logio_module>
# 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
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> 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
</IfModule>
<IfModule proxy_module>
ProxyRequests On
ProxyVia On
<Proxy *>
Allow from all
</Proxy>
</IfModule>
<VirtualHost *:9092>
# 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
<Proxy "*">
Allow from all
AuthType Basic
AuthName "Restricted Site"
AuthBasicProvider file
AuthUserFile /usr/local/apache2/conf/.htpasswd
Require valid-user
</Proxy>
</VirtualHost>

View File

@ -56,6 +56,9 @@
"vhosts": [ "vhosts": [
{ {
"name": "/" "name": "/"
},
{
"name": "other"
} }
], ],
"permissions": [ "permissions": [

View File

@ -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}

View File

@ -1,3 +1,3 @@
# uaa requires a secret in order to renew tokens # 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 management.oauth_authorization_endpoint_params.resource = rabbitmq

View File

@ -1,2 +1,2 @@
auth_oauth2.issuer = ${OAUTH_PROVIDER_URL} auth_oauth2.issuer = ${KEYCLOAK_URL}
auth_oauth2.https.cacertfile = ${OAUTH_PROVIDER_CA_CERT} auth_oauth2.https.cacertfile = ${KEYCLOAK_CA_CERT}

View File

@ -1,2 +1,2 @@
auth_oauth2.issuer = ${OAUTH_PROVIDER_URL} auth_oauth2.issuer = ${KEYCLOAK_URL}
auth_oauth2.https.peer_verification = verify_none auth_oauth2.https.peer_verification = verify_none

View File

@ -1,2 +1,4 @@
# uaa requires a secret in order to renew tokens # uaa requires a secret in order to renew tokens
management.oauth_provider_url = ${UAA_URL} management.oauth_provider_url = ${UAA_URL}
# uaa requires a secret in order to renew tokens
management.oauth_client_secret = ${OAUTH_CLIENT_SECRET}

View File

@ -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 # configure static signing keys and the oauth provider used by the plugin
auth_oauth2.default_key = ${OAUTH_SIGNING_KEY_ID} auth_oauth2.default_key = ${OAUTH_SIGNING_KEY_ID}

View File

@ -21,7 +21,7 @@ describe('When basic authentication is enabled but UAA is down', function () {
it('can log in with Basic Auth', async function () { it('can log in with Basic Auth', async function () {
await homePage.toggleBasicAuthSection() await homePage.toggleBasicAuthSection()
assert.ok(await homePage.isLoginButtonVisible) assert.ok(await homePage.getBasicAuthLoginButton())
await homePage.basicAuthLogin('guest', 'guest') await homePage.basicAuthLogin('guest', 'guest')
await overview.isLoaded() await overview.isLoaded()
assert.equal(await overview.getUser(), 'User guest') assert.equal(await overview.getUser(), 'User guest')

View File

@ -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 () { it('should display warning message that UAA is down', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const message = await homePage.getWarning() const message = await homePage.getWarning()
assert.equal(true, message.startsWith('OAuth resource [rabbitmq] not available')) assert.ok(message.startsWith('OAuth resource [rabbitmq] not available'))
assert.equal(true, message.endsWith(' not reachable')) assert.ok(message.endsWith(' not reachable'))
}) })
it('should not be presented oauth2 section', async function () { it('should not be presented oauth2 section', async function () {
await homePage.isLoaded() await homePage.isLoaded()
if (await homePage.isOAuth2SectionVisible()) { assert.ok(await homePage.isOAuth2SectionNotVisible())
throw new Error('OAuth2 section should not be present')
}
}) })
after(async function () { after(async function () {

View File

@ -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 () { it('should not have a warning message', async function () {
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })

View File

@ -28,15 +28,14 @@ describe('An user without management tag', function () {
}) })
it('cannot log in into the management ui', async function () { it('cannot log in into the management ui', async function () {
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningVisible())
assert.ok(visible)
}) })
it('should get "Not authorized" warning message', async function(){ it('should get "Not authorized" warning message', async function(){
assert.equal('Not authorized', await homePage.getWarning()) assert.equal('Not authorized', await homePage.getWarning())
assert.equal('Click here to logout', await homePage.getLogoutButton()) assert.equal('Click here to logout', await homePage.getLogoutButton())
assert.ok(!await homePage.isBasicAuthSectionVisible()) assert.ok(await homePage.isBasicAuthSectionNotVisible())
assert.ok(!await homePage.isOAuth2SectionVisible()) assert.ok(await homePage.isOAuth2SectionNotVisible())
}) })
describe("After clicking on logout button", function() { 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(){ it('should get redirected to home page again without error message', async function(){
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })
}) })

View File

@ -20,13 +20,13 @@ describe('When UAA is down', function () {
it('should display warning message that UAA is down', async function () { it('should display warning message that UAA is down', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const message = await homePage.getWarning() const message = await homePage.getWarning()
assert.equal(true, message.startsWith('OAuth resource [rabbitmq] not available')) assert.ok(message.startsWith('OAuth resource [rabbitmq] not available'))
assert.equal(true, message.endsWith(' not reachable')) assert.ok(message.endsWith(' not reachable'))
}) })
it('should not be presented with a login button to log in', async function () { it('should not be presented with a login button to log in', async function () {
await homePage.isLoaded() await homePage.isLoaded()
assert.equal(false, await homePage.isLoginButtonVisible()) assert.ok(await homePage.isLoginButtonNotVisible())
}) })
after(async function () { after(async function () {

View File

@ -1,16 +1,14 @@
const { By, Key, until, Builder } = require('selenium-webdriver') const { By, Key, until, Builder } = require('selenium-webdriver')
require('chromedriver') require('chromedriver')
const assert = require('assert') const assert = require('assert')
const { buildDriver, goToLogin, goToHome, captureScreensFor, teardown } = require('../../utils') const { buildDriver, goToHome, captureScreensFor, teardown } = require('../../utils')
const OverviewPage = require('../../pageobjects/OverviewPage') const OverviewPage = require('../../pageobjects/OverviewPage')
describe('A user with a JWT token', function () { describe('A user with a JWT token', function () {
let overview let overview
let captureScreen let captureScreen
let token
let fakePortal
before(async function () { before(async function () {
driver = buildDriver() driver = buildDriver()
overview = new OverviewPage(driver) overview = new OverviewPage(driver)

View File

@ -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 () { it('should be presented with a login button to log in', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const value = await homePage.getLoginButton() assert.equal(await homePage.getLoginButton(), 'Click here to log in')
assert.equal(value, 'Click here to log in')
}) })
it('should not have a warning message', async function () { it('should not have a warning message', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })
it('login button should redirect to the configured oauth_provider_url', async function () { it('login button should redirect to the configured oauth_provider_url', async function () {

View File

@ -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 () { it('user should be presented with a login button to log in', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const value = await homePage.getLoginButton() assert.equal(await homePage.getLoginButton(), 'Click here to log in')
assert.equal(value, 'Click here to log in')
}) })
after(async function () { after(async function () {

View File

@ -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 () { it('should get a warning message', async function () {
const message = await homePage.getWarning() assert.equal(await homePage.getWarning(), 'Not_Authorized')
assert.equal('Not_Authorized', message)
}) })
it('should be presented with a login button to log in', async function () { it('should be presented with a login button to log in', async function () {
const value = await homePage.getLoginButton() assert.equal(await homePage.getLoginButton(), 'Click here to log in')
assert.equal(value, 'Click here to log in')
}) })
after(async function () { after(async function () {

View File

@ -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("rabbit_x", resources[2].value)
assert.equal("RabbitMQ X_Idp", resources[2].text) assert.equal("RabbitMQ X_Idp", resources[2].text)
const value = await homePage.getLoginButton() assert.equal(await homePage.getLoginButton(), 'Click here to log in')
assert.equal(value, 'Click here to log in')
}) })
it('should not have a warning message', async function () { it('should not have a warning message', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })
after(async function () { after(async function () {

View File

@ -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 () { it('should be presented with a login button to log in', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const value = await homePage.getLoginButton() assert.equal(await homePage.getLoginButton(), 'Click here to log in')
assert.equal(value, 'Click here to log in')
}) })
it('should not have a warning message', async function () { it('should not have a warning message', async function () {
await homePage.isLoaded() await homePage.isLoaded()
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })
after(async function () { after(async function () {

View File

@ -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 () { it('redirect to previous accessed page after login ', async function () {
await homePage.clickToLogin() await homePage.clickToLogin()
await idpLogin.login('rabbit_admin', 'rabbit_admin') await idpLogin.login('rabbit_admin', 'rabbit_admin')
if (!await exchanges.isLoaded()) { if (!await exchanges.isLoaded()) {
throw new Error('Failed to login') throw new Error('Failed to login')
} }
await exchanges.getPagingSectionHeaderText()
assert.equal("All exchanges (8)", await exchanges.getPagingSectionHeaderText())
}) })

View File

@ -29,15 +29,14 @@ describe('An user without management tag', function () {
if (!await homePage.isLoaded()) { if (!await homePage.isLoaded()) {
throw new Error('Failed to login') throw new Error('Failed to login')
} }
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningVisible())
assert.ok(visible)
}) })
it('should get "Not authorized" warning message and logout button but no login button', async function(){ 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('Not authorized', await homePage.getWarning())
assert.equal('Click here to logout', await homePage.getLogoutButton()) assert.equal('Click here to logout', await homePage.getLogoutButton())
assert.ok(!await homePage.isBasicAuthSectionVisible()) assert.ok(await homePage.isBasicAuthSectionNotVisible())
assert.ok(!await homePage.isOAuth2SectionVisible()) assert.ok(await homePage.isOAuth2SectionNotVisible())
}) })
describe("After clicking on logout button", function() { 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(){ it('should get redirected to home page again without error message', async function(){
await driver.sleep(250) await driver.sleep(250)
const visible = await homePage.isWarningVisible() assert.ok(await homePage.isWarningNotVisible())
assert.ok(!visible)
}) })
}) })

View File

@ -146,18 +146,12 @@ module.exports = class BasePage {
return element.isDisplayed() return element.isDisplayed()
} catch(e) { } catch(e) {
return Promise.resolve(false) 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() { async getPopupWarning() {
let element = await driver.findElement(FORM_POPUP) let element = await driver.findElement(FORM_POPUP)
return this.driver.wait(until.elementIsVisible(element), this.timeout, return this.driver.wait(until.elementIsVisible(element), this.timeout,
@ -208,14 +202,37 @@ module.exports = class BasePage {
async waitForDisplayed (locator) { async waitForDisplayed (locator) {
if (this.interactionDelay && this.interactionDelay > 0) await this.driver.sleep(this.interactionDelay) if (this.interactionDelay && this.interactionDelay > 0) await this.driver.sleep(this.interactionDelay)
try { let times = 1
return this.waitForVisible(await this.waitForLocated(locator)) do {
}catch(error) { try {
if (!error.name.includes("NoSuchSessionError")) { return this.waitForVisible(await this.waitForLocated(locator))
console.error("Failed to waitForDisplayed " + locator + " due to " + error) }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) { async getText (locator) {

View File

@ -51,6 +51,9 @@ module.exports = class SSOHomePage extends BasePage {
async getOAuthResourceOptions () { async getOAuthResourceOptions () {
return this.getSelectableOptions(SELECT_RESOURCES) return this.getSelectableOptions(SELECT_RESOURCES)
} }
async isLoginButtonNotVisible() {
return this.waitForNotDisplayed(OAUTH2_LOGIN_BUTTON)
}
async isLoginButtonVisible() { async isLoginButtonVisible() {
try { try {
await this.waitForDisplayed(OAUTH2_LOGIN_BUTTON) await this.waitForDisplayed(OAUTH2_LOGIN_BUTTON)
@ -71,12 +74,18 @@ module.exports = class SSOHomePage extends BasePage {
async isOAuth2SectionVisible() { async isOAuth2SectionVisible() {
return this.isDisplayed(SECTION_LOGIN_WITH_OAUTH) return this.isDisplayed(SECTION_LOGIN_WITH_OAUTH)
} }
async isOAuth2SectionNotVisible() {
return this.waitForNotDisplayed(SECTION_LOGIN_WITH_OAUTH)
}
async getOAuth2Section() { async getOAuth2Section() {
return this.waitForDisplayed(SECTION_LOGIN_WITH_OAUTH) return this.waitForDisplayed(SECTION_LOGIN_WITH_OAUTH)
} }
async isBasicAuthSectionVisible() { async isBasicAuthSectionVisible() {
return this.isDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH) return this.isDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH)
} }
async isBasicAuthSectionNotVisible() {
return this.waitForNotDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH)
}
async getBasicAuthSection() { async getBasicAuthSection() {
return this.waitForDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH) return this.waitForDisplayed(SECTION_LOGIN_WITH_BASIC_AUTH)
} }
@ -104,6 +113,9 @@ module.exports = class SSOHomePage extends BasePage {
return Promise.resolve(false) return Promise.resolve(false)
} }
} }
async isWarningNotVisible () {
return this.waitForNotDisplayed(WARNING)
}
async getWarnings() { async getWarnings() {
try try
{ {

View File

@ -3,15 +3,17 @@ const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const fsp = fs.promises const fsp = fs.promises
const path = require('path') const path = require('path')
const { By, Key, until, Builder, logging, Capabilities } = require('selenium-webdriver') const { By, Key, until, Builder, logging, Capabilities } = require('selenium-webdriver')
const proxy = require('selenium-webdriver/proxy')
require('chromedriver') require('chromedriver')
const UAALoginPage = require('./pageobjects/UAALoginPage') const UAALoginPage = require('./pageobjects/UAALoginPage')
const KeycloakLoginPage = require('./pageobjects/KeycloakLoginPage') const KeycloakLoginPage = require('./pageobjects/KeycloakLoginPage')
const assert = require('assert') const assert = require('assert')
const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false'
const uaaUrl = process.env.UAA_URL || 'http://localhost:8080' const uaaUrl = process.env.UAA_URL || 'http://localhost:8080'
const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL) || 'http://localhost:15672/' const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL) || 'http://localhost:15672/'
//const proxyUrl = calculateProxyUrl(baseUrl)
const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost' 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 seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444'
const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens' const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens'
const profiles = process.env.PROFILES || '' const profiles = process.env.PROFILES || ''
@ -23,6 +25,19 @@ function randomly_pick_baseurl(baseUrl) {
function getRandomInt(max) { function getRandomInt(max) {
return Math.floor(Math.random() * 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 { class CaptureScreenshot {
driver driver
test test
@ -64,10 +79,19 @@ module.exports = {
"--disable-search-engine-choice-screen" "--disable-search-engine-choice-screen"
] ]
}); });
driver = builder
builder = builder
.forBrowser('chrome') .forBrowser('chrome')
.withCapabilities(chromeCapabilities) .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 } ) driver.manage().setTimeouts( { pageLoad: 35000 } )
return driver return driver
}, },