summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBadlop <badlop@process-one.net>2008-12-23 01:02:44 +0000
committerBadlop <badlop@process-one.net>2008-12-23 01:02:44 +0000
commitaf2fa5b5f53106e9d374ce654876f2c7e0cec0cf (patch)
tree009b1dd04a657ecf9c0006364f3595da6f974a7b /src
parent* src/odbc/odbc_queries.erl: Fix removal of private_storage of an (diff)
* src/cyrsasl_digest.erl: Check digest-uri in SASL digest
authentication (thanks to Paul Guyot)(EJAB-569) SVN Revision: 1743
Diffstat (limited to 'src')
-rw-r--r--src/cyrsasl_digest.erl70
1 files changed, 48 insertions, 22 deletions
diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
index 5395205d..0d27dbb6 100644
--- a/src/cyrsasl_digest.erl
+++ b/src/cyrsasl_digest.erl
@@ -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.