]> granicus.if.org Git - ejabberd/commitdiff
* src/cyrsasl_digest.erl: Check digest-uri in SASL digest
authorBadlop <badlop@process-one.net>
Tue, 23 Dec 2008 01:02:44 +0000 (01:02 +0000)
committerBadlop <badlop@process-one.net>
Tue, 23 Dec 2008 01:02:44 +0000 (01:02 +0000)
authentication (thanks to Paul Guyot)(EJAB-569)

SVN Revision: 1743

ChangeLog
src/cyrsasl_digest.erl

index b47c2703e76a34664c82d4e26272d99b4d06d90a..f6d6e2e2d1c28a0ed4da2bb1360bc67f39d4e68f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
 
index 45d2991e9335dc5abd5ac6132da8356b81739d24..1e40e1437fe289333da26ae25b71e76827c4eaa3 100644 (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, "", []).
 
@@ -116,6 +125,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.