Packages
oidcc
1.5.1
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
retired
3.4.0
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.2.0-beta.3
3.2.0-beta.2
retired
3.2.0-beta.1
retired
3.1.2
3.1.2-beta.1
retired
3.1.1
retired
3.1.0
retired
3.1.0-beta.2
retired
3.1.0-beta.1
retired
3.0.2
3.0.1
retired
3.0.0
retired
3.0.0-rc.6
retired
3.0.0-rc.5
retired
3.0.0-rc.4
retired
3.0.0-rc.3
retired
3.0.0-rc.2
retired
3.0.0-rc.1
retired
3.0.0-alpha.5
retired
3.0.0-alpha.4
retired
3.0.0-alpha.3
retired
3.0.0-alpha.2
retired
3.0.0-alpha.1
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
1.8.1
retired
1.8.0
retired
1.7.0
retired
1.6.0
retired
1.5.1
retired
1.5.0
retired
1.4.0
retired
1.3.0
retired
1.2.1
retired
1.2.0
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
OpenID Connect client library for the BEAM.
Retired package: Deprecated - Unmaintained major version, update
Current section
Files
Jump to
Current section
Files
src/oidcc_session.erl
-module(oidcc_session).
-behaviour(gen_server).
%% API.
-export([start_link/3]).
-export([start_link/4]).
-export([is_user_agent/2]).
-export([is_cookie_data/2]).
-export([is_peer_ip/2]).
-export([get_id/1]).
-export([get_provider/1]).
-export([get_scopes/1]).
-export([get_nonce/1]).
-export([get_pkce/1]).
-export([get_peer_ip/1]).
-export([get_user_agent/1]).
-export([get_cookie_data/1]).
-export([get_client_mod/1]).
-export([set_user_agent/2]).
-export([set_cookie_data/2]).
-export([set_peer_ip/2]).
-export([set_client_mod/2]).
-export([close/1]).
%% gen_server.
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).
-record(state, {
id = undefined,
timeout = undefined,
data = #{}
}).
%% API.
start_link(Id, Nonce, ProviderId) ->
{ok, Config} = oidcc:get_openid_provider_info(ProviderId),
Scopes = maps:get(request_scopes, Config),
start_link(Id, Nonce, ProviderId, Scopes).
start_link(Id, Nonce, ProviderId, Scopes0) ->
Scopes = case Scopes0 of
undefined -> application:get_env(oidcc, scopes, [openid]);
_ -> Scopes0
end,
Pkce = generate_pkce_if_supported(ProviderId),
gen_server:start_link(?MODULE, {Id, Nonce, Pkce, ProviderId, Scopes}, []).
-spec close(Pid ::pid()) -> ok.
close(Pid) ->
gen_server:cast(Pid, close).
is_user_agent(UserAgent, Pid) ->
gen_server:call(Pid, {is, user_agent, UserAgent}).
is_cookie_data(CookieData, Pid) ->
gen_server:call(Pid, {is, cookie_data, CookieData}).
is_peer_ip(PeerIp, Pid) ->
gen_server:call(Pid, {is, peer_ip, PeerIp}).
get_id(Pid) ->
gen_server:call(Pid, get_id).
get_provider(Pid) ->
gen_server:call(Pid, {get, provider}).
get_scopes(Pid) ->
gen_server:call(Pid, {get, scopes}).
get_nonce(Pid) ->
gen_server:call(Pid, {get, nonce}).
get_pkce(Pid) ->
gen_server:call(Pid, {get, pkce}).
get_peer_ip(Pid) ->
gen_server:call(Pid, {get, peer_ip}).
get_user_agent(Pid) ->
gen_server:call(Pid, {get, user_agent}).
get_cookie_data(Pid) ->
gen_server:call(Pid, {get, cookie_data}).
get_client_mod(Pid) ->
gen_server:call(Pid, {get, client_mod}).
set_user_agent(UserAgent, Pid) ->
gen_server:call(Pid, {set, user_agent, UserAgent}).
set_peer_ip(PeerIp, Pid) ->
gen_server:call(Pid, {set, peer_ip, PeerIp }).
set_cookie_data(CookieData, Pid) ->
gen_server:call(Pid, {set, cookie_data, CookieData }).
set_client_mod(ClientMod, Pid) ->
gen_server:call(Pid, {set, client_mod, ClientMod }).
%% gen_server.
init({Id, Nonce, Pkce, ProviderId, Scopes}) ->
Timeout = application:get_env(oidcc, session_timeout, 300000),
Map = #{nonce => Nonce, scopes => Scopes, pkce => Pkce,
provider => ProviderId},
{ok, #state{id = Id, data = Map, timeout=Timeout}, Timeout}.
handle_call({get, Field}, _From, #state{data=Map, timeout=To} = State) ->
Value = maps:get(Field, Map, undefined),
{reply, {ok, Value}, State, To};
handle_call({set, Field, Value}, _From, #state{data=Map, timeout=To} = State) ->
NewMap = maps:put(Field, Value, Map),
{reply, ok, State#state{data=NewMap}, To};
handle_call({is, Field, InVal}, _From, #state{data=Map, timeout=To} = State) ->
Value = maps:get(Field, Map, undefined),
{reply, InVal == Value, State, To};
handle_call(get_id, _From, #state{id=Id, timeout=To} = State) ->
{reply, {ok, Id}, State, To};
handle_call(_Request, _From, #state{timeout=To} = State) ->
{reply, ignored, State, To}.
handle_cast(close, #state{id = Id} = State) ->
ok = oidcc_session_mgr:session_terminating(Id),
{stop, normal, State};
handle_cast(_Request, #state{timeout = To} = State) ->
{noreply, State, To}.
handle_info(timeout, #state{id = Id} = State) ->
ok = oidcc_session_mgr:session_terminating(Id),
{stop, normal, State};
handle_info(_Info, #state{timeout=To} = State) ->
{noreply, State, To}.
terminate(normal, _State) ->
ok;
terminate(_Reason, #state{id = Id}) ->
oidcc_session_mgr:session_terminating(Id),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
generate_pkce_if_supported(ProviderId) ->
{ok, Config} = oidcc:get_openid_provider_info(ProviderId),
UsePkce = maps:is_key(code_challenge_methods_supported, Config),
Methods = maps:get(code_challenge_methods_supported, Config, [<<"S256">>]),
generate_pkce(UsePkce, Methods).
generate_pkce(true, Methods) ->
CodeVerifier = gen_code_verifier(),
UseS256 = lists:member(<<"S256">>, Methods),
apply_s256(UseS256, CodeVerifier);
generate_pkce(_, _) ->
undefined.
apply_s256(true, CodeVerifier) ->
#{
verifier => CodeVerifier,
challenge => base64url:encode(crypto:hash(sha256, CodeVerifier)),
method => 'S256'
};
apply_s256(_, CodeVerifier) ->
#{
verifier => CodeVerifier,
challenge => CodeVerifier,
method => plain
}.
gen_code_verifier() ->
base64:encode(crypto:strong_rand_bytes(64)).