88-export ([get_access_token /2 , get_expiration_time /1 ,
99 refresh_access_token /2 ,
1010 get_oauth_provider /1 , get_oauth_provider /2 ,
11- get_openid_configuration /2 ,
11+ get_openid_configuration /3 ,
1212 build_openid_discovery_endpoint /3 ,
1313 merge_openid_configuration /2 ,
1414 merge_oauth_provider /2 ,
1515 extract_ssl_options_as_list /1 ,
16- format_ssl_options /1 , format_oauth_provider /1 , format_oauth_provider_id /1
16+ map_proxy_auth_to_httpc_option /1 ,
17+ map_proxy_to_httpc_option /1 ,
18+ map_ssl_options_to_httpc_option /1 ,
19+ map_timeout_to_httpc_option /1 ,
20+ format_ssl_options /1 , format_oauth_provider /1 , format_oauth_provider_id /1
1721 ]).
1822
1923-include (" oauth2_client.hrl" ).
@@ -28,10 +32,11 @@ get_access_token(OAuthProvider, Request) ->
2832 Header = [],
2933 Type = ? CONTENT_URLENCODED ,
3034 Body = build_access_token_request_body (Request ),
31- HTTPOptions = get_ssl_options_if_any (OAuthProvider ) ++
32- get_timeout_of_default (Request # access_token_request .timeout ),
33- Options = [],
34- Response = httpc :request (post , {URL , Header , Type , Body }, HTTPOptions , Options ),
35+ HTTPOptions =
36+ map_ssl_options_to_httpc_option (OAuthProvider # oauth_provider .ssl_options ) ++
37+ map_timeout_to_httpc_option (Request # access_token_request .timeout ),
38+ Response = http_post (URL , Header , Type , Body , HTTPOptions ,
39+ OAuthProvider # oauth_provider .proxy_options ),
3540 parse_access_token_response (Response ).
3641
3742-spec refresh_access_token (oauth_provider (), refresh_token_request ()) ->
@@ -42,12 +47,36 @@ refresh_access_token(OAuthProvider, Request) ->
4247 Header = [],
4348 Type = ? CONTENT_URLENCODED ,
4449 Body = build_refresh_token_request_body (Request ),
45- HTTPOptions = get_ssl_options_if_any (OAuthProvider ) ++
46- get_timeout_of_default (Request # refresh_token_request .timeout ),
47- Options = [],
48- Response = httpc :request (post , {URL , Header , Type , Body }, HTTPOptions , Options ),
50+ HTTPOptions =
51+ map_ssl_options_to_httpc_option (OAuthProvider # oauth_provider .ssl_options ) ++
52+ map_timeout_to_httpc_option (Request # refresh_token_request .timeout ),
53+ Response = http_post (URL , Header , Type , Body , HTTPOptions ,
54+ OAuthProvider # oauth_provider .proxy_options ),
4955 parse_access_token_response (Response ).
5056
57+ http_post (URL , Header , Type , Body , HTTPOptions , ProxyOptions ) ->
58+ case ProxyOptions of
59+ undefined -> httpc :request (post , {URL , Header , Type , Body }, HTTPOptions , []);
60+ _ ->
61+ case httpc :set_options (map_proxy_to_httpc_option (ProxyOptions )) of
62+ ok ->
63+ httpc :request (post , {URL , Header , Type , Body },
64+ HTTPOptions ++ map_proxy_auth_to_httpc_option (ProxyOptions ), []);
65+ {error , _ } = Error -> Error
66+ end
67+ end .
68+ http_get (URL , HTTPOptions , ProxyOptions ) ->
69+ case ProxyOptions of
70+ undefined -> httpc :request (get , {URL , []}, HTTPOptions , []);
71+ _ ->
72+ case httpc :set_options (map_proxy_to_httpc_option (ProxyOptions )) of
73+ ok ->
74+ httpc :request (get , {URL , []},
75+ HTTPOptions ++ map_proxy_auth_to_httpc_option (ProxyOptions ), []);
76+ {error , _ } = Error -> Error
77+ end
78+ end .
79+
5180append_paths (Path1 , Path2 ) ->
5281 erlang :iolist_to_binary ([Path1 , Path2 ]).
5382
@@ -94,14 +123,17 @@ drop_trailing_path_separator(Path) when is_list(Path) ->
94123 end .
95124
96125-spec get_openid_configuration (DiscoveryEndpoint :: uri_string :uri_string (),
97- ssl :tls_option () | []) -> {ok , openid_configuration ()} | {error , term ()}.
98- get_openid_configuration (DiscoverEndpoint , TLSOptions ) ->
99- rabbit_log :debug (" get_openid_configuration from ~p (~p )" , [DiscoverEndpoint ,
100- format_ssl_options (TLSOptions )]),
101- Options = [],
102- Response = httpc :request (get , {DiscoverEndpoint , []}, TLSOptions , Options ),
126+ ssl :tls_option () | [], proxy_options () | undefined | 'none' ) ->
127+ {ok , openid_configuration ()} | {error , term ()}.
128+ get_openid_configuration (DiscoverEndpoint , TLSOptions , ProxyOptions ) ->
129+ rabbit_log :debug (" get_openid_configuration from ~p (~p ) [~p ]" , [DiscoverEndpoint ,
130+ format_ssl_options (TLSOptions ), format_proxy_options (ProxyOptions )]),
131+ HTTPOptions =
132+ map_ssl_options_to_httpc_option (TLSOptions ) ++
133+ map_timeout_to_httpc_option (? DEFAULT_HTTP_TIMEOUT ),
134+ Response = http_get (DiscoverEndpoint , HTTPOptions , ProxyOptions ),
103135 parse_openid_configuration_response (Response ).
104-
136+
105137-spec merge_openid_configuration (openid_configuration (), oauth_provider ()) ->
106138 oauth_provider ().
107139merge_openid_configuration (OpenId , OAuthProvider0 ) ->
@@ -283,7 +315,9 @@ download_oauth_provider(OAuthProvider) ->
283315 undefined -> {error , {missing_oauth_provider_attributes , [issuer ]}};
284316 URL ->
285317 rabbit_log :debug (" Downloading oauth_provider using ~p " , [URL ]),
286- case get_openid_configuration (URL , get_ssl_options_if_any (OAuthProvider )) of
318+ case get_openid_configuration (URL ,
319+ OAuthProvider # oauth_provider .ssl_options ,
320+ OAuthProvider # oauth_provider .proxy_options ) of
287321 {ok , OpenIdConfiguration } ->
288322 {ok , update_oauth_provider_endpoints_configuration (
289323 merge_openid_configuration (OpenIdConfiguration , OAuthProvider ))};
@@ -395,8 +429,36 @@ lookup_root_oauth_provider() ->
395429 token_endpoint = get_env (token_endpoint ),
396430 authorization_endpoint = get_env (authorization_endpoint ),
397431 end_session_endpoint = get_env (end_session_endpoint ),
398- ssl_options = extract_ssl_options_as_list (Map )
432+ ssl_options = extract_ssl_options_as_list (Map ),
433+ proxy_options = extract_proxy_options (Map )
399434 }.
435+
436+ -spec extract_proxy_options (#{atom () => any ()}|list ()) -> proxy_options () | undefined .
437+ extract_proxy_options (List ) when is_list (List ) ->
438+ case {proplists :get_value (proxy_host , List , undefined ),
439+ proplists :get_value (proxy_port , List , 0 )} of
440+ {undefined , _ } -> undefined ;
441+ {_ , 0 } -> undefined ;
442+ {H , P } ->
443+ # proxy_options {
444+ host = H ,
445+ port = P ,
446+ username = proplists :get_value (proxy_username , List , undefined ),
447+ password = proplists :get_value (proxy_password , List , undefined )
448+ }
449+ end ;
450+ extract_proxy_options (Map ) ->
451+ case {maps :get (proxy_host , Map , undefined ), maps :get (proxy_port , Map , 0 )} of
452+ {undefined , _ } -> undefined ;
453+ {_ , 0 } -> undefined ;
454+ {H , P } ->
455+ # proxy_options {
456+ host = H ,
457+ port = P ,
458+ username = maps :get (proxy_username , Map , undefined ),
459+ password = maps :get (proxy_password , Map , undefined )
460+ }
461+ end .
400462
401463-spec extract_ssl_options_as_list (#{atom () => any ()}) -> proplists :proplist ().
402464extract_ssl_options_as_list (Map ) ->
@@ -522,17 +584,44 @@ append_extra_parameters(Request, QueryList) ->
522584 Params -> Params ++ QueryList
523585 end .
524586
525- get_ssl_options_if_any ( OAuthProvider ) ->
526- case OAuthProvider # oauth_provider . ssl_options of
587+ map_ssl_options_to_httpc_option ( SslOptions ) ->
588+ case SslOptions of
527589 undefined -> [];
528590 Options -> [{ssl , Options }]
529591 end .
530- get_timeout_of_default (Timeout ) ->
592+
593+ map_timeout_to_httpc_option (Timeout ) ->
531594 case Timeout of
532595 undefined -> [{timeout , ? DEFAULT_HTTP_TIMEOUT }];
533596 Timeout -> [{timeout , Timeout }]
534597 end .
535598
599+ map_proxy_to_httpc_option (ProxyOptions ) ->
600+ case ProxyOptions of
601+ undefined ->
602+ [];
603+ Proxy -> case {Proxy # proxy_options .host , Proxy # proxy_options .port } of
604+ {undefined , 0 } -> [];
605+ {_ , 0 } -> [];
606+ {undefined , _ } -> [];
607+ {Host , Port } ->
608+ P = {{Host , Port },[]},
609+ [{proxy , P }]
610+ end
611+ end .
612+
613+ map_proxy_auth_to_httpc_option (ProxyOptions ) ->
614+ case ProxyOptions of
615+ undefined ->
616+ [];
617+ Proxy ->
618+ case {Proxy # proxy_options .username , Proxy # proxy_options .password } of
619+ {undefined , _ } -> [];
620+ {_ , undefined } -> [];
621+ {_ , _ } = Auth -> [{proxy_auth , Auth }]
622+ end
623+ end .
624+
536625is_json (? CONTENT_JSON ) -> true ;
537626is_json (_ ) -> false .
538627
@@ -588,7 +677,9 @@ map_to_oauth_provider(PropList) when is_list(PropList) ->
588677 proplists :get_value (jwks_uri , PropList , undefined ),
589678 ssl_options =
590679 extract_ssl_options_as_list (maps :from_list (
591- proplists :get_value (https , PropList , [])))
680+ proplists :get_value (https , PropList , []))),
681+ proxy_options =
682+ extract_proxy_options (PropList )
592683 }.
593684map_to_access_token_response (Code , Reason , Headers , Body ) ->
594685 case decode_body (proplists :get_value (" content-type" , Headers , ? CONTENT_JSON ), Body ) of
@@ -626,6 +717,18 @@ format_ssl_options(TlsOptions) ->
626717 proplists :get_value (cacertfile , TlsOptions ),
627718 CaCertsCount ])).
628719
720+ -spec format_proxy_options (proxy_options ()|undefined ) -> string ().
721+ format_proxy_options (undefined ) ->
722+ lists :flatten (io_lib :format (" {no proxy}" , []));
723+
724+ format_proxy_options (ProxyOptions ) ->
725+ lists :flatten (io_lib :format (" {host: ~p , port: ~p , username: ~p , " ++
726+ " password: ~p }" , [
727+ ProxyOptions # proxy_options .host ,
728+ ProxyOptions # proxy_options .port ,
729+ ProxyOptions # proxy_options .username ,
730+ ProxyOptions # proxy_options .password ])).
731+
629732format_oauth_provider_id (root ) -> " <from keyconfig>" ;
630733format_oauth_provider_id (Id ) -> binary_to_list (Id ).
631734
@@ -634,15 +737,16 @@ format_oauth_provider(OAuthProvider) ->
634737 lists :flatten (io_lib :format (" {id: ~p , issuer: ~p , discovery_endpoint: ~p , " ++
635738 " token_endpoint: ~p , " ++
636739 " authorization_endpoint: ~p , end_session_endpoint: ~p , " ++
637- " jwks_uri: ~p , ssl_options: ~p }" , [
740+ " jwks_uri: ~p , ssl_options: ~p , proxy_options: ~p }" , [
638741 format_oauth_provider_id (OAuthProvider # oauth_provider .id ),
639742 OAuthProvider # oauth_provider .issuer ,
640743 OAuthProvider # oauth_provider .discovery_endpoint ,
641744 OAuthProvider # oauth_provider .token_endpoint ,
642745 OAuthProvider # oauth_provider .authorization_endpoint ,
643746 OAuthProvider # oauth_provider .end_session_endpoint ,
644747 OAuthProvider # oauth_provider .jwks_uri ,
645- format_ssl_options (OAuthProvider # oauth_provider .ssl_options )])).
748+ format_ssl_options (OAuthProvider # oauth_provider .ssl_options ),
749+ format_proxy_options (OAuthProvider # oauth_provider .proxy_options )])).
646750
647751get_env (Par ) ->
648752 application :get_env (rabbitmq_auth_backend_oauth2 , Par , undefined ).
0 commit comments