esl / MongooseIM

MongooseIM is Erlang Solutions' robust, scalable and efficient XMPP server, aimed at large installations. Specifically designed for enterprise purposes, it is fault-tolerant and can utilise the resources of multiple clustered machines.
Other
1.67k stars 428 forks source link

Can't set up http auth in mongooseim #358

Closed vooolll closed 9 years ago

vooolll commented 9 years ago

I set the following configuration for http authentication:

{auth_opts, [ {basic_auth, "user:password"}, % tested with and without this key {host, "http://localhost:8000"}, {path_prefix, "/chat/"} % default ]}.

My log:

2015-01-20 05:24:41.296 [info] <0.676.0>@ejabberd_listener:accept:305 (#Port<0.5197>) Accepted connection {{10,0,2,2},39589} -> {{10,0,2,15},5279} 2015-01-20 05:24:41.298 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "<?xml version='1.0' ?>" 2015-01-20 05:24:41.299 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = [60,63,120,109,108,32,118,101,114,115,105,111,110,61,39,49,46,48,39,63,62,60,115,116,114,101,97,109,58,115,116,114,101,97,109,32,120,109,108,110,115,61,39,106,97,98,98,101,114,58,99,108,105,101,110,116,39,32,120,109,108,110,115,58,115,116,114,101,97,109,61,39,104,116,116,112,58,47,47,101,116,104,101,114,120,46,106,97,98,98,101,114,46,111,114,103,47,115,116,114,101,97,109,115,39,32,105,100,61,39,"3164976318",39,32,102,114,111,109,61,39,"localhost",39,[" version='","1.0","'"],[" xml:lang='","en","'"],62] 2015-01-20 05:24:41.300 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"stream:featuresDIGEST-MD5SCRAM-SHA-1PLAIN/stream:features">> 2015-01-20 05:24:41.305 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.305 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,0,1421731481299419}, Size=51 M=25.5, I=6.024 2015-01-20 05:24:41.305 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.306 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,979.8647402397787,1421731481325443}, Size=0 M=0.0, I=-19.449 2015-01-20 05:24:41.329 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.329 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,489.93237011988936,1421731481325994}, Size=0 M=0.0, I=3.229 2015-01-20 05:24:41.337 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.337 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,244.96618505994468,1421731481329223}, Size=0 M=0.0, I=7.972 2015-01-20 05:24:41.340 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.340 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,122.48309252997234,1421731481337195}, Size=114 M=60.718494489413736, I=3.445 2015-01-20 05:24:41.341 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = [60,63,120,109,108,32,118,101,114,115,105,111,110,61,39,49,46,48,39,63,62,60,115,116,114,101,97,109,58,115,116,114,101,97,109,32,120,109,108,110,115,61,39,106,97,98,98,101,114,58,99,108,105,101,110,116,39,32,120,109,108,110,115,58,115,116,114,101,97,109,61,39,104,116,116,112,58,47,47,101,116,104,101,114,120,46,106,97,98,98,101,114,46,111,114,103,47,115,116,114,101,97,109,115,39,32,105,100,61,39,"2285106403",39,32,102,114,111,109,61,39,"localhost",39,[" version='","1.0","'"],[" xml:lang='","en","'"],62] 2015-01-20 05:24:41.342 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"stream:featuresDIGEST-MD5SCRAM-SHA-1PLAIN/stream:features">> 2015-01-20 05:24:41.399 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "" 2015-01-20 05:24:41.399 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,0,1421731481341852}, Size=162 M=81.0, I=57.41 2015-01-20 05:24:41.399 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"bm9uY2U9IjM2NzM2NDg2Iixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz">> 2015-01-20 05:24:41.424 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "dXNlcm5hbWU9InVzZXIiLHJlYWxtPSJsb2NhbGhvc3QiLG5vbmNlPSIzNjczNjQ4NiIsY25vbmNlPSJEVnI3dTI0andnalBjaDN0NlgyRXBESE9jWWRhQm1ZY0NQVitXNjdqazdzPSIsbmM9MDAwMDAwMDEscW9wPWF1dGgsZGlnZXN0LXVyaT0ieG1wcC9sb2NhbGhvc3QiLHJlc3BvbnNlPTA2MTM3M2VkYTFhMTdlNWFkNWRmNTRkOTYxZDM3MDFiLGNoYXJzZXQ9dXRmLTg=" 2015-01-20 05:24:41.425 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,994.9637636653973,1421731481423262}, Size=342 M=340.2862380835981, I=1.275 2015-01-20 05:24:41.425 [debug] <0.717.0>@ejabberd_auth_http:make_req:243 Making request 'get_password' for user user@localhost... 2015-01-20 05:24:41.825 [debug] <0.717.0>@ejabberd_auth_http:make_req:251 Request result: 200: <<>> 2015-01-20 05:24:41.825 [debug] <0.717.0>@ejabberd_auth_http:make_req:243 Making request 'get_password' for user user@localhost... 2015-01-20 05:24:41.830 [debug] <0.717.0>@ejabberd_auth_http:make_req:251 Request result: 200: <<>> 2015-01-20 05:24:41.830 [info] <0.717.0>@ejabberd_c2s:wait_for_sasl_response:893 ({socket_state,ejabberd_tls,{tlssock,#Port<0.5197>,#Port<0.5199>},<0.716.0>}) Failed authentication for user@localhost from IP 10.0.2.2 ({{10,0,2,2},39589}) 2015-01-20 05:24:41.830 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"">> 2015-01-20 05:24:41.831 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "AHVzZXIAMTIzNDU=" 2015-01-20 05:24:41.831 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,998.5440750786147,1421731481764537}, Size=179 M=178.73976831686485, I=66.689 2015-01-20 05:24:41.831 [debug] <0.717.0>@ejabberd_auth_http:make_req:243 Making request 'check_password' for user user@localhost... 2015-01-20 05:24:41.835 [debug] <0.717.0>@ejabberd_auth_http:make_req:251 Request result: 200: <<>> 2015-01-20 05:24:41.836 [info] <0.717.0>@ejabberd_c2s:wait_for_feature_request:734 ({socket_state,ejabberd_tls,{tlssock,#Port<0.5197>,#Port<0.5199>},<0.716.0>}) Failed authentication for user@localhost from IP 10.0.2.2 ({{10,0,2,2},39589}) 2015-01-20 05:24:41.836 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"">> 2015-01-20 05:24:41.945 [debug] <0.716.0>@ejabberd_receiver:process_data:336 Received XML on stream = "/stream:stream" 2015-01-20 05:24:41.945 [debug] <0.716.0>@shaper:update:69 State: {maxrate,1000,997.3548361524668,1421731481944226}, Size=16 M=15.957789033362387, I=1.258 2015-01-20 05:24:41.945 [debug] <0.717.0>@ejabberd_c2s:send_text:1725 Send XML on stream = "/stream:stream"

First of all at the wiki there is written that check_password, user_exists, is ok for custom token authentication.

I try to implement this two methods but it is still invoking the get_password. Then I try to implement it. In ejabberd log there is ok responce in each request. Even more I can show you my web server log:

[20/Jan/2015 05:24:41] "GET /chat/get_password?user=user&server=localhost&pass= HTTP/1.1" 200 4 [20/Jan/2015 05:24:41] "GET /chat/get_password?user=user&server=localhost&pass= HTTP/1.1" 200 4 [20/Jan/2015 05:24:41] "GET /chat/check_password?user=user&server=localhost&pass=12345 HTTP/1.1" 200 4

I think the problem is in content type what it should be?

my response from courl looks like this: HTTP/1.0 200 OK Date: Tue, 20 Jan 2015 06:20:34 GMT Server: WSGIServer/0.1 Python/2.7.6 Vary: Accept, Accept-Language Content-Type: application/json Content-Language: en-us Allow: GET, HEAD, OPTIONS

"true"

Please help me, what is wrong with my configuration?

I made a bit debugging work:

-spec check_password(binary(), binary(), binary()) -> boolean().
check_password(User, Server, Password) ->
    {LUser, LServer} = stringprep(User, Server),
    case scram:enabled(Server) of
        false ->
            ?DEBUG("Check pass: ~s", ["invoked"]),
            case make_req(get, <<"check_password">>, LUser, LServer, Password) of
                {ok, <<"true">>} ->
                  ?DEBUG("Checking status: ~s", ["success"]),
                  true;
                _ ->
                  ?DEBUG("Checking status: ~s", ["error"]),
                  false
            end;
        true ->
            {ok, true} =:= verify_scram_password(LUser, LServer, Password)
    end.

using this I figure out that my response doesn't match {ok, <<"true">>} . How can I fix it (should I supply different content type or do other stuff) ?

fenek commented 9 years ago

Hi vooolll,

Can you please share your ejabberd.cfg file? You can either paste it somewhere or send it directly to me (you can find my e-mail on my profile page).

I've noticed something. It seems that your client chooses to authenticate with DIGEST-MD5 mechanism, what is a correct, standard behaviour (to pick the best mechanism available) but the wiki page states explicitly: "Client side: MUST NOT use DIGEST-MD5 mechanism; use PLAIN". Or at least it seems the case but some important log parts were removed by GitHub. Can you please update the issue and repaste the log, surrounded by code block?

fenek commented 9 years ago

Oh and another thing: If what you've pasted is an exact response, then another comment on wiki page applies: "If specific value is expected in response body, it MUST NOT be put in quotes!". And it looks like you return "true" in body, not true. Now I think that perhaps I should have formatted these more clearly...

vooolll commented 9 years ago

Thank you for your response. The error was in my web server. How can I check out what type of xmpp authentication comming, DIGEST-MD5 or PLAIN? May I consider that encrypted connection comming when the ejabberd_auth_http invokes get_password endpoint?

fenek commented 9 years ago

Since the log you've pasted is kind of corrupted, I can only guess: I think your client library tried DIGEST-MD5 first and then PLAIN. get_password is required for DIGEST-MD5 only, so you shouldn't need this endpoint after all. My opinion is that MIM and auth server should communicate over internal network, so encryption is not that necessary but of course it won't hurt to be a bit cautious and use HTTPS.

Anyway, by observing "Send XML" and "Received XML" debug logs on server side you can learn what server and client are talking about. Look for plain strings like DIGEST-MD5 and PLAIN.

vooolll commented 9 years ago

Thank you so much. I should read more about mongooseim and xmpp protocol. Sory for wasting your time.

fenek commented 9 years ago

This time wasn't wasted. You have learnt something new and I have learnt that the wiki page was not clear enough. :)

vooolll commented 9 years ago

I can't make get_password work properly when DIGEST-MD5 used,

I suppose the function check_password invoked:

-spec check_password(binary(), binary(), binary(), binary(), fun()) -> boolean().
check_password(User, Server, Password, Digest, DigestGen) ->

So I try to debug it:

-spec check_password(binary(), binary(), binary(), binary(), fun()) -> boolean().
check_password(User, Server, Password, Digest, DigestGen) ->
    {LUser, LServer} = stringprep(User, Server),
    case make_req(get, <<"get_password">>, LUser, LServer, <<"">>) of
        {error, _} ->
            false;
        {ok, GotPasswd} ->
            ?DEBUG("GotPasswd : ~s", [GotPasswd]),
            case scram:enabled(LServer) of
                true ->
                    case scram:deserialize(GotPasswd) of
                        {ok, #scram{storedkey = StoredKey}} ->
                            ?DEBUG("Scram : ~s", ["used"]),
                            Passwd = base64:decode(StoredKey),
                            ejabberd_auth:check_digest(Digest, DigestGen, Password, Passwd);
                        _ ->
                            false
                    end;
                false ->
                    ?DEBUG("Scram : ~s", ["Scram is not used"]),
                    ejabberd_auth:check_digest(Digest, DigestGen, Password, GotPasswd)
            end
    end.

In log I have the message that there is no scram usage. I try to pass my password as plain text. Please, check out log:

2015-01-22 10:23:44.125 [debug] <0.693.0>@ejabberd_auth_http:make_req:254 Making request 'get_password' for user 5@localhost... 2015-01-22 10:23:44.142 [debug] <0.693.0>@ejabberd_auth_http:make_req:262 Request result: 200: <<"\"91db10157fe0f2e05577d3db382b87e7b3964e06\"">> 2015-01-22 10:23:44.143 [debug] <0.693.0>@ejabberd_auth_http:make_req:254 Making request 'get_password' for user 5@localhost... 2015-01-22 10:23:44.155 [debug] <0.693.0>@ejabberd_auth_http:make_req:262 Request result: 200: <<"\"91db10157fe0f2e05577d3db382b87e7b3964e06\"">> 2015-01-22 10:23:44.155 [debug] <0.693.0>@ejabberd_auth_http:check_password:93 GotPasswd : "91db10157fe0f2e05577d3db382b87e7b3964e06" 2015-01-22 10:23:44.155 [debug] <0.693.0>@ejabberd_auth_http:check_password:105 Scram : Scram is not used 2015-01-22 10:23:44.156 [info] <0.693.0>@ejabberd_c2s:wait_for_sasl_response:893 ({socket_state,ejabberd_tls,{tlssock,#Port<0.5355>,#Port<0.5357>},<0.692.0>}) Failed authentication for 5@localhost from IP 10.0.2.2 ({{10,0,2,2},47863}) 2015-01-22 10:23:44.156 [debug] <0.693.0>@ejabberd_c2s:send_text:1725 Send XML on stream = <<"">>

You said me about quotes yesterday, I try to skip it but it sends it anyway. May be I should use specific http content type for that?

vooolll commented 9 years ago

Solved, it was my server specific problem. Thank you. May I pull request http authentication into example directory ?

fenek commented 9 years ago

Sure! All contributions are always welcome. :)