summaryrefslogtreecommitdiff
path: root/components/authorize/src/authorize_rpc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'components/authorize/src/authorize_rpc.erl')
-rw-r--r--components/authorize/src/authorize_rpc.erl193
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)}}.