summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Klishin <klishinm@vmware.com>2020-10-30 13:22:36 +0300
committerGitHub <noreply@github.com>2020-10-30 13:22:36 +0300
commit74ca4e0365ac32b43d99c29cc19e568d6a9c207d (patch)
treebfe506df11659eeaaee959e1ff616352ce2123d6
parentd9a1355dfac8b8426608e43605291e3766f0977c (diff)
parent13b2b0f522499b6d2fa48c1349213418500ba6c4 (diff)
downloadrabbitmq-server-git-74ca4e0365ac32b43d99c29cc19e568d6a9c207d.tar.gz
Merge pull request #2487 from rabbitmq/mk-rabbitmq-auth-mechanism-ssl-12
Make it possible to extract username from certificate SANs
-rw-r--r--priv/schema/rabbit.schema19
-rw-r--r--src/rabbit_ssl.erl33
-rw-r--r--test/config_schema_SUITE_data/rabbit.snippets22
3 files changed, 70 insertions, 4 deletions
diff --git a/priv/schema/rabbit.schema b/priv/schema/rabbit.schema
index 0100fac996..daf54c2c86 100644
--- a/priv/schema/rabbit.schema
+++ b/priv/schema/rabbit.schema
@@ -408,12 +408,27 @@ end}.
%% https://github.com/rabbitmq/rabbitmq-auth-mechanism-ssl for further
%% details.
%%
-%% To use the SSL cert's CN instead of its DN as the username
+%% To use the peer certificate's Common Name (CN) field
+%% instead of its Distinguished Name (DN) for username extraction.
%%
%% {ssl_cert_login_from, common_name},
+%%
+%% To use the first SAN value of type DNS:
+%%
+%% {ssl_cert_login_from, subject_alternative_name},
+%% {ssl_cert_login_san_type, dns},
+%% {ssl_cert_login_san_index, 0}
{mapping, "ssl_cert_login_from", "rabbit.ssl_cert_login_from", [
- {datatype, {enum, [distinguished_name, common_name]}}
+ {datatype, {enum, [distinguished_name, common_name, subject_alternative_name, subject_alt_name]}}
+]}.
+
+{mapping, "ssl_cert_login_san_type", "rabbit.ssl_cert_login_san_type", [
+ {datatype, {enum, [dns, ip, email, uri, other_name]}}
+]}.
+
+{mapping, "ssl_cert_login_san_index", "rabbit.ssl_cert_login_san_index", [
+ {datatype, integer}, {validators, ["non_negative_integer"]}
]}.
%% TLS handshake timeout, in milliseconds.
diff --git a/src/rabbit_ssl.erl b/src/rabbit_ssl.erl
index d2283647b6..84670b0a19 100644
--- a/src/rabbit_ssl.erl
+++ b/src/rabbit_ssl.erl
@@ -120,6 +120,11 @@ peer_cert_subject(Cert) ->
peer_cert_subject_items(Cert, Type) ->
rabbit_cert_info:subject_items(Cert, Type).
+%% Filters certificate SAN extensions by (OTP) SAN type name.
+peer_cert_subject_alternative_names(Cert, Type) ->
+ SANs = rabbit_cert_info:subject_alternative_names(Cert),
+ lists:filter(fun({Key, _}) -> Key =:= Type end, SANs).
+
%% Return a string describing the certificate's validity.
peer_cert_validity(Cert) ->
rabbit_cert_info:validity(Cert).
@@ -138,6 +143,27 @@ peer_cert_auth_name(distinguished_name, Cert) ->
false -> unsafe
end;
+peer_cert_auth_name(subject_alt_name, Cert) ->
+ peer_cert_auth_name(subject_alternative_name, Cert);
+
+peer_cert_auth_name(subject_alternative_name, Cert) ->
+ case auth_config_sane() of
+ true ->
+ Type = application:get_env(rabbit, ssl_cert_login_san_type, dns),
+ %% lists:nth/2 is 1-based
+ Index = application:get_env(rabbit, ssl_cert_login_san_index, 0) + 1,
+ OfType = peer_cert_subject_alternative_names(Cert, otp_san_type(Type)),
+ rabbit_log:debug("Peer certificate SANs of type ~s: ~p, index to use with lists:nth/2: ~b", [Type, OfType, Index]),
+ case length(OfType) of
+ 0 -> not_found;
+ N when N < Index -> not_found;
+ N when N >= Index ->
+ {_, Value} = lists:nth(Index, OfType),
+ rabbit_data_coercion:to_binary(Value)
+ end;
+ false -> unsafe
+ end;
+
peer_cert_auth_name(common_name, Cert) ->
%% If there is more than one CN then we join them with "," in a
%% vaguely DN-like way. But this is more just so we do something
@@ -160,3 +186,10 @@ auth_config_sane() ->
"See https://www.rabbitmq.com/ssl.html#peer-verification to learn more.", [V]),
false
end.
+
+otp_san_type(dns) -> dNSName;
+otp_san_type(ip) -> iPAddress;
+otp_san_type(email) -> rfc822Name;
+otp_san_type(uri) -> uniformResourceIdentifier;
+otp_san_type(other_name) -> otherName;
+otp_san_type(Other) -> Other.
diff --git a/test/config_schema_SUITE_data/rabbit.snippets b/test/config_schema_SUITE_data/rabbit.snippets
index a86fd95c76..57616e13f9 100644
--- a/test/config_schema_SUITE_data/rabbit.snippets
+++ b/test/config_schema_SUITE_data/rabbit.snippets
@@ -452,10 +452,28 @@ tcp_listen_options.exit_on_close = false",
{fail_if_no_peer_cert, false},
{honor_ecc_order, true}]}]}],
[]},
- {ssl_cert_login_from,
+
+ {ssl_cert_login_from_cn,
"ssl_cert_login_from = common_name",
- [{rabbit,[{ssl_cert_login_from,common_name}]}],
+ [{rabbit,[{ssl_cert_login_from, common_name}]}],
[]},
+
+ {ssl_cert_login_from_dn,
+ "ssl_cert_login_from = distinguished_name",
+ [{rabbit,[{ssl_cert_login_from, distinguished_name}]}],
+ []},
+
+ {ssl_cert_login_from_san_dns,
+ "ssl_cert_login_from = subject_alternative_name
+ ssl_cert_login_san_type = dns
+ ssl_cert_login_san_index = 0",
+ [{rabbit,[
+ {ssl_cert_login_from, subject_alternative_name},
+ {ssl_cert_login_san_type, dns},
+ {ssl_cert_login_san_index, 0}
+ ]}],
+ []},
+
{tcp_listen_options_linger_on,
"tcp_listen_options.linger.on = true
tcp_listen_options.linger.timeout = 100",