summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2010-11-10 13:52:06 +0000
committerSimon MacMullen <simon@rabbitmq.com>2010-11-10 13:52:06 +0000
commit0266d57133df73c714845dbc750e369a8be7d699 (patch)
treeed3027a7f5b734640650f1c69178abfd6b9abbc2 /src
parent524156880a84cf6397ec0c659ac5a32cedc379af (diff)
downloadrabbitmq-server-git-0266d57133df73c714845dbc750e369a8be7d699.tar.gz
Mostly working EXTERNAL implementation
Diffstat (limited to 'src')
-rw-r--r--src/rabbit_auth_mechanism.erl2
-rw-r--r--src/rabbit_auth_mechanism_amqplain.erl4
-rw-r--r--src/rabbit_auth_mechanism_external.erl49
-rw-r--r--src/rabbit_auth_mechanism_plain.erl4
-rw-r--r--src/rabbit_auth_mechanism_scram_md5.erl4
-rw-r--r--src/rabbit_reader.erl2
-rw-r--r--src/rabbit_ssl.erl24
7 files changed, 62 insertions, 27 deletions
diff --git a/src/rabbit_auth_mechanism.erl b/src/rabbit_auth_mechanism.erl
index b13a14ec38..c932471d77 100644
--- a/src/rabbit_auth_mechanism.erl
+++ b/src/rabbit_auth_mechanism.erl
@@ -44,7 +44,7 @@ behaviour_info(callbacks) ->
%% Called before authentication starts. Should create a state
%% object to be passed through all the stages of authentication.
- {init, 0},
+ {init, 1},
%% Handle a stage of authentication. Possible responses:
%% {ok, User}
diff --git a/src/rabbit_auth_mechanism_amqplain.erl b/src/rabbit_auth_mechanism_amqplain.erl
index 61f61e403a..0207e6c63b 100644
--- a/src/rabbit_auth_mechanism_amqplain.erl
+++ b/src/rabbit_auth_mechanism_amqplain.erl
@@ -34,7 +34,7 @@
-behaviour(rabbit_auth_mechanism).
--export([description/0, should_offer/1, init/0, handle_response/2]).
+-export([description/0, should_offer/1, init/1, handle_response/2]).
-include("rabbit_auth_mechanism_spec.hrl").
@@ -56,7 +56,7 @@ description() ->
should_offer(_Sock) ->
true.
-init() ->
+init(_Sock) ->
[].
handle_response(Response, _State) ->
diff --git a/src/rabbit_auth_mechanism_external.erl b/src/rabbit_auth_mechanism_external.erl
index 251aa41770..43f2a196d6 100644
--- a/src/rabbit_auth_mechanism_external.erl
+++ b/src/rabbit_auth_mechanism_external.erl
@@ -34,10 +34,12 @@
-behaviour(rabbit_auth_mechanism).
--export([description/0, should_offer/1, init/0, handle_response/2]).
+-export([description/0, should_offer/1, init/1, handle_response/2]).
-include("rabbit_auth_mechanism_spec.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
-rabbit_boot_step({?MODULE,
[{description, "auth mechanism external"},
{mfa, {rabbit_registry, register,
@@ -45,27 +47,42 @@
{requires, rabbit_registry},
{enables, kernel_ready}]}).
-%% SASL PLAIN, as used by the Qpid Java client and our clients. Also,
-%% apparently, by OpenAMQ.
+-record(state, {username = undefined}).
+
+%% SASL EXTERNAL. SASL says EXTERNAL means "use credentials
+%% established by means external to the mechanism". We define that to
+%% mean the peer certificate's subject's CN.
description() ->
[{name, <<"EXTERNAL">>},
{description, <<"SASL EXTERNAL authentication mechanism">>}].
+%% TODO: safety check, don't offer unless verify_peer set
should_offer(Sock) ->
- Cert = case rabbit_net:peercert(Sock) of
- nossl -> 'not_ssl';
- {error, no_peercert} -> 'no_peer_cert';
- {ok, C} -> C
- end,
+ case peer_subject(Sock) of
+ none -> false;
+ _ -> true
+ end.
+
+init(Sock) ->
+ {ok, C} = rabbit_net:peercert(Sock),
+ CN = case rabbit_ssl:peer_cert_subject_item(C, ?'id-at-commonName') of
+ not_found -> not_found;
+ CN0 -> list_to_binary(CN0)
+ end,
+ #state{username = CN}.
- io:format("Sock: ~p~n", [{Sock, Cert}]),
- true.
+handle_response(_Response, #state{username = Username}) ->
+ case Username of
+ not_found -> {refused, Username};
+ _ -> rabbit_access_control:lookup_user(Username)
+ end.
-init() ->
- [].
+%%--------------------------------------------------------------------------
-handle_response(Response, _State) ->
- [User, Pass] = [list_to_binary(T) ||
- T <- string:tokens(binary_to_list(Response), [0])],
- rabbit_access_control:check_user_pass_login(User, Pass).
+peer_subject(Sock) ->
+ case rabbit_net:peercert(Sock) of
+ nossl -> none;
+ {error, no_peercert} -> none;
+ {ok, C} -> rabbit_ssl:peer_cert_subject(C)
+ end.
diff --git a/src/rabbit_auth_mechanism_plain.erl b/src/rabbit_auth_mechanism_plain.erl
index 28aed92b43..7de6197625 100644
--- a/src/rabbit_auth_mechanism_plain.erl
+++ b/src/rabbit_auth_mechanism_plain.erl
@@ -34,7 +34,7 @@
-behaviour(rabbit_auth_mechanism).
--export([description/0, should_offer/1, init/0, handle_response/2]).
+-export([description/0, should_offer/1, init/1, handle_response/2]).
-include("rabbit_auth_mechanism_spec.hrl").
@@ -55,7 +55,7 @@ description() ->
should_offer(_Sock) ->
true.
-init() ->
+init(_Sock) ->
[].
handle_response(Response, _State) ->
diff --git a/src/rabbit_auth_mechanism_scram_md5.erl b/src/rabbit_auth_mechanism_scram_md5.erl
index 02032bdd76..688f9dee30 100644
--- a/src/rabbit_auth_mechanism_scram_md5.erl
+++ b/src/rabbit_auth_mechanism_scram_md5.erl
@@ -34,7 +34,7 @@
-behaviour(rabbit_auth_mechanism).
--export([description/0, should_offer/1, init/0, handle_response/2]).
+-export([description/0, should_offer/1, init/1, handle_response/2]).
-include("rabbit_auth_mechanism_spec.hrl").
@@ -67,7 +67,7 @@ description() ->
should_offer(_Sock) ->
true.
-init() ->
+init(_Sock) ->
#state{}.
handle_response(Username, State = #state{username = undefined}) ->
diff --git a/src/rabbit_reader.erl b/src/rabbit_reader.erl
index cc25c83393..dd5bd61d72 100644
--- a/src/rabbit_reader.erl
+++ b/src/rabbit_reader.erl
@@ -752,7 +752,7 @@ handle_method0(#'connection.start_ok'{mechanism = Mechanism,
sock = Sock}) ->
AuthMechanism = auth_mechanism_to_module(Mechanism, Sock),
State = State0#v1{auth_mechanism = AuthMechanism,
- auth_state = AuthMechanism:init(),
+ auth_state = AuthMechanism:init(Sock),
connection_state = securing,
connection =
Connection#connection{
diff --git a/src/rabbit_ssl.erl b/src/rabbit_ssl.erl
index 4335dd2e40..d37d77a650 100644
--- a/src/rabbit_ssl.erl
+++ b/src/rabbit_ssl.erl
@@ -36,6 +36,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_validity/1]).
+-export([peer_cert_subject_item/2]).
%%--------------------------------------------------------------------------
@@ -45,9 +46,10 @@
-type(certificate() :: binary()).
--spec(peer_cert_issuer/1 :: (certificate()) -> string()).
--spec(peer_cert_subject/1 :: (certificate()) -> string()).
--spec(peer_cert_validity/1 :: (certificate()) -> string()).
+-spec(peer_cert_issuer/1 :: (certificate()) -> string()).
+-spec(peer_cert_subject/1 :: (certificate()) -> string()).
+-spec(peer_cert_validity/1 :: (certificate()) -> string()).
+-spec(peer_cert_subject_item/2 :: (certificate(), atom()) -> string()).
-endif.
@@ -71,6 +73,14 @@ peer_cert_subject(Cert) ->
format_rdn_sequence(Subject)
end, Cert).
+%% Return a part of the certificate's subject.
+peer_cert_subject_item(Cert, Type) ->
+ cert_info(fun(#'OTPCertificate' {
+ tbsCertificate = #'OTPTBSCertificate' {
+ subject = Subject }}) ->
+ find_by_type(Type, Subject)
+ end, Cert).
+
%% Return a string describing the certificate's validity.
peer_cert_validity(Cert) ->
cert_info(fun(#'OTPCertificate' {
@@ -89,6 +99,14 @@ cert_info(F, Cert) ->
DecCert -> DecCert
end).
+find_by_type(Type, {rdnSequence, RDNs}) ->
+ case [V || #'AttributeTypeAndValue'{type = T, value = V}
+ <- lists:flatten(RDNs),
+ T == Type] of
+ [{printableString, S}] -> S;
+ [] -> not_found
+ end.
+
%%--------------------------------------------------------------------------
%% Formatting functions
%%--------------------------------------------------------------------------