diff --git a/apps/consul_proxy/src/consul_proxy_middleware_hijack.erl b/apps/consul_proxy/src/consul_proxy_middleware_hijack.erl index a42bf5859b3682a16e3eceabaa516a87199eaa12..d01fb12db92139b578ddb2e5ac15ea0dd8f70a5e 100644 --- a/apps/consul_proxy/src/consul_proxy_middleware_hijack.erl +++ b/apps/consul_proxy/src/consul_proxy_middleware_hijack.erl @@ -38,7 +38,8 @@ transport = undefined, timeout = 3000, client_state = undefined, - username = undefined + username = undefined, + domains = [] }). @@ -121,31 +122,39 @@ handle_call({socket_recv, Terms = #{<<"action">> := <<"login">>}, SocketState}, case maps:get(Username, users(), undefined) of undefined -> {reply, SocketState#socket_state{client_state = unauthorized}, State}; - {Salt, Hash} -> + {Salt, Hash, Domains} -> case pbkdf2:pbkdf2(sha512, Password, Salt, ?PBKDF2_ITERATIONS, ?PBKDF2_DERIVED_LENGTH) of {ok, Hash} -> send(SocketState, #{<<"action">> => <<"authorized">>, <<"username">> => Username}), {reply, SocketState#socket_state{ client_state = authorized, timeout = 60000, - username = Username + username = Username, + domains = Domains }, State}; _ -> {reply, SocketState#socket_state{client_state = unauthorized}, State} end end; -handle_call({socket_recv, Terms = #{<<"action">> := <<"bind">>}, SocketState}, _From, State) -> +handle_call({socket_recv, Terms = #{<<"action">> := <<"bind">>}, SocketState = #socket_state{domains = Domains}}, _From, State) -> #{<<"host">> := Host, <<"path">> := Path, <<"mode">> := Mode} = Terms, #socket_state{socket = Socket, transport = Transport} = SocketState, - case re:compile(Path) of - {ok, MP} -> - ets:insert(State#state.domain_tab, {Host, Mode, MP, Socket, Transport}), - send(SocketState, Terms), - lager:notice("~s/~s ~s by ~s on ~p", [Host, Path, Mode, SocketState#socket_state.username, Socket]), - {reply, SocketState#socket_state{client_state = bound}, State}; - {error, {Description, Position}} -> - Message = io_lib:format("Bad path regexp '~s', ~s at position ~p", [Path, Description, Position]), + case host_matches(Host, Domains) of + true -> + case re:compile(Path) of + {ok, MP} -> + ets:insert(State#state.domain_tab, {Host, Mode, MP, Socket, Transport}), + send(SocketState, Terms), + lager:notice("~s/~s ~s by ~s on ~p", [Host, Path, Mode, SocketState#socket_state.username, Socket]), + {reply, SocketState#socket_state{client_state = bound}, State}; + {error, {Description, Position}} -> + Message = io_lib:format("Bad path regexp '~s', ~s at position ~p", [Path, Description, Position]), + send(SocketState, #{<<"action">> => <<"error">>, <<"message">> => lists:flatten(Message)}), + {reply, SocketState, State} + end; + false -> + Message = io_lib:format("Host ~s not allowed", [Host]), send(SocketState, #{<<"action">> => <<"error">>, <<"message">> => lists:flatten(Message)}), {reply, SocketState, State} end; @@ -218,9 +227,20 @@ parse_users([], Parsed) -> Parsed; parse_users([User | Users], Parsed) -> - [Username, Password] = binary:split(User, <<$:>>), + Username = proplists:get_value(<<"username">>, User, <<"">>), + Password = proplists:get_value(<<"password">>, User, <<"">>), + Domains = lists:foldl( + fun(Domain, Acc) -> + case re:compile(Domain) of + {ok, MP} -> + [MP | Acc]; + {error, {Description, Position}} -> + lager:warning("Bad domain regexp '~s', ~s at position ~p", [Domain, Description, Position]), + Acc + end + end, [], proplists:get_value(<<"domains">>, User, [])), <<Salt:?PBKDF2_SALT_LENGTH/binary, Hash:?PBKDF2_DERIVED_LENGTH/binary>> = base64:decode(Password), - parse_users(Users, Parsed#{Username => {Salt, Hash}}). + parse_users(Users, Parsed#{Username => {Salt, Hash, Domains}}). hijack([], Req, _From) -> {ignored, Req}; @@ -261,3 +281,14 @@ request_to_map(Req) -> <<"body">> => Body }, {Map, Req2}. + +host_matches(_Host, []) -> + false; + +host_matches(Host, [RE | REs]) -> + case re:run(Host, RE) of + nomatch -> + host_matches(Host, REs); + _ -> + true + end. diff --git a/test/defaults.consul b/test/defaults.consul index d11fbabbef23e9e4a725ffd374ceeff3ba8a040c..b1c5dd10de6bf409411660c97f45876bb22f6d83 100644 --- a/test/defaults.consul +++ b/test/defaults.consul @@ -6,4 +6,4 @@ consul_proxy/scripts/resolver-example.erl:e0NhcHR1cmUsX30gPSBjb3dib3lrdV9yZXE6bW consul_proxy/watchers/nodes:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ== consul_proxy/watchers/services:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ== consul_proxy/watchers/kv:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ== -consul_proxy/hijackers:WwogICJoaWphY2tlcjowdEhWdFNhOThrSGkyZStkVHVWdHo3S3lYWTgzVys3cGZ6eEZYd2VKWUtualcxOXRSeHBVbFFSV1lYbGI4V21YIgpd +consul_proxy/hijackers:WwogIHsKICAgICJ1c2VybmFtZSIgOiAiaGlqYWNrZXIiLAogICAgInBhc3N3b3JkIiA6ICIwdEhWdFNhOThrSGkyZStkVHVWdHo3S3lYWTgzVys3cGZ6eEZYd2VKWUtualcxOXRSeHBVbFFSV1lYbGI4V21YIiwKICAgICJkb21haW5zIiA6IFsKICAgICAgIi4qIgogICAgXQogIH0KXQ==