rabbitmq-server/deps/rabbitmq_auth_backend_oauth2/src/Elixir.RabbitMQ.CLI.Ctl.Com...

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

138 lines
4.5 KiB
Erlang
Raw Normal View History

2024-01-03 16:28:36 +08:00
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved.
%%
-module('Elixir.RabbitMQ.CLI.Ctl.Commands.AddSigningKeyCommand').
-behaviour('Elixir.RabbitMQ.CLI.CommandBehaviour').
-export([
usage/0,
validate/2,
merge_defaults/2,
banner/2,
run/2,
switches/0,
aliases/0,
output/2,
description/0,
formatter/0
]).
usage() ->
<<"add_signing_key <name> [--json=<json_key>] [--pem=<public_key>] [--pem-file=<pem_file>]">>.
description() -> <<"Add signing key required to validate JWT's digital signatures">>.
switches() ->
[{json, string},
{pem, string},
{pem_file, string}].
aliases() -> [].
validate([], _Options) -> {validation_failure, not_enough_args};
validate([_,_|_], _Options) -> {validation_failure, too_many_args};
validate([_], Options) ->
Json = maps:get(json, Options, undefined),
Pem = maps:get(pem, Options, undefined),
PemFile = maps:get(pem_file, Options, undefined),
case {is_binary(Json), is_binary(Pem), is_binary(PemFile)} of
{false, false, false} ->
{validation_failure,
{bad_argument, <<"No key specified">>}};
{true, false, false} ->
validate_json(Json);
{false, true, false} ->
validate_pem(Pem);
{false, false, true} ->
validate_pem_file(PemFile);
{_, _, _} ->
{validation_failure,
{bad_argument, <<"There can be only one key type">>}}
end.
validate_json(Json) ->
case rabbit_json:try_decode(Json) of
{ok, _} ->
case uaa_jwt:verify_signing_key(json, Json) of
ok -> ok;
{error, {fields_missing_for_kty, Kty}} ->
{validation_failure,
{bad_argument,
<<"Key fields are missing fot kty \"", Kty/binary, "\"">>}};
{error, unknown_kty} ->
{validation_failure,
{bad_argument, <<"\"kty\" field is invalid">>}};
{error, no_kty} ->
{validation_failure,
{bad_argument, <<"Json key should contain \"kty\" field">>}};
{error, Err} ->
{validation_failure, {bad_argument, Err}}
end;
{error, _} ->
{validation_failure, {bad_argument, <<"Invalid JSON">>}}
end.
validate_pem(Pem) ->
case uaa_jwt:verify_signing_key(pem, Pem) of
ok -> ok;
{error, invalid_pem_string} ->
{validation_failure, <<"Unable to read a key from the PEM string">>};
{error, Err} ->
{validation_failure, Err}
end.
validate_pem_file(PemFile) ->
case uaa_jwt:verify_signing_key(pem_file, PemFile) of
ok -> ok;
{error, enoent} ->
{validation_failure, {bad_argument, <<"PEM file not found">>}};
{error, invalid_pem_file} ->
{validation_failure, <<"Unable to read a key from the PEM file">>};
{error, Err} ->
{validation_failure, Err}
end.
merge_defaults(Args, #{pem_file := FileName} = Options) ->
AbsFileName = filename:absname(FileName),
{Args, Options#{pem_file := AbsFileName}};
merge_defaults(Args, Options) -> {Args, Options}.
banner([Name], #{json := Json}) ->
<<"Adding OAuth signing key \"",
Name/binary,
"\" in JSON format: \"",
Json/binary, "\"">>;
banner([Name], #{pem := Pem}) ->
<<"Adding OAuth signing key \"",
Name/binary,
"\" public key: \"",
Pem/binary, "\"">>;
banner([Name], #{pem_file := PemFile}) ->
<<"Adding OAuth signing key \"",
Name/binary,
"\" filename: \"",
PemFile/binary, "\"">>.
run([Name], #{node := Node} = Options) ->
{Type, Value} = case Options of
#{json := Json} -> {json, Json};
#{pem := Pem} -> {pem, Pem};
#{pem_file := PemFile} -> {pem_file, PemFile}
end,
case rabbit_misc:rpc_call(Node,
uaa_jwt, add_signing_key,
[Name, Type, Value]) of
{ok, _Keys} -> ok;
{error, Err} -> {error, Err}
end.
output(E, _Opts) ->
'Elixir.RabbitMQ.CLI.DefaultOutput':output(E).
formatter() -> 'Elixir.RabbitMQ.CLI.Formatters.Erlang'.