aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Bracco <href@random.sh>2021-09-03 22:47:55 +0200
committerJordan Bracco <href@random.sh>2021-09-03 22:47:55 +0200
commit023fcf384bc89b861f51c81a20a5aefea8afe772 (patch)
tree52c8aa95835acea5fbcb664d8e3f92c4e1e90316
parentvarious small fixes (diff)
userinfo endpointHEADmain
-rw-r--r--apps/ory/src/ory_hydra.erl6
-rw-r--r--apps/ory/src/ory_kratos.erl17
-rw-r--r--apps/styx_web/src/styx_web_app.erl1
-rw-r--r--apps/styx_web/src/styx_web_userinfo.erl35
-rw-r--r--config/sys.config11
5 files changed, 64 insertions, 6 deletions
diff --git a/apps/ory/src/ory_hydra.erl b/apps/ory/src/ory_hydra.erl
index 8902c98..47b6601 100644
--- a/apps/ory/src/ory_hydra.erl
+++ b/apps/ory/src/ory_hydra.erl
@@ -1,5 +1,5 @@
-module(ory_hydra).
--export([url/0, admin_url/0, login_request/1, accept_login_request/2, consent_request/1, accept_consent_request/2, reject_consent_request/2]).
+-export([url/0, admin_url/0, userinfo/1, login_request/1, accept_login_request/2, consent_request/1, accept_consent_request/2, reject_consent_request/2]).
login_request(Challenge) ->
Url = [admin_url(), "/oauth2/auth/requests/login?login_challenge=", Challenge],
@@ -29,6 +29,10 @@ reject_consent_request(Challenge, Data) ->
Json = jsone:encode(Data),
api_response(hackney:request(put, Url, Headers, Json, [])).
+userinfo(Authorization) ->
+ Url = [url(), "/userinfo"],
+ Headers = [{"accept", "application/json"}, {"authorization", Authorization}],
+ api_response(hackney:request(get, Url, Headers, <<>>, [])).
admin_url() ->
{ok, Value} = application:get_env(ory, hydra_admin_url),
diff --git a/apps/ory/src/ory_kratos.erl b/apps/ory/src/ory_kratos.erl
index 02a85a0..1d4c5a1 100644
--- a/apps/ory/src/ory_kratos.erl
+++ b/apps/ory/src/ory_kratos.erl
@@ -1,7 +1,8 @@
-module(ory_kratos).
--export([login_url/1, registration_url/1, settings_url/1, recovery_url/1, verification_url/1, url/0]).
+-export([login_url/1, registration_url/1, settings_url/1, recovery_url/1, verification_url/1, url/0, admin_url/0]).
-export([registration_flow/2, login_flow/2, settings_flow/2, recovery_flow/2, verification_flow/2, logout_flow/1, whoami/1, error/1]).
+-export([get_identity/1]).
login_url(browser) ->
[url(), "/self-service/login/browser"].
@@ -22,6 +23,10 @@ url() ->
{ok, Value} = application:get_env(ory, kratos_url),
Value.
+admin_url() ->
+ {ok, Value} = application:get_env(ory, kratos_admin_url),
+ Value.
+
registration_flow(Cookie, Id) ->
Url = [url(), "/self-service/registration/flows?id=", Id],
Headers = [{<<"cookie">>, Cookie}, {"accept", "application/json"}],
@@ -59,9 +64,13 @@ whoami(Cookie) ->
error(Id) ->
Url = [url(), "/self-service/errors?id=", Id],
- {ok, 200, _, Client} = hackney:request(get, Url, [], <<>>, []),
- {ok, Body} = hackney:body(Client),
- {ok, jsone:decode(Body)}.
+ Headers = [{"accept", "application/json"}],
+ api_response(hackney:request(get, Url, Headers, <<>>, [])).
+
+get_identity(Id) ->
+ Url = [admin_url(), "/identities/", Id],
+ Headers = [{"accept", "application/json"}],
+ api_response(hackney:request(get, Url, Headers, <<>>, [])).
api_response(Error = {error, Error}) ->
logger:error("ory_kratos hackney error: ~p", [Error]),
diff --git a/apps/styx_web/src/styx_web_app.erl b/apps/styx_web/src/styx_web_app.erl
index 39ce39b..ce2f29f 100644
--- a/apps/styx_web/src/styx_web_app.erl
+++ b/apps/styx_web/src/styx_web_app.erl
@@ -29,6 +29,7 @@ routes() ->
%% App
{"/", styx_web_index, undefined},
{"/launchpad", styx_web_launchpad, undefined},
+ {"/userinfo", styx_web_userinfo, undefined},
%% Kratos
{"/login", styx_web_kratos_flow, #{page_title => "Login", template => login_dtl, getflowmf => {ory_kratos, login_flow}, initflowmf => {ory_kratos, login_url}}},
diff --git a/apps/styx_web/src/styx_web_userinfo.erl b/apps/styx_web/src/styx_web_userinfo.erl
new file mode 100644
index 0000000..2875898
--- /dev/null
+++ b/apps/styx_web/src/styx_web_userinfo.erl
@@ -0,0 +1,35 @@
+-module(styx_web_userinfo).
+-behaviour(cowboy_handler).
+-export([init/2]).
+
+init(Req = #{method := <<"GET">>}, State) ->
+ get(Req, State);
+init(Req, _) ->
+ styx_web_error:init(Req, #{code => 404, status => <<"Not Found">>}).
+
+get(Req, State) ->
+ Authorization = cowboy_req:header(<<"authorization">>, Req),
+ case ory_hydra:userinfo(Authorization) of
+ {ok, UserInfo} ->
+ get_identity(Req, UserInfo, State)
+ end.
+
+get_identity(Req, UserInfo = #{<<"sub">> := Id}, State) ->
+ case ory_kratos:get_identity(Id) of
+ {ok, Identity} -> process(Req, UserInfo, Identity, State)
+ end.
+
+process(Req, UserInfo, #{<<"traits">> := Traits, <<"schema_id">> := Schema}, State) ->
+ Mapper = maps:get(Schema, application:get_env(styx, openid_userinfo_mapper, #{})),
+ MapFun = fun(Key, Value, Acc) -> maps:put(Key, get_value(Traits, Value), Acc) end,
+ Data = maps:fold(MapFun, #{}, Mapper),
+ MergedData = maps:merge(UserInfo, Data),
+ Headers = #{<<"content-type">> => <<"application/json">>},
+ cowboy_req:reply(200, Headers, jsone:encode(MergedData), Req).
+
+get_value(Traits, Value) when is_binary(Value) ->
+ maps:get(Value, Traits);
+get_value(Traits, [Value | Acc]) ->
+ get_value(maps:get(Value, Traits), Acc);
+get_value(Value, []) ->
+ Value.
diff --git a/config/sys.config b/config/sys.config
index 60a32cb..4c51865 100644
--- a/config/sys.config
+++ b/config/sys.config
@@ -1,6 +1,15 @@
[
{kernel, [{logger_level, debug}]},
- {styx, []},
+ {styx, [
+ {openid_userinfo_mapper, #{
+ <<"default">> => #{
+ <<"preferred_username">> => <<"username">>,
+ <<"email">> => <<"email">>,
+ <<"given_name">> => [<<"name">>, <<"first">>],
+ <<"family_name">> => [<<"name">>, <<"last">>]
+ }
+ }}
+ ]},
{ory, [
{kratos_url, <<"http://127.0.0.1:4433">>},
{kratos_admin_url, <<"http://127.0.0.1:4434">>},