summaryrefslogtreecommitdiff
path: root/components/authorize/src/authorize_sig.erl
blob: c69bbd025f9da8238af7d06e01f84e3a71c1704c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
-module(authorize_sig).

-compile(export_all).

-include_lib("lager/include/log.hrl").
-define(DIGEST_TYPE, sha256).

%% Inspired by
%% http://blog.differentpla.net/blog/2015/04/19/jwt-rs256-erlang/

decode_jwt(JWT, PubKey) when is_list(JWT)->
    decode_jwt(list_to_binary(JWT), PubKey);

decode_jwt(JWT, PubKey) when is_binary(JWT)->
    ?debug("authorize_sig:decode_jwt(JWT, PubKey=~s)~n", [authorize_keys:pp_key(PubKey)]),
    [H, P, S] = binary:split(JWT, <<".">>, [global]),
    Header = decode_json(base64url:decode(H)),
    Payload = decode_json(base64url:decode(P)),
    ?debug("JWT Header = ~p~nPayload: ~p~n", [Header, authorize_keys:abbrev_payload(Payload)]),
    Signature = base64url:decode(S),
    SigningInput = <<H/binary, ".", P/binary>>,
    Res = case public_key:verify(
		 SigningInput, ?DIGEST_TYPE, Signature, PubKey) of
	      false ->
		  ?debug("public_key:verify() -> false~n", []),
		  invalid;
	      true ->
		  {Header, Payload}
	  end,
    ?debug("decoded JWT = ~p~n", [authorize_keys:abbrev_jwt(Res)]),
    Res.

encode_jwt(JSON, PrivKey) ->
    encode_jwt(JSON, header(), PrivKey).

encode_jwt(Payload0, Header0, PrivKey) ->
    ?debug("encode_jwt()", []),
    Header = base64url:encode(ensure_json(Header0)),
    Payload = base64url:encode(ensure_json(Payload0)),
    SigningInput = <<Header/binary, ".", Payload/binary>>,
    Signature = base64url:encode(
		  public_key:sign(SigningInput, ?DIGEST_TYPE, PrivKey)),
    <<SigningInput/binary, ".", Signature/binary>>.

header() ->
    "{\"alg\": \"RS256\"}".

ensure_json("{" ++ _ = JSON) ->
    list_to_binary(JSON);
ensure_json(<<"{", _/binary>> = JSON) ->
    JSON;
ensure_json({struct, _} = JSON) ->
    list_to_binary(exo_json:encode(JSON));
ensure_json([_|_] = JSON) ->
    %% Since there may be atoms
    {ok, Normalized} = msgpack:unpack(msgpack:pack(JSON, [jsx,
							  {allow_atom,pack}]), [jsx]),
    ?debug("Normalized = ~p~n", [authorize_keys:abbrev_payload(Normalized)]),
    jsx:encode(Normalized).

decode_json(JSON) when is_list(JSON) ->
    jsx:decode(iolist_to_binary(JSON));
decode_json(JSON) when is_binary(JSON) ->
    jsx:decode(JSON).