You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Thomas Eckert <th...@gmail.com> on 2013/12/03 12:27:30 UTC

make mod_auth_form tell you where the credentials came from

I have been having problems with mod_auth_form on returning DENIED from my
custom auth provider. This provider has it's own module-local session
cache, where stuff like accessible paths, credentials and the like are
stored to avoid having to query an external (and expensive) authentication
daemon. Once such a session is accessed by the user browsing (e.g. with the
corresponding session cookie) I might need to invalidate the session (e.g.
time out). After failing the appropriate checks I would "return DENIED" but
this had an unpleasant drawback: If a user accessed the session by sending
the filled-in form (e.g. on a new device with no cookie) the code would
still return DENIED if the session was invalid for whatever reason. This
resulted in the user being shown the form again, even though the user just
filled in the form correctly.

This is how I solved the problem for me:

diff --git a/modules/aaa/mod_auth_form.c b/modules/aaa/mod_auth_form.c
index 28045b5..91df0c9 100644
--- a/modules/aaa/mod_auth_form.c
+++ b/modules/aaa/mod_auth_form.c
@@ -687,6 +687,18 @@ static int get_form_auth(request_rec * r,
         }
     }

+    /* We sometimes want to know whether the user credentials came from
the HTTP body (on form submit) or from the headers (e.g. cookie).
+       At this point we know the user credentials have not been fetched
from the headers but from the body. */
+    if (*sent_user && *sent_pw) {
+      /* always attach this note to the main request, so we can find it
again later */
+      request_rec* r_main = r;
+      while (r_main->main) {
+        r_main = r_main->main;
+      }
+      ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "got user credentials
from HTTP body");
+      apr_table_set(r_main->notes, "auth_form_credentials_source",
apr_pstrdup(r->pool, "body"));
+    }
+
     /* set the user, even though the user is unauthenticated at this point
*/
     if (*sent_user) {
         r->user = (char *) *sent_user;

Is there a better solution with existing means ? If not I propose adding
the above in some way so that custom providers can work around the
described problem.

Re: make mod_auth_form tell you where the credentials came from

Posted by Thomas Eckert <th...@gmail.com>.
> Or why is it in 34 that the provider's internal session is expired?

I don't think it matters why the session is not valid anymore, as we cannot
make assumptions to the logic someone wants to implement in their custom
auth provider. In the example, however, you can just assume a time out.

> I think what is missing here is something between 32 and 33 that
> re-validates the custom auth provider's internal session, whenever valid
> user credentials where received from a filled form.

That's what I aimed for with the patch. Because the auth provider should
behave differently depending on whether the user just submitted a filled-in
form or the user's client simply sent the session cookie, that information
has to be there. I figured the r->notes table to be the 'easiest' place to
pull it from.

If there exists a way to pull/derive that information from without the
patch, I would like to know.




On Sun, Dec 8, 2013 at 12:33 PM, Micha Lenk <mi...@lenk.info> wrote:

> Hi Thomas,
>
> Am 03.12.2013 18:04, schrieb Thomas Eckert:
> > Now suppose the following
> >
> > [...]
> > 32 user fills in and submits form
> > 32 custom auth provider receives the user credentials
> > 33 custom auth provider looks up it's own session in it's module
> > internal session cache
> > 34 custom auth provider realizes the provider internal session expired
>
> I think what is missing here is something between 32 and 33 that
> re-validates the custom auth provider's internal session, whenever valid
> user credentials where received from a filled form.
>
> Or why is it in 34 that the provider's internal session is expired?
>
> Regards,
> Micha
>

Re: make mod_auth_form tell you where the credentials came from

Posted by Micha Lenk <mi...@lenk.info>.
Hi Thomas,

Am 03.12.2013 18:04, schrieb Thomas Eckert:
> Now suppose the following
> 
> [...]
> 32 user fills in and submits form
> 32 custom auth provider receives the user credentials
> 33 custom auth provider looks up it's own session in it's module
> internal session cache
> 34 custom auth provider realizes the provider internal session expired

I think what is missing here is something between 32 and 33 that
re-validates the custom auth provider's internal session, whenever valid
user credentials where received from a filled form.

Or why is it in 34 that the provider's internal session is expired?

Regards,
Micha

Re: make mod_auth_form tell you where the credentials came from

Posted by Thomas Eckert <th...@gmail.com>.
There are two type of sessions:
  * sessions by mod_session which are used to maintain a mapping between
user requests and "apache's session"
  * sessions in my custom provider, which are used to prevent accessing the
underlying auth daemon if not necessary

The custom provider itself is fairly simple, as it just registers in the
AUTHN_PROVIDER_GROUP with a simple check_password(r, user, pass) function.
The module's configuration (server config) contains a hash which I referred
to as the "module's local session cache". This module local session cache
is not visible to anything else then the custom provider module and there
is no interaction between that hash and any other part of apache - aside
from mutex locks/unlocks around it for accessing the module internal
session cache securely (worker mpm).

mod_auth_socache is not used.

> The end user has never logged in, so they get a form, they enter
credentials, they are logged in. Time passes, a session of some kind
expires (a session provided by mod_session,
> or an internal unrelated session?), and the user… has to log in again?

Basically, yes.

 1 user tries to browse protected resource
 2 user is redirected to form
 3 user fills in and submits form
 4 custom auth provider receives the user credentials
 5 custom auth provider sets up internal session
 6 custom auth provider returns OK
 7 mod_session/mod_session_cookie set up their session and cookie (a part
of this probably happens before step 4 already but that doesn't matter)
 8 user is directed to whatever was given by AuthFormLoginsuccessLocation
 9 time passes and custom provider internal session expires
10 user tries to browse protected resource, user's client submitting the
cookie
11 based on the session cookie the user name/pass is extracted
12 custom auth provider receives the user credentials
13 custom auth provider looks up it's own session in it's module internal
session cache
14 custom auth provider realizes the provider internal session expired
15 custom auth provider returns DECLINED to force the user to log in again
16 continue at step 2

Now suppose the following
<http://httpd.apache.org/docs/current/mod/mod_auth_form.html#authformloginsuccesslocation>

21 user tries to browse protected resource
22 user is redirected to form
23 user fills in and submits form
24 custom auth provider receives the user credentials
25 custom auth provider sets up internal session
26 custom auth provider returns OK
27 mod_session/mod_session_cookie set up their session and cookie
28 user is directed to whatever was given by AuthFormLoginsuccessLocation
29 time passes and custom provider internal session expires
30 user tries to browse protected resource BUT user's client DOES NOT
submit the cookie (browser private mode, different browser, completely
different device, etc.)
31 user is redirected to form
32 user fills in and submits form
32 custom auth provider receives the user credentials
33 custom auth provider looks up it's own session in it's module internal
session cache
34 custom auth provider realizes the provider internal session expired

After step 34, the custom provider should *not* return DECLINED because it
would have the user be presented with the login form even though the user
just submitted the correclty filled-in form. Instead, the custom provider
should go on using the credentials it was given.

In the custom provider, is there a way to know about the difference with
currently existing means ?



On Tue, Dec 3, 2013 at 4:45 PM, Graham Leggett <mi...@sharp.fm> wrote:

> On 03 Dec 2013, at 5:29 PM, Thomas Eckert <th...@gmail.com>
> wrote:
>
> > This whole process is important for supporting two factor authentication
> - in my example with OTP - but I doubt this is the only use case. In
> general it's a good idea to let the auth providers know where the user
> credentials came from (eg. headers vs. body).
>
> I see a possible technical solution to something, but I don't yet
> understand the problem that technical solution is trying to solve.
>
> The end user has never logged in, so they get a form, they enter
> credentials, they are logged in. Time passes, a session of some kind
> expires (a session provided by mod_session, or an internal unrelated
> session?), and the user… has to log in again?
>
> I get the sense you're fighting against httpd's AAA modules instead of
> using them. Are you using mod_auth_socache to cache the credentials or
> something else? Are you using mod_session to implement your session or
> something else?
>
> Regards,
> Graham
> --
>
>

Re: make mod_auth_form tell you where the credentials came from

Posted by Graham Leggett <mi...@sharp.fm>.
On 03 Dec 2013, at 5:29 PM, Thomas Eckert <th...@gmail.com> wrote:

> This whole process is important for supporting two factor authentication - in my example with OTP - but I doubt this is the only use case. In general it's a good idea to let the auth providers know where the user credentials came from (eg. headers vs. body).

I see a possible technical solution to something, but I don't yet understand the problem that technical solution is trying to solve.

The end user has never logged in, so they get a form, they enter credentials, they are logged in. Time passes, a session of some kind expires (a session provided by mod_session, or an internal unrelated session?), and the user… has to log in again?

I get the sense you're fighting against httpd's AAA modules instead of using them. Are you using mod_auth_socache to cache the credentials or something else? Are you using mod_session to implement your session or something else?

Regards,
Graham
--


Re: make mod_auth_form tell you where the credentials came from

Posted by Thomas Eckert <th...@gmail.com>.
I will assume a forms based login and cookie managed sessions but it is not
limited to this setup.

A user connects, is queried for authentication, submits credentials and is
subsequently allowed access. The session is established via a cookie. If
the user credentials were accepted by a custom provider, this custom
provider does not know whether the client sent the session cookie or
whether the user just filled in the authentication form but this might be
of relevance to how the custom provider has to react.

Suppose, due to internal logic (see below for an example) the custom
provider needs to confirm the user credentials by having the user log in
again. Obviously, this should not happen if the user just filled in and
submitted the form but it should happen if the user's client sent the
authentication details via the session cookie. To decide correctly the
custom provider needs to be able to discern between the credential sources.

In my case the custom provider has to maintain a module local session
cache, where each user is mapped to a cache entry in order to prevent
unnecessary calls to the underlying authentication daemon. Calls to the
daemon are costly compared to accessing the module local session cache.
Entries in the session cache can become invalid in between user requests,
e.g. by a time out. When such a session cache entry is accessed (due to a
request by the corresponding user) the time out is realized by the custom
provider and the session entry is invalidated. Now the custom provider
needs to decide whether to use the existing user credentials which were
handed down into the provider by apache or
whether to force the user to confirm the credentials by returning DECLINED
- which causes the form to be displayed again.

This whole process is important for supporting two factor authentication -
in my example with OTP - but I doubt this is the only use case. In general
it's a good idea to let the auth providers know where the user credentials
came from (eg. headers vs. body).




On Tue, Dec 3, 2013 at 1:15 PM, Graham Leggett <mi...@sharp.fm> wrote:

> On 03 Dec 2013, at 1:27 PM, Thomas Eckert <th...@gmail.com>
> wrote:
>
> > I have been having problems with mod_auth_form on returning DENIED from
> my custom auth provider. This provider has it's own module-local session
> cache, where stuff like accessible paths, credentials and the like are
> stored to avoid having to query an external (and expensive) authentication
> daemon. Once such a session is accessed by the user browsing (e.g. with the
> corresponding session cookie) I might need to invalidate the session (e.g.
> time out). After failing the appropriate checks I would "return DENIED" but
> this had an unpleasant drawback: If a user accessed the session by sending
> the filled-in form (e.g. on a new device with no cookie) the code would
> still return DENIED if the session was invalid for whatever reason. This
> resulted in the user being shown the form again, even though the user just
> filled in the form correctly.
>
> I'm not fully understanding the flow you're describing. Are you sure
> you're not accidentally password protecting / session protecting the login
> form?
>
> The login form needs to be accessible without any restrictions on
> authn/authz or session, otherwise httpd will deny access to the form too.
>
> Can you clarify the flow of requests during login that you are expecting?
>
> Regards,
> Graham
> --
>
>

Re: make mod_auth_form tell you where the credentials came from

Posted by Graham Leggett <mi...@sharp.fm>.
On 03 Dec 2013, at 1:27 PM, Thomas Eckert <th...@gmail.com> wrote:

> I have been having problems with mod_auth_form on returning DENIED from my custom auth provider. This provider has it's own module-local session cache, where stuff like accessible paths, credentials and the like are stored to avoid having to query an external (and expensive) authentication daemon. Once such a session is accessed by the user browsing (e.g. with the corresponding session cookie) I might need to invalidate the session (e.g. time out). After failing the appropriate checks I would "return DENIED" but this had an unpleasant drawback: If a user accessed the session by sending the filled-in form (e.g. on a new device with no cookie) the code would still return DENIED if the session was invalid for whatever reason. This resulted in the user being shown the form again, even though the user just filled in the form correctly.

I'm not fully understanding the flow you're describing. Are you sure you're not accidentally password protecting / session protecting the login form?

The login form needs to be accessible without any restrictions on authn/authz or session, otherwise httpd will deny access to the form too.

Can you clarify the flow of requests during login that you are expecting?

Regards,
Graham
--