* src/cyrsasl_digest.erl: Check digest-uri in SASL digest

authentication (thanks to Paul Guyot)(EJAB-569)

SVN Revision: 1743
This commit is contained in:
Badlop 2008-12-23 01:02:44 +00:00
parent 74f15f790a
commit af2fa5b5f5
2 changed files with 51 additions and 25 deletions

View File

@ -1,5 +1,8 @@
2008-12-23 Badlop <badlop@process-one.net>
* src/cyrsasl_digest.erl: Check digest-uri in SASL digest
authentication (thanks to Paul Guyot)(EJAB-569)
* src/odbc/odbc_queries.erl: Fix removal of private_storage of an
account when the account is removed
@ -7,9 +10,6 @@
account is removed (EJAB-720)
* src/mod_privacy_odbc.erl: Likewise
2008-12-19 Christophe Romain <christophe.romain@process-one.net>
2008-12-19 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue

View File

@ -18,7 +18,8 @@
-behaviour(cyrsasl).
-record(state, {step, nonce, username, authzid, get_password, auth_module}).
-record(state, {step, nonce, username, authzid, get_password, auth_module,
host}).
start(_Opts) ->
cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, true).
@ -26,9 +27,10 @@ start(_Opts) ->
stop() ->
ok.
mech_new(_Host, GetPassword, _CheckPassword) ->
mech_new(Host, GetPassword, _CheckPassword) ->
{ok, #state{step = 1,
nonce = randoms:get_string(),
host = Host,
get_password = GetPassword}}.
mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
@ -41,27 +43,35 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
bad ->
{error, "bad-protocol"};
KeyVals ->
DigestURI = xml:get_attr_s("digest-uri", KeyVals),
UserName = xml:get_attr_s("username", KeyVals),
AuthzId = xml:get_attr_s("authzid", KeyVals),
case (State#state.get_password)(UserName) of
{false, _} ->
case is_digesturi_valid(DigestURI, State#state.host) of
false ->
?DEBUG("User login not authorized because digest-uri "
"seems invalid: ~p", [DigestURI]),
{error, "not-authorized", UserName};
{Passwd, AuthModule} ->
Response = response(KeyVals, UserName, Passwd,
Nonce, AuthzId, "AUTHENTICATE"),
case xml:get_attr_s("response", KeyVals) of
Response ->
RspAuth = response(KeyVals,
UserName, Passwd,
Nonce, AuthzId, ""),
{continue,
"rspauth=" ++ RspAuth,
State#state{step = 5,
auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
_ ->
{error, "not-authorized", UserName}
true ->
AuthzId = xml:get_attr_s("authzid", KeyVals),
case (State#state.get_password)(UserName) of
{false, _} ->
{error, "not-authorized", UserName};
{Passwd, AuthModule} ->
Response = response(KeyVals, UserName, Passwd,
Nonce, AuthzId, "AUTHENTICATE"),
case xml:get_attr_s("response", KeyVals) of
Response ->
RspAuth = response(KeyVals,
UserName, Passwd,
Nonce, AuthzId, ""),
{continue,
"rspauth=" ++ RspAuth,
State#state{step = 5,
auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
_ ->
{error, "not-authorized", UserName}
end
end
end
end;
@ -75,7 +85,6 @@ mech_step(A, B) ->
?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]),
{error, "bad-protocol"}.
parse(S) ->
parse1(S, "", []).
@ -118,6 +127,23 @@ parse4([], Key, Val, Ts) ->
parse1([], "", [{Key, lists:reverse(Val)} | Ts]).
%% @doc Check if the digest-uri is valid.
%% RFC-2831 allows to provide the IP address in Host,
%% however ejabberd doesn't allow that.
%% If the service (for example jabber.example.org)
%% is provided by several hosts (being one of them server3.example.org),
%% then digest-uri can be like xmpp/server3.example.org/jabber.example.org
%% In that case, ejabberd only checks the service name, not the host.
is_digesturi_valid(DigestURICase, JabberHost) ->
DigestURI = stringprep:tolower(DigestURICase),
case catch string:tokens(DigestURI, "/") of
["xmpp", Host] when Host == JabberHost ->
true;
["xmpp", _Host, ServName] when ServName == JabberHost ->
true;
_ ->
false
end.