diff options
Diffstat (limited to 'components/authorize/src/authorize_rpc.erl')
-rw-r--r-- | components/authorize/src/authorize_rpc.erl | 193 |
1 files changed, 60 insertions, 133 deletions
diff --git a/components/authorize/src/authorize_rpc.erl b/components/authorize/src/authorize_rpc.erl index ba54f3a..9fa052a 100644 --- a/components/authorize/src/authorize_rpc.erl +++ b/components/authorize/src/authorize_rpc.erl @@ -21,14 +21,17 @@ -export([get_credentials/1, sign_message/2, validate_message/3, - validate_authorization/3, - validate_authorization/4, store_creds/3, store_creds/4, + remove_connection/2, authorize_local_message/3, authorize_remote_message/3]). -export([filter_by_service/3]). +%% for service_discovery notifications +-export([service_available/3, + service_unavailable/3]). + %% for testing & development -export([public_key/0, public_key_json/0, private_key/0]). @@ -53,6 +56,8 @@ init([]) -> {Priv, Pub} = authorize_keys:get_device_key(), ?debug("KeyPair = {~s, ~s}~n", [authorize_keys:pp_key(Priv), authorize_keys:pp_key(Pub)]), + CS = rvi_common:get_component_specification(), + service_discovery_rpc:subscribe(CS, ?MODULE), {ok, #st { cs = rvi_common:get_component_specification(), private_key = Priv, public_key = Pub} }. @@ -78,22 +83,9 @@ get_credentials(CompSpec) -> rvi_common:request(authorize, ?MODULE, get_credentials, [], [status, creds], CompSpec). -validate_authorization(CompSpec, JWT, Conn) -> - ?debug("authorize_rpc:validate_authorization():" - " Conn = ~p~n", [Conn]), - rvi_common:request(authorize, ?MODULE, validate_authorization, - [{jwt, JWT}, - {conn, Conn}], - [status], CompSpec). - -validate_authorization(CompSpec, JWT, Creds, Conn) -> - ?debug("authorize_rpc:validate_authorization():" - " Conn = ~p~n", [Conn]), - rvi_common:request(authorize, ?MODULE, validate_authorization, - [{jwt, JWT}, - {creds, Creds}, - {conn, Conn}], - [status], CompSpec). +remove_connection(CompSpec, Conn) -> + rvi_common:notification(authorize, ?MODULE, remove_connection, + [{conn, Conn}], [status], CompSpec). store_creds(CompSpec, Creds, Conn) -> store_creds(CompSpec, Creds, Conn, undefined). @@ -129,6 +121,14 @@ filter_by_service(CompSpec, Services, Conn) -> { conn, Conn }], [status, services], CompSpec). +service_available(CS, SvcName, _DLMod) -> + rvi_common:notification(authorize, ?MODULE, service_available, + [{service, SvcName}], CS). + +service_unavailable(CS, SvcName, _DLMod) -> + rvi_common:notification(authorize, ?MODULE, service_unavailable, + [{service, SvcName}], CS). + public_key() -> gen_server:call(?SERVER, public_key). @@ -140,7 +140,7 @@ private_key() -> %% JSON-RPC entry point %% CAlled by local exo http server -handle_rpc("sign_message", Args) -> +handle_rpc(<<"sign_message">>, Args) -> {ok, Message} = rvi_common:get_json_element(["message"], Args), LogId = rvi_common:get_json_log_id(Args), [ Status, JWT ] = @@ -148,7 +148,7 @@ handle_rpc("sign_message", Args) -> ?debug("Message signature = ~p~n", [JWT]), {ok, [ {status, rvi_common:json_rpc_status(Status)}, {jwt, JWT} ]}; -handle_rpc("validate_message", Args) -> +handle_rpc(<<"validate_message">>, Args) -> ?debug("validate_message; Args = ~p~n", [Args]), {ok, JWT} = rvi_common:get_json_element(["jwt"], Args), {ok, Conn} = rvi_common:get_json_element(["conn"], Args), @@ -157,24 +157,12 @@ handle_rpc("validate_message", Args) -> gen_server:call(?SERVER, { rvi, validate_message, [JWT, Conn, LogId] }), {ok, [ {status, rvi_common:json_rpc_status(Status)}, {message, Msg} ]}; -handle_rpc("get_credentials", Args) -> +handle_rpc(<<"get_credentials">>, Args) -> LogId = rvi_common:get_json_log_id(Args), [ Status | Rem ] = gen_server:call(?SERVER, { rvi, get_credentials, [LogId] }), {ok, [ rvi_common:json_rpc_status(Status) | Rem ] }; -handle_rpc("validate_authorization", Args) -> - {ok, JWT} = rvi_common:get_json_element(["jwt"], Args), - {ok, Conn} = rvi_common:get_json_element(["connection"], Args), - LogId = rvi_common:get_json_log_id(Args), - CmdArgs = - case rvi_common:get_json_element(["creds"], Args) of - {ok, Creds} -> [JWT, Creds, Conn, LogId]; - {error, _} -> [JWT, Conn, LogId] - end, - [ Status | Rem ] = - gen_server:call(?SERVER, {rvi, validate_authorization, CmdArgs}), - {ok, [ rvi_common:json_rpc_status(Status) | Rem] }; -handle_rpc("store_creds", Args) -> +handle_rpc(<<"store_creds">>, Args) -> {ok, Creds} = rvi_common:get_json_element(["creds"], Args), {ok, Conn} = rvi_common:get_json_element(["conn"], Args), {ok, PeerCert} = rvi_common:get_json_element(["peer_cert"], Args), @@ -182,7 +170,7 @@ handle_rpc("store_creds", Args) -> [ Status | Rem ] = gen_server:call(?SERVER, {rvi, store_creds, [Creds, Conn, PeerCert, LogId]}), {ok, [ rvi_common:json_rpc_status(Status) | Rem]}; -handle_rpc("authorize_local_message", Args) -> +handle_rpc(<<"authorize_local_message">>, Args) -> {ok, Service} = rvi_common:get_json_element(["service"], Args), {ok, Params} = rvi_common:get_json_element(["parameters"], Args), LogId = rvi_common:get_json_log_id(Args), @@ -193,7 +181,7 @@ handle_rpc("authorize_local_message", Args) -> { ok, [ rvi_common:json_rpc_status(Status) | Rem] }; -handle_rpc("authorize_remote_message", Args) -> +handle_rpc(<<"authorize_remote_message">>, Args) -> {ok, Service} = rvi_common:get_json_element(["service"], Args), {ok, Params} = rvi_common:get_json_element(["parameters"], Args), LogId = rvi_common:get_json_log_id(Args), @@ -201,7 +189,7 @@ handle_rpc("authorize_remote_message", Args) -> [Service, Params, LogId]}), { ok, rvi_common:json_rpc_status(Status)}; -handle_rpc("filter_by_service", Args) -> +handle_rpc(<<"filter_by_service">>, Args) -> ?debug("authorize_rpc:handle_rpc(\"filter_by_service\", ~p)~n", [Args]), {ok, Services} = rvi_common:get_json_element(["services"], Args), {ok, Conn} = rvi_common:get_json_element(["conn"], Args), @@ -217,12 +205,24 @@ handle_rpc(Other, _Args) -> { ok, [ { status, rvi_common:json_rpc_status(invalid_command)} ] }. +handle_notification(<<"service_available">>, Args) -> + {ok, SvcName} = rvi_common:get_json_element(["service"], Args), + gen_server:cast(?SERVER, {service_available, SvcName}), + ok; +handle_notification(<<"service_unavailable">>, Args) -> + {ok, SvcName} = rvi_common:get_json_element(["service"], Args), + gen_server:cast(?SERVER, {service_unavailable, SvcName}), + ok; +handle_notification(<<"remove_connection">>, Args) -> + {ok, Conn} = rvi_common:get_json_element(["conn"], Args), + gen_server:cast(?SERVER, {remove_connection, Conn}, Args), + ok; handle_notification(Other, _Args) -> ?debug("authorize_rpc:handle_other(~p): unknown", [ Other ]), ok. %% -%% Genserver implementation +%% Gen_server implementation %% handle_call({rvi, sign_message, [Msg | LogId]}, _, #st{private_key = Key} = State) -> Sign = authorize_sig:encode_jwt(Msg, Key), @@ -241,62 +241,19 @@ handle_call({rvi, validate_message, [JWT, Conn | LogId]}, _, State) -> handle_call({rvi, get_credentials, _Args}, _From, State) -> {reply, [ ok, authorize_keys:get_credentials() ], State}; -handle_call({rvi, validate_authorization, [JWT, Conn | [_] = LogId]}, _From, State) -> - %% The authorize JWT contains the public key used to sign the cred - ?debug( - "authorize_rpc:handle_call({rvi, validate_authorization, [_,_,_]})~n", - []), - try authorize_sig:decode_jwt(JWT, authorize_keys:provisioning_key()) of - {_Header, Keys} -> - log(LogId, result, "auth jwt validated", []), - KeyStructs = get_json_element(["keys"], Keys, []), - authorize_keys:save_keys(KeyStructs, Conn), - {reply, [ok], State}; - invalid -> - ?warning("Invalid auth JWT from ~p~n", [Conn]), - log(LogId, error, "auth jwt INVALID", []), - {reply, [not_found], State} - catch - error:_Err -> - ?warning("Auth validation exception: ~p~n", [_Err]), - {reply, [not_found], State} - end; - -handle_call({rvi, validate_authorization, [JWT, Creds, Conn | [_] = LogId] }, _From, State) -> - %% The authorize JWT contains the public key used to sign the cred - ?debug( - "authorize_rpc:handle_call({rvi, validate_authorization, [_,_,_]})~n", - []), - try authorize_sig:decode_jwt(JWT, authorize_keys:provisioning_key()) of - {_Header, Keys} -> - log(LogId, result, "auth jwt validated", []), - KeyStructs = get_json_element(["keys"], Keys, []), - ?debug("KeyStructs = ~p~n", [KeyStructs]), - authorize_keys:save_keys(KeyStructs, Conn), - do_store_creds(Creds, Conn, undefined, LogId), - {reply, [ok], State}; - invalid -> - ?warning("Invalid auth JWT from ~p~n", [Conn]), - log(LogId, error, "auth jwt INVALID", []), - {reply, [not_found], State} - catch - error:_Err -> - ?warning("Auth validation exception: ~p~n", [_Err]), - {reply, [not_found], State} - end; - handle_call({rvi, store_creds, [Creds, Conn, PeerCert | LogId]}, _From, State) -> - do_store_creds(Creds, Conn, PeerCert, LogId), + do_store_creds(Creds, Conn, PeerCert, LogId, State#st.cs), {reply, [ok], State}; + handle_call({rvi, authorize_local_message, [Service, _Params | LogId] } = R, _From, State) -> ?debug("authorize_rpc:handle_call(~p)~n", [R]), - case authorize_keys:find_cred_by_service(Service) of - {ok, {ID, _Cred}} -> - log(LogId, result, "auth msg: Cred=~s", [authorize_keys:abbrev_bin(ID)]), - {reply, [ok], State}; - _ -> - log(LogId, error, "NO CREDS for ~s", [Service]), - {reply, [ not_found ], State} + case authorize_keys:validate_service_call(Service, local) of + invalid -> + log(LogId, error, "local msg REJECTED", []), + {reply, [ not_found ], State}; + {ok, Id} -> + log(LogId, result, "local msg allowed: Cred=~s", [Id]), + {reply, [ok], State} end; handle_call({rvi, authorize_remote_message, [_Service, Params | LogId]}, @@ -341,6 +298,15 @@ handle_call(Other, _From, State) -> ?warning("authorize_rpc:handle_call(~p): unknown", [ Other ]), { reply, unknown_command, State}. +handle_cast({rvi, service_available, Svc}, State) -> + authorize_keys:cache_authorizations(Svc), + {noreply, State}; +handle_cast({rvi, service_unavailable, Svc}, State) -> + authorize_keys:remove_cached_authorizations(Svc), + {noreply, State}; +handle_cast({rvi, remove_connection, Conn}, State) -> + authorize_keys:remove_connection(Conn), + {noreply, State}; handle_cast(Other, State) -> ?warning("authorize_rpc:handle_cast(~p): unknown", [ Other ]), {noreply, State}. @@ -353,20 +319,14 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. -do_store_creds(Creds, Conn, PeerCert, LogId) -> +do_store_creds(Creds, Conn, PeerCert, LogId, CS) -> ?debug("Storing ~p creds for conn ~p~nPeerCert = ~w", [length(Creds), Conn, authorize_keys:abbrev(PeerCert)]), + authorize_keys:remove_cached_authorizations_for_conn(Conn), lists:foreach(fun(Cred) -> store_cred(Cred, Conn, PeerCert, LogId) - end, Creds). - -get_json_element(Path, JSON, Default) -> - case rvi_common:get_json_element(Path, JSON) of - {ok, Value} -> - Value; - _ -> - Default - end. + end, Creds), + authorize_keys:update_authorization_cache(Conn, CS). store_cred(CredJWT, Conn, PeerCert, LogId) -> case authorize_sig:decode_jwt(authorize_keys:strip_nl(CredJWT), authorize_keys:provisioning_key()) of @@ -389,36 +349,3 @@ log([ID], Lvl, Fmt, Args) -> rvi_log:log(ID, Lvl, <<"authorize">>, rvi_log:format(Fmt, Args)); log(_, _, _, _) -> ok. - -%% check_msg(Checks, Params) -> -%% check_msg(Checks, Params, []). - - %% {ok, Timeout1} = rvi_common:get_json_element(["timeout"], Msg), - %% {ok, SvcName1} = rvi_common:get_json_element(["service_name"], Msg), - %% {ok, Params1} = rvi_common:get_json_element(["parameters"], Msg), - %% ?debug("authorize_rpc:authorize_remote_message(): timeout1: ~p~n", [Timeout1]), - %% ?debug("authorize_rpc:authorize_remote_message(): service_name1: ~p~n", [SvcName1]), - %% ?debug("authorize_rpc:authorize_remote_message(): parameters1: ~p~n", [Params1]), - - %% if Timeout =:= Timeout1 * 1000, - %% SvcName =:= SvcName1, - %% Parameters =:= Params1 -> - %% ?debug("Remote message authorized.~n", []), - %% {reply, [ ok ], State}; - %% true -> - %% ?debug("Remote message NOT authorized.~n", []), - %% {reply, [ not_found ], State} - %% end - %% end; - -%% check_msg([], _, []) -> -%% ok; -%% check_msg([{Key, Expect}|T], Msg, Acc) -> -%% case rvi_common:get_json_element([Key], Msg) of -%% {ok, Expect} -> -%% check_msg(T, Msg, Acc); -%% _ -> -%% check_msg(T, Msg, [Key|Acc]) -%% end; -%% check_msg([], _, [_|_] = Acc) -> -%% {error, {mismatch, lists:reverse(Acc)}}. |