Add support for solving http-01 challenge

This commit is contained in:
Konstantinos Kallas 2017-06-18 13:20:47 +03:00
parent 1d1250b056
commit dc4c00a78c
2 changed files with 57 additions and 7 deletions

View File

@ -1,6 +1,6 @@
-module(acme_challenge).
-export ([ key_authorization/2
-export ([ key_authorization/2
, solve_challenge/3
]).
%% Challenge Types
@ -16,7 +16,7 @@
-include("ejabberd_acme.hrl").
-spec parse_challenge(string(), jose_jwk:key()) -> bitstring().
-spec key_authorization(string(), jose_jwk:key()) -> bitstring().
key_authorization(Token, Key) ->
Thumbprint = jose_jwk:thumbprint(Key),
% ?INFO_MSG("Thumbprint: ~p~n", [Thumbprint]),
@ -34,7 +34,7 @@ parse_challenge(Challenge0) ->
Res = #challenge{
type = Type,
status = list_to_atom(bitstring_to_list(Status)),
uri = Uri,
uri = bitstring_to_list(Uri),
token = Token
},
{ok, Res}
@ -73,6 +73,7 @@ solve_challenge1(Chal = #challenge{type = <<"http-01">>, token=Tkn}, {Key, HttpD
?ERROR_MSG("Error writing to file: ~s with reason: ~p~n", [FileLocation, Err]),
Err
end;
%% TODO: Fill stub
solve_challenge1(Challenge, _Key) ->
?INFO_MSG("Challenge: ~p~n", [Challenge]).

View File

@ -10,7 +10,9 @@
, new_authz/4
, get_authz/1
, solve_challenge/4
, scenario/3
, scenario0/2
]).
@ -23,6 +25,7 @@
-include_lib("public_key/include/public_key.hrl").
-define(REQUEST_TIMEOUT, 5000). % 5 seconds.
-define(MAX_POLL_REQUESTS, 20).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -90,6 +93,11 @@ new_authz(Url, PrivateKey, Req, Nonce) ->
get_authz(Url) ->
prepare_get_request(Url, fun get_response/1).
-spec solve_challenge(url(), jose_jwk:key(), proplist(), nonce()) ->
{ok, proplist(), nonce()} | {error, _}.
solve_challenge(Url, PrivateKey, Req, Nonce) ->
EJson = {[{<<"resource">>, <<"challenge">>}] ++ Req},
prepare_post_request(Url, PrivateKey, EJson, Nonce, fun get_response/1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@ -164,6 +172,37 @@ get_challenges(Body) ->
{<<"challenges">>, Challenges} = proplists:lookup(<<"challenges">>, Body),
Challenges.
-spec get_authz_until_valid(url()) ->
{ok, proplist(), nonce()} | {error, _}.
get_authz_until_valid(Url) ->
get_authz_until_valid(Url, ?MAX_POLL_REQUESTS).
-spec get_authz_until_valid(url(), non_neg_integer()) ->
{ok, proplist(), nonce()} | {error, _}.
get_authz_until_valid(Url, 0) ->
?ERROR_MSG("Maximum request limit waiting for validation reached", []),
{error, max_request_limit};
get_authz_until_valid(Url, N) ->
case get_authz(Url) of
{ok, Resp, Nonce} ->
case is_authz_valid(Resp) of
true ->
{ok, Resp, Nonce};
false ->
get_authz_until_valid(Url, N-1)
end;
{error, _} = Err ->
Err
end.
-spec is_authz_valid(proplist()) -> boolean().
is_authz_valid(Authz) ->
case proplists:lookup(<<"status">>, Authz) of
{<<"status">>, <<"valid">>} ->
true;
none ->
false
end.
%% TODO: Fix the duplicated code at the below 4 functions
@ -204,7 +243,7 @@ make_get_request(Url) ->
failed_http_request(Error, Url)
end.
-spec prepare_post_request(url(), jose_jwk:key(), jiffy:json_value(),
-spec prepare_post_request(url(), jose_jwk:key(), jiffy:json_value(),
nonce(), handle_resp_fun()) -> {ok, _, nonce()} | {error, _}.
prepare_post_request(Url, PrivateKey, EJson, Nonce, HandleRespFun) ->
case encode(EJson) of
@ -370,12 +409,22 @@ new_user_scenario(CAUrl, HttpDir) ->
{ok, Authz2, Nonce5} = get_authz(AuthzUrl),
Challenges = get_challenges(Authz2),
?INFO_MSG("Challenges: ~p~n", [Challenges]),
% ?INFO_MSG("Challenges: ~p~n", [Challenges]),
{ok, ChallengeUrl, KeyAuthz} = acme_challenge:solve_challenge(<<"http-01">>, Challenges, {PrivateKey, HttpDir}),
?INFO_MSG("File for http-01 challenge written correctly", []),
{Account2, Authz2, PrivateKey}.
Req3 =
[ {<<"type">>, <<"http-01">>}
, {<<"keyAuthorization">>, KeyAuthz}
],
{ok, SolvedChallenge, Nonce6} = solve_challenge(ChallengeUrl, PrivateKey, Req3, Nonce5),
?INFO_MSG("SolvedChallenge: ~p~n", [SolvedChallenge]),
timer:sleep(2000),
{ok, Authz3, Nonce7} = get_authz_until_valid(AuthzUrl),
{Account2, Authz2, Authz3, PrivateKey}.
generate_key() ->