Solve acme challenges using built in http server

This commit is contained in:
Konstantinos Kallas 2017-07-12 19:23:52 +03:00
parent 5199ede4a2
commit 77a96b0ec6
4 changed files with 68 additions and 17 deletions

View File

@ -160,6 +160,7 @@ listen:
request_handlers:
"/websocket": ejabberd_http_ws
"/api": mod_http_api
"/.well-known": acme_challenge
## "/pub/archive": mod_http_fileserver
web_admin: true
http_bind: true
@ -668,7 +669,8 @@ language: "en"
acme:
contact: "mailto:cert-admin-ejabberd@example.com"
http_dir: "/home/konstantinos/Desktop/Programming/test-server-for-acme/"
cert_dir: "/usr/local/var/lib/ejabberd/"
cert_dir: "/usr/local/var/lib/ejabberd/"
###. =======
###' MODULES

View File

@ -1,7 +1,9 @@
-module(acme_challenge).
-export ([ key_authorization/2,
solve_challenge/3
-export ([key_authorization/2,
solve_challenge/3,
process/2
]).
%% Challenge Types
%% ================
@ -13,9 +15,19 @@
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_acme.hrl").
%% TODO: Maybe validate request here??
process(LocalPath, Request) ->
Result = ets_get_key_authorization(LocalPath),
?INFO_MSG("Trying to serve: ~p at: ~p", [Request, LocalPath]),
?INFO_MSG("Http Response: ~p", [Result]),
{200,
[{<<"Content-Type">>, <<"text/plain">>}],
Result}.
-spec key_authorization(bitstring(), jose_jwk:key()) -> bitstring().
key_authorization(Token, Key) ->
Thumbprint = jose_jwk:thumbprint(Key),
@ -68,17 +80,49 @@ solve_challenge(ChallengeType, Challenges, Options) ->
{ok, url(), bitstring()} | {error, _}.
solve_challenge1(Chal = #challenge{type = <<"http-01">>, token=Tkn}, {Key, HttpDir}) ->
KeyAuthz = key_authorization(Tkn, Key),
%% save_key_authorization(Chal, Tkn, KeyAuthz, HttpDir);
ets_put_key_authorization(Tkn, KeyAuthz),
{ok, Chal#challenge.uri, KeyAuthz};
solve_challenge1(Challenge, _Key) ->
?INFO_MSG("Challenge: ~p~n", [Challenge]).
save_key_authorization(Chal, Tkn, KeyAuthz, HttpDir) ->
FileLocation = HttpDir ++ "/.well-known/acme-challenge/" ++ bitstring_to_list(Tkn),
case file:write_file(FileLocation, KeyAuthz) of
ok ->
{ok, Chal#challenge.uri, KeyAuthz};
{error, _} = Err ->
?ERROR_MSG("Error writing to file: ~s with reason: ~p~n", [FileLocation, Err]),
{error, Reason} = Err ->
?ERROR_MSG("Error writing to file: ~s with reason: ~p~n", [FileLocation, Reason]),
Err
end;
%% TODO: Fill stub
solve_challenge1(Challenge, _Key) ->
?INFO_MSG("Challenge: ~p~n", [Challenge]).
end.
-spec ets_put_key_authorization(bitstring(), bitstring()) -> ok.
ets_put_key_authorization(Tkn, KeyAuthz) ->
Tab = ets_get_acme_table(),
Key = [<<"acme-challenge">>, Tkn],
ets:insert(Tab, {Key, KeyAuthz}),
ok.
-spec ets_get_key_authorization([bitstring()]) -> bitstring().
ets_get_key_authorization(Key) ->
Tab = ets_get_acme_table(),
case ets:take(Tab, Key) of
[{Key, KeyAuthz}] ->
KeyAuthz;
_ ->
?ERROR_MSG("Unable to serve key authorization in: ~p", [Key]),
<<"">>
end.
-spec ets_get_acme_table() -> atom().
ets_get_acme_table() ->
case ets:info(acme) of
undefined ->
ets:new(acme, [named_table, public]);
_ ->
acme
end.
%% Useful functions

View File

@ -513,13 +513,12 @@ get_config_hosts() ->
end.
get_config_cert_dir() ->
{ok, Acme} = get_config_acme(),
case lists:keyfind(cert_dir, 1, Acme) of
{cert_dir, CertDir} ->
{ok, CertDir};
false ->
?ERROR_MSG("No certificate directory has been specified", []),
{error, configuration_cert_dir}
case ejabberd_config:get_option(cert_dir, undefined) of
undefined ->
?ERROR_MSG("No cert_dir configuration has been specified", []),
throw({error, configuration});
CertDir ->
{ok, CertDir}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -32,6 +32,12 @@
-define(MAX_POLL_REQUESTS, 20).
-define(POLL_WAIT_TIME, 500). % 500 ms.
%%%
%%% This module contains functions that implement all necessary http
%%% requests to the ACME Certificate Authority. Its purpose is to
%%% facilitate the acme client implementation by separating the
%%% handling/validating/parsing of all the needed http requests.
%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%