|
8 | 8 | -export([get_access_token/2, get_expiration_time/1, |
9 | 9 | refresh_access_token/2, |
10 | 10 | get_oauth_provider/1, get_oauth_provider/2, |
11 | | - get_openid_configuration/2, get_openid_configuration/3, |
| 11 | + get_openid_configuration/2, |
| 12 | + build_openid_discovery_endpoint/3, build_openid_discovery_endpoint/1, |
| 13 | + build_openid_discovery_endpoint/2, |
12 | 14 | merge_openid_configuration/2, |
13 | 15 | merge_oauth_provider/2, |
14 | 16 | extract_ssl_options_as_list/1, |
@@ -47,28 +49,64 @@ refresh_access_token(OAuthProvider, Request) -> |
47 | 49 | append_paths(Path1, Path2) -> |
48 | 50 | erlang:iolist_to_binary([Path1, Path2]). |
49 | 51 |
|
50 | | --spec get_openid_configuration(uri_string:uri_string(), erlang:iodata() | <<>>, |
| 52 | +-spec build_openid_discovery_endpoint(Issuer :: uri_string:uri_string()) |
| 53 | + -> uri_string:uri_string(). |
| 54 | +build_openid_discovery_endpoint(Issuer) -> |
| 55 | + build_openid_discovery_endpoint(Issuer, undefined, undefined). |
| 56 | + |
| 57 | +-spec build_openid_discovery_endpoint(Issuer :: uri_string:uri_string(), |
| 58 | + OpenIdConfigurationPath :: uri_string:uri_string() | undefined) |
| 59 | + -> uri_string:uri_string(). |
| 60 | +build_openid_discovery_endpoint(Issuer, OpenIdConfigurationPath) -> |
| 61 | + build_openid_discovery_endpoint(Issuer, OpenIdConfigurationPath, undefined). |
| 62 | + |
| 63 | +-spec build_openid_discovery_endpoint(Issuer :: uri_string:uri_string(), |
| 64 | + OpenIdConfigurationPath :: uri_string:uri_string() | undefined, |
| 65 | + Params :: query_list()) -> uri_string:uri_string(). |
| 66 | + |
| 67 | +build_openid_discovery_endpoint(Issuer, undefined, Params) -> |
| 68 | + build_openid_discovery_endpoint(Issuer, ?DEFAULT_OPENID_CONFIGURATION_PATH, |
| 69 | + Params); |
| 70 | +build_openid_discovery_endpoint(Issuer, OpenIdConfigurationPath, Params) -> |
| 71 | + URLMap0 = uri_string:parse(Issuer), |
| 72 | + OpenIdPath = ensure_leading_path_separator(OpenIdConfigurationPath), |
| 73 | + URLMap1 = URLMap0#{ |
| 74 | + path := case maps:get(path, URLMap0) of |
| 75 | + "/" -> OpenIdPath; |
| 76 | + "" -> OpenIdPath; |
| 77 | + [] -> OpenIdPath; |
| 78 | + P -> append_paths(drop_trailing_path_separator(P), OpenIdPath) |
| 79 | + end |
| 80 | + }, |
| 81 | + uri_string:recompose( |
| 82 | + case {Params, maps:get(query, URLMap1, undefined)} of |
| 83 | + {undefined, undefined} -> |
| 84 | + URLMap1; |
| 85 | + {_, undefined} -> |
| 86 | + URLMap1#{query => uri_string:compose_query(Params)}; |
| 87 | + {_, Q} -> |
| 88 | + URLMap1#{query => uri_string:compose_query(Q ++ Params)} |
| 89 | + end). |
| 90 | +ensure_leading_path_separator(Path) -> |
| 91 | + case string:slice(Path, 0, 1) of |
| 92 | + "/" -> Path; |
| 93 | + _ -> "/" ++ Path |
| 94 | + end. |
| 95 | +drop_trailing_path_separator(Path) -> |
| 96 | + case string:slice(Path, string:len(Path)-1, 1) of |
| 97 | + "/" -> lists:droplast(Path); |
| 98 | + _ -> Path |
| 99 | + end. |
| 100 | + |
| 101 | +-spec get_openid_configuration(DiscoveryEndpoint :: uri_string:uri_string(), |
51 | 102 | ssl:tls_option() | []) -> {ok, openid_configuration()} | {error, term()}. |
52 | | -get_openid_configuration(IssuerURI, OpenIdConfigurationPath, TLSOptions) -> |
53 | | - URLMap = uri_string:parse(IssuerURI), |
54 | | - Path = case maps:get(path, URLMap) of |
55 | | - "/" -> OpenIdConfigurationPath; |
56 | | - "" -> OpenIdConfigurationPath; |
57 | | - P -> append_paths(P, OpenIdConfigurationPath) |
58 | | - end, |
59 | | - URL = uri_string:resolve(Path, IssuerURI), |
60 | | - rabbit_log:debug("get_openid_configuration issuer URL ~p (~p)", [URL, |
| 103 | +get_openid_configuration(DiscoverEndpoint, TLSOptions) -> |
| 104 | + rabbit_log:debug("get_openid_configuration from ~p (~p)", [DiscoverEndpoint, |
61 | 105 | format_ssl_options(TLSOptions)]), |
62 | 106 | Options = [], |
63 | | - Response = httpc:request(get, {URL, []}, TLSOptions, Options), |
| 107 | + Response = httpc:request(get, {DiscoverEndpoint, []}, TLSOptions, Options), |
64 | 108 | parse_openid_configuration_response(Response). |
65 | 109 |
|
66 | | --spec get_openid_configuration(uri_string:uri_string(), ssl:tls_option() | []) -> |
67 | | - {ok, openid_configuration()} | {error, term()}. |
68 | | -get_openid_configuration(IssuerURI, TLSOptions) -> |
69 | | - get_openid_configuration(IssuerURI, ?DEFAULT_OPENID_CONFIGURATION_PATH, TLSOptions). |
70 | | -% Returns {ok, with_modidified_oauth_provider} or {ok} if oauth_provider was |
71 | | -% not modified |
72 | 110 | -spec merge_openid_configuration(openid_configuration(), oauth_provider()) -> |
73 | 111 | oauth_provider(). |
74 | 112 | merge_openid_configuration(OpendIdConfiguration, OAuthProvider) -> |
@@ -179,43 +217,37 @@ update_oauth_provider_endpoints_configuration(OAuthProviderId, OAuthProvider) -> |
179 | 217 |
|
180 | 218 | do_update_oauth_provider_endpoints_configuration(OAuthProvider) -> |
181 | 219 | case OAuthProvider#oauth_provider.token_endpoint of |
182 | | - undefined -> |
183 | | - do_nothing; |
184 | | - TokenEndpoint -> |
185 | | - application:set_env(rabbitmq_auth_backend_oauth2, token_endpoint, TokenEndpoint) |
| 220 | + undefined -> do_nothing; |
| 221 | + TokenEndpoint -> set_env(token_endpoint, TokenEndpoint) |
186 | 222 | end, |
187 | 223 | case OAuthProvider#oauth_provider.authorization_endpoint of |
188 | | - undefined -> |
189 | | - do_nothing; |
190 | | - AuthzEndpoint -> |
191 | | - application:set_env(rabbitmq_auth_backend_oauth2, authorization_endpoint, AuthzEndpoint) |
| 224 | + undefined -> do_nothing; |
| 225 | + AuthzEndpoint -> set_env(authorization_endpoint, AuthzEndpoint) |
192 | 226 | end, |
193 | 227 | case OAuthProvider#oauth_provider.end_session_endpoint of |
194 | | - undefined -> |
195 | | - do_nothing; |
196 | | - EndSessionEndpoint -> |
197 | | - application:set_env(rabbitmq_auth_backend_oauth2, end_session_endpoint, EndSessionEndpoint) |
| 228 | + undefined -> do_nothing; |
| 229 | + EndSessionEndpoint -> set_env(end_session_endpoint, EndSessionEndpoint) |
198 | 230 | end, |
199 | | - List = application:get_env(rabbitmq_auth_backend_oauth2, key_config, []), |
| 231 | + List = get_env(key_config, []), |
200 | 232 | ModifiedList = case OAuthProvider#oauth_provider.jwks_uri of |
201 | 233 | undefined -> List; |
202 | 234 | JwksEndPoint -> [{jwks_url, JwksEndPoint} | proplists:delete(jwks_url, List)] |
203 | 235 | end, |
204 | | - application:set_env(rabbitmq_auth_backend_oauth2, key_config, ModifiedList), |
| 236 | + set_env(key_config, ModifiedList), |
205 | 237 | rabbit_log:debug("Updated oauth_provider details: ~p ", [ format_oauth_provider(OAuthProvider)]), |
206 | 238 | OAuthProvider. |
207 | 239 |
|
208 | 240 | do_update_oauth_provider_endpoints_configuration(OAuthProviderId, OAuthProvider) -> |
209 | | - OAuthProviders = application:get_env(rabbitmq_auth_backend_oauth2, oauth_providers, #{}), |
| 241 | + OAuthProviders = get_env(oauth_providers, #{}), |
210 | 242 | Proplist = maps:get(OAuthProviderId, OAuthProviders), |
211 | 243 | ModifiedOAuthProviders = maps:put(OAuthProviderId, |
212 | 244 | merge_oauth_provider(OAuthProvider, Proplist), OAuthProviders), |
213 | | - application:set_env(rabbitmq_auth_backend_oauth2, oauth_providers, ModifiedOAuthProviders), |
| 245 | + set_env(oauth_providers, ModifiedOAuthProviders), |
214 | 246 | rabbit_log:debug("Replaced oauth_providers "), |
215 | 247 | OAuthProvider. |
216 | 248 |
|
217 | 249 | use_global_locks_on_all_nodes() -> |
218 | | - case application:get_env(rabbitmq_auth_backend_oauth2, use_global_locks, true) of |
| 250 | + case get_env(use_global_locks, true) of |
219 | 251 | true -> {rabbit_nodes:list_running(), rabbit_nodes:lock_retries()}; |
220 | 252 | _ -> {} |
221 | 253 | end. |
@@ -246,7 +278,7 @@ unlock(LockId) -> |
246 | 278 |
|
247 | 279 | -spec get_oauth_provider(list()) -> {ok, oauth_provider()} | {error, any()}. |
248 | 280 | get_oauth_provider(ListOfRequiredAttributes) -> |
249 | | - case application:get_env(rabbitmq_auth_backend_oauth2, default_oauth_provider) of |
| 281 | + case get_env(default_oauth_provider) of |
250 | 282 | undefined -> get_oauth_provider_from_keyconfig(ListOfRequiredAttributes); |
251 | 283 | {ok, DefaultOauthProviderId} -> |
252 | 284 | rabbit_log:debug("Using default_oauth_provider ~p", [DefaultOauthProviderId]), |
@@ -359,18 +391,18 @@ find_missing_attributes(#oauth_provider{} = OAuthProvider, RequiredAttributes) - |
359 | 391 | intersection(Filtered, RequiredAttributes). |
360 | 392 |
|
361 | 393 | lookup_oauth_provider_from_keyconfig() -> |
362 | | - Issuer = application:get_env(rabbitmq_auth_backend_oauth2, issuer, undefined), |
363 | | - TokenEndpoint = application:get_env(rabbitmq_auth_backend_oauth2, token_endpoint, undefined), |
364 | | - AuthorizationEndpoint = application:get_env(rabbitmq_auth_backend_oauth2, authorization_endpoint, undefined), |
365 | | - EndSessionEndpoint = application:get_env(rabbitmq_auth_backend_oauth2, end_session_endpoint, undefined), |
366 | | - Map = maps:from_list(application:get_env(rabbitmq_auth_backend_oauth2, key_config, [])), |
| 394 | + Map = maps:from_list(get_env(key_config, [])), |
| 395 | + Issuer = get_env(issuer), |
| 396 | + DiscoverEndpoint = build_openid_discovery_endpoint(Issuer, |
| 397 | + get_env(discovery_endpoint_path), get_env(discovery_endpoint_params)), |
367 | 398 | #oauth_provider{ |
368 | 399 | id = root, |
369 | 400 | issuer = Issuer, |
| 401 | + discovery_endpoint = DiscoverEndpoint, |
370 | 402 | jwks_uri = maps:get(jwks_url, Map, undefined), %% jwks_url not uri . _url is the legacy name |
371 | | - token_endpoint = TokenEndpoint, |
372 | | - authorization_endpoint = AuthorizationEndpoint, |
373 | | - end_session_endpoint = EndSessionEndpoint, |
| 403 | + token_endpoint = get_env(token_endpoint), |
| 404 | + authorization_endpoint = get_env(authorization_endpoint), |
| 405 | + end_session_endpoint = get_env(end_session_endpoint), |
374 | 406 | ssl_options = extract_ssl_options_as_list(Map) |
375 | 407 | }. |
376 | 408 |
|
@@ -431,7 +463,7 @@ get_verify_or_peer_verification(Ssl_options, Default) -> |
431 | 463 | end. |
432 | 464 |
|
433 | 465 | lookup_oauth_provider_config(OAuth2ProviderId) -> |
434 | | - case application:get_env(rabbitmq_auth_backend_oauth2, oauth_providers) of |
| 466 | + case get_env(oauth_providers) of |
435 | 467 | undefined -> {error, oauth_providers_not_found}; |
436 | 468 | {ok, MapOfProviders} when is_map(MapOfProviders) -> |
437 | 469 | case maps:get(OAuth2ProviderId, MapOfProviders, undefined) of |
@@ -522,14 +554,28 @@ map_to_unsuccessful_access_token_response(Map) -> |
522 | 554 | error_description = maps:get(?RESPONSE_ERROR_DESCRIPTION, Map, undefined) |
523 | 555 | }. |
524 | 556 | map_to_oauth_provider(PropList) when is_list(PropList) -> |
| 557 | + Issuer = proplists:get_value(issuer, PropList), |
| 558 | + DiscoveryEndpoint = build_openid_discovery_endpoint(Issuer, |
| 559 | + proplists:get_value(discovery_endpoint_path, PropList), |
| 560 | + proplists:get_value(discovery_endpoint_params, PropList)), |
525 | 561 | #oauth_provider{ |
526 | | - id = proplists:get_value(id, PropList), |
527 | | - issuer = proplists:get_value(issuer, PropList), |
528 | | - token_endpoint = proplists:get_value(token_endpoint, PropList), |
529 | | - authorization_endpoint = proplists:get_value(authorization_endpoint, PropList, undefined), |
530 | | - end_session_endpoint = proplists:get_value(end_session_endpoint, PropList, undefined), |
531 | | - jwks_uri = proplists:get_value(jwks_uri, PropList, undefined), |
532 | | - ssl_options = extract_ssl_options_as_list(maps:from_list(proplists:get_value(https, PropList, []))) |
| 562 | + id = |
| 563 | + proplists:get_value(id, PropList), |
| 564 | + issuer = |
| 565 | + Issuer, |
| 566 | + discovery_endpoint = |
| 567 | + DiscoveryEndpoint, |
| 568 | + token_endpoint = |
| 569 | + proplists:get_value(token_endpoint, PropList), |
| 570 | + authorization_endpoint = |
| 571 | + proplists:get_value(authorization_endpoint, PropList, undefined), |
| 572 | + end_session_endpoint = |
| 573 | + proplists:get_value(end_session_endpoint, PropList, undefined), |
| 574 | + jwks_uri = |
| 575 | + proplists:get_value(jwks_uri, PropList, undefined), |
| 576 | + ssl_options = |
| 577 | + extract_ssl_options_as_list(maps:from_list( |
| 578 | + proplists:get_value(https, PropList, []))) |
533 | 579 | }. |
534 | 580 | map_to_access_token_response(Code, Reason, Headers, Body) -> |
535 | 581 | case decode_body(proplists:get_value("content-type", Headers, ?CONTENT_JSON), Body) of |
@@ -581,3 +627,10 @@ format_oauth_provider(OAuthProvider) -> |
581 | 627 | OAuthProvider#oauth_provider.end_session_endpoint, |
582 | 628 | OAuthProvider#oauth_provider.jwks_uri, |
583 | 629 | format_ssl_options(OAuthProvider#oauth_provider.ssl_options)])). |
| 630 | + |
| 631 | +get_env(Par) -> |
| 632 | + application:get_env(rabbitmq_auth_backend_oauth2, Par, undefined). |
| 633 | +get_env(Par, Def) -> |
| 634 | + application:get_env(rabbitmq_auth_backend_oauth2, Par, Def). |
| 635 | +set_env(Par, Val) -> |
| 636 | + application:set_env(rabbitmq_auth_backend_oauth2, Par, Val). |
0 commit comments