You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Matt Puumala <pu...@gmail.com> on 2010/12/20 04:36:16 UTC

Set AuthName to prompt for sequential passwords

Greetings!

I am trying to make a two-factor authentication module, built on
AuthType Basic. (google for Perfect Paper Passwords for the scheme I'm
using).  To make it work, I need to be able to prompt the user to type
in two passwords sequentially.

So, the user comes to the page, apache sends "401 AuthRequired" and
the configured AuthName (this is prompt 1).

The user enters username and first password. The module verifies, and
constructs the second prompt.

In my plan, I'd like to set the AuthName for that client, then send
back "401 AuthRequired" again. The new AuthName realm is prompt 2,
which is shown to the user.

However, I'm having problems changing the AuthName.

I'm starting with extremely simple test bed, using output files to
dump data.

I expected the "Old Auth Name" to be "Testing the Thing", and the "New
Auth Name" to be "Simple String". But the Auth Name doesn't change.

This is my first apache module. Is there something in the intricacies
of the request cycle that I'm missing? Or is there some other obviously
better way to prompt for passwords sequentially?


Server: Windows XP running XAMPP.
Server version: Apache/2.2.14 (Win32)
Server built:   Nov 11 2009 14:29:03
mod_perl/2.0.4 Perl/v5.10.1

------- Auth Handler Skeleton ---------------
package CustomAuth::AuthTwoPW;

use strict;
use Apache2::Const qw(:common);
use Apache2::Access ();

sub handler
{
  my $r = shift;
  my($res, $sent_pw) = $r->get_basic_auth_pw;

  # debug output
   my $FH;
   open  $FH, ">", "/Documents and Settings/Matt/Desktop/stuff.txt";
   my $stoij = "response is " . $res . "\nSent pw is " . $sent_pw . "\n";
  print $FH $stoij;

  return $res if $res != OK;

  my $user = $r->connection->user;
  unless($user eq "matt" and $sent_pw eq "pw1")
  {

    print $FH "Didnt get good pw, returning AUTH_REQUIRED\n";

    $r->note_basic_auth_failure;
    $r->log_error("Didn't get good first password",
		   $r->filename);
    return AUTH_REQUIRED;
  }

  # Got first username/pw combo. RESET, change prompts, and get next set

  # reset prompts
  my $oldval = $r->auth_name("Simple String");
  my $newval = $r->auth_name();

  print $FH "Old authname val is " . $oldval . "\n";
  print $FH "New authname val is " . $newval . "\n";

  # Reset headers so client auth's again
  $r->note_basic_auth_failure;

  # ask for second pw
  return AUTH_REQUIRED;


} # closes 'handler'

1;
------- END Auth Handler Skeleton ---------------

------- Debug File Output -----------------
response is 0
Sent pw is pw1
Old authname val is Testing The Thing
New authname val is Testing The Thing
------- END Debug File Output -----------------


------- ModPerl Config ----------------------
LoadFile "C:/Documents and Settings/Matt/My
Documents/xampp/perl/bin/perl510.dll"
LoadModule perl_module modules/mod_perl.so
LoadModule apreq_module modules/mod_apreq2.so

PerlSwitches -T
PerlPostConfigRequire "C:/Documents and Settings/Matt/My
Documents/xampp/apache/conf/extra/startup.pl"


...[ snip ]...


<Directory "C:/Documents and Settings/Matt/My
Documents/xampp/htdocs/authenticatedstuff">
  SetHandler perl-script
  AuthName "Testing The Thing"
  AuthType Basic
  PerlOptions +GlobalRequest
  PerlAuthenHandler CustomAuth::AuthTwoPW
  require valid-user
</Directory>


# ASP settings
Include "conf/extra/asp.conf"
------- END ModPerl Config ----------------------

Re: Set AuthName to prompt for sequential passwords

Posted by Matt Puumala <pu...@gmail.com>.
Thank you so much for the insight. Your thoughts are very
valuable. I'll be digging into the CookieAuth module to see what I can
see. After I look at it just a bit, it may be that I can just use
CookieAuth as it is, or with minor tweaks and a big authentication
routine. It would deny authentication, but set a different cookie after
"phase 1"; and grant authentication with a good "phase 1" cookie and
proper "phase 2" responses.

You'll hear from me again, as I find other questions, or if a miracle
happens and I complete the project and get something that works.

Thank you again!

Matt

On Mon, Dec 20, 2010 at 6:40 PM, André Warnier <aw...@ice-sa.com> wrote:
>
> Talking about HTTP authentication, that's a good plan.
> Unfortunately sometimes difficult to follow, because HTTP authentication is
> full of twists and turns that don't usually let you do things stepwise.
>
> There is already plenty of stuff in the above paragraph to be answered.
>
> What the browser displays in the title bar of its embedded authentication
> mechanism, is nothing else than the content of the "realm" of the "auth
> required" header that it receives back from the server.  So you could
> "trick" that by fabricating this header (and the 401 response) yourself,
> instead of letting Apache send it.

...  [snip]...

Re: Set AuthName to prompt for sequential passwords

Posted by André Warnier <aw...@ice-sa.com>.
Matt Puumala wrote:
> Thank you for the reply!
> 
> I am with you 100%. There are plans for the session db, and the cookie
> format, all on the drawing boards, to get past "stateless http". But
> I'm trying to do it stepwise, to save my sanity.

Talking about HTTP authentication, that's a good plan.
Unfortunately sometimes difficult to follow, because HTTP authentication is full of twists 
and turns that don't usually let you do things stepwise.

> 
> So for now the question is: How do I actually prompt the user for the
> passwords? My reason for using Basic Auth and changing the realm is to
> make use of browsers' built-in popup auth mechanism. Is my solution of
> just authenticating twice naive? Is there a way to control that
> mechanism more manually (this is where my "change the AuthName in
> code" idea came from)? If not that, then...? Create an HTML form on
> the fly? (My gut says "eww" to that.) Any ideas you might have, including
> where to go to read more, are welcome.
> 
There is already plenty of stuff in the above paragraph to be answered.

What the browser displays in the title bar of its embedded authentication mechanism, is 
nothing else than the content of the "realm" of the "auth required" header that it 
receives back from the server.  So you could "trick" that by fabricating this header (and 
the 401 response) yourself, instead of letting Apache send it.
When the browser response will come back, it will have an "Authorization" header 
containing this same "realm" part that you sent, and since it is your authentication 
module catching this new request, you can deal with it too.
I am also quite sure that you could, with mod_perl, go and play games with Apache to 
change it's notion of the "realm" you are in.  But what I am not so sure of, are the 
unforeseen side-effects of doing that.

So I do believe that with your scheme, it may be better to go right away to your own login 
pages.  You can either create them on-the-fly, or have a template on disk with some 
pre-defined kind of markers which you would replace by whatever message you want to place 
there.  Which could even be things such as
<input name="hidden_param_1" type="hidden" value="%%%param_1%%%">
<input name="hidden_param_2" type="hidden" value="%%%param_2%%%">
...
which you find with a perl regexp and replace on the fly before sending the page to the 
user.  Then when the user re-posts that form (remember, maybe 30 minutes later), you can 
re-read these parameters to remember where you're at.  That may replace the cookie.
Provided that you do not give the opportunity for an ill-intentioned user to save the 
received form to disk, play with the hidden values, and then re-post the modified form and 
gain some advantage by doing so.

For more ideas, the Apache::AuthCookie module and the other Apache::Auth* on CPAN are a 
good start.

I think that the main thing to keep in mind, is that whenever you send back a response to 
the browser (whether it is a 401 or a 200 or whatever), the current request/response cycle 
is finished, done, forgotten, and the next request your module handles may be in 3 hours, 
come from another browser in another country, and be handled by another Apache child 
running another perl interpreter and another copy of your Auth module.
And if this new request happens to be a second one from a browser with which you 
interacted before, you have to be able to tell that only by the content of this new 
request. (Whether that is because it contains a cookie, or because it posts some special 
parameter from a form is a matter of choice, it is not essential in the overall logic).
And never trust what the browser sends.  It may not even be a browser.

Apache+mod_perl AAA is very powerful, and fun.  It can also quickly become very messy.



Re: Set AuthName to prompt for sequential passwords

Posted by Matt Puumala <pu...@gmail.com>.
Thank you for the reply!

I am with you 100%. There are plans for the session db, and the cookie
format, all on the drawing boards, to get past "stateless http". But
I'm trying to do it stepwise, to save my sanity.

So for now the question is: How do I actually prompt the user for the
passwords? My reason for using Basic Auth and changing the realm is to
make use of browsers' built-in popup auth mechanism. Is my solution of
just authenticating twice naive? Is there a way to control that
mechanism more manually (this is where my "change the AuthName in
code" idea came from)? If not that, then...? Create an HTML form on
the fly? (My gut says "eww" to that.) Any ideas you might have, including
where to go to read more, are welcome.

Also, you mention that secure areas should "require a cookie". You've
anticipated my next question...  BUT!!! I'll start a new thread
later, if I can't find answers in my reading.

Again, thanks for your thoughts!

Matt


On Mon, Dec 20, 2010 at 3:46 AM, André Warnier <aw...@ice-sa.com> wrote:
> Hi.
>
> Without going into the details of your code, I believe that what you are
> bumping against may be the very nature of HTTP.
>
> In your scheme, you need 2 consecutive interactions with the user, and the
> second one needs to be able to "remember" what the first one was.
> The basic logic of HTTP goes against that : each request/response cycle is
> totally independent of the others, and there is no "memory" kept between two
> transactions.
> At least not by HTTP itself. Think that between your first interaction, and
> the second, there may have been 1000 other request/response cycles happening
> for other users.
>
> So the only way to do this, is by super-imposing some kind of "session"
> mechanism, whereby the server can detect, on the second request, that there
> has been a first one, and what its results were.
> There are various such schemes, but the simplest mechanism for doing that is
> probably via cookies.
> Your first request/response should set a "step 1 cookie", which is detected
> and read by the second request/response cycle, which then modifies that
> cookie into a "step 2 cookie".
> Your real application areas should then require the step 2 cookie for
> authenticating a user and granting the resource.
>
> I think that trying to do this by playing with the "realm", which is
> intimately linked to the URL requested by the browser, is going to lead you
> into loops of logic.
>
>
>
> Matt Puumala wrote:
>> [ snip ]

Re: Set AuthName to prompt for sequential passwords

Posted by David Nicol <da...@gmail.com>.
> Matt Puumala wrote:
>>
>> Greetings!
>>
>> I am trying to make a two-factor authentication module, built on
>> AuthType Basic. (google for Perfect Paper Passwords for the scheme I'm
>> using).  To make it work, I need to be able to prompt the user to type
>> in two passwords sequentially.


my thought is that the two basic authentications would make sense at
two separate virtual domains.

Firstly, the client would authenticate to
http://step1.example.org/step1, after which they would be directed to
step2.example.org/step2/XYZABC where XYZABC is a one-time-use,
hard-to-guess code generated by step 1 and stored somewhere step2 can
see it.

step1 and step2 are different domains, the authentication starts all
over for step2, the infrastructure has now clue that they are two
steps in your process.

After passing the test at step2, the paranoia really starts.

Re: Set AuthName to prompt for sequential passwords

Posted by André Warnier <aw...@ice-sa.com>.
Hi.

Without going into the details of your code, I believe that what you are bumping against 
may be the very nature of HTTP.

In your scheme, you need 2 consecutive interactions with the user, and the second one 
needs to be able to "remember" what the first one was.
The basic logic of HTTP goes against that : each request/response cycle is totally 
independent of the others, and there is no "memory" kept between two transactions.
At least not by HTTP itself. Think that between your first interaction, and the second, 
there may have been 1000 other request/response cycles happening for other users.

So the only way to do this, is by super-imposing some kind of "session" mechanism, whereby 
the server can detect, on the second request, that there has been a first one, and what 
its results were.
There are various such schemes, but the simplest mechanism for doing that is probably via 
cookies.
Your first request/response should set a "step 1 cookie", which is detected and read by 
the second request/response cycle, which then modifies that cookie into a "step 2 cookie".
Your real application areas should then require the step 2 cookie for authenticating a 
user and granting the resource.

I think that trying to do this by playing with the "realm", which is intimately linked to 
the URL requested by the browser, is going to lead you into loops of logic.



Matt Puumala wrote:
> Greetings!
> 
> I am trying to make a two-factor authentication module, built on
> AuthType Basic. (google for Perfect Paper Passwords for the scheme I'm
> using).  To make it work, I need to be able to prompt the user to type
> in two passwords sequentially.
> 
> So, the user comes to the page, apache sends "401 AuthRequired" and
> the configured AuthName (this is prompt 1).
> 
> The user enters username and first password. The module verifies, and
> constructs the second prompt.
> 
> In my plan, I'd like to set the AuthName for that client, then send
> back "401 AuthRequired" again. The new AuthName realm is prompt 2,
> which is shown to the user.
> 
> However, I'm having problems changing the AuthName.
> 
> I'm starting with extremely simple test bed, using output files to
> dump data.
> 
> I expected the "Old Auth Name" to be "Testing the Thing", and the "New
> Auth Name" to be "Simple String". But the Auth Name doesn't change.
> 
> This is my first apache module. Is there something in the intricacies
> of the request cycle that I'm missing? Or is there some other obviously
> better way to prompt for passwords sequentially?
> 
> 
> Server: Windows XP running XAMPP.
> Server version: Apache/2.2.14 (Win32)
> Server built:   Nov 11 2009 14:29:03
> mod_perl/2.0.4 Perl/v5.10.1
> 
> ------- Auth Handler Skeleton ---------------
> package CustomAuth::AuthTwoPW;
> 
> use strict;
> use Apache2::Const qw(:common);
> use Apache2::Access ();
> 
> sub handler
> {
>   my $r = shift;
>   my($res, $sent_pw) = $r->get_basic_auth_pw;
> 
>   # debug output
>    my $FH;
>    open  $FH, ">", "/Documents and Settings/Matt/Desktop/stuff.txt";
>    my $stoij = "response is " . $res . "\nSent pw is " . $sent_pw . "\n";
>   print $FH $stoij;
> 
>   return $res if $res != OK;
> 
>   my $user = $r->connection->user;
>   unless($user eq "matt" and $sent_pw eq "pw1")
>   {
> 
>     print $FH "Didnt get good pw, returning AUTH_REQUIRED\n";
> 
>     $r->note_basic_auth_failure;
>     $r->log_error("Didn't get good first password",
> 		   $r->filename);
>     return AUTH_REQUIRED;
>   }
> 
>   # Got first username/pw combo. RESET, change prompts, and get next set
> 
>   # reset prompts
>   my $oldval = $r->auth_name("Simple String");
>   my $newval = $r->auth_name();
> 
>   print $FH "Old authname val is " . $oldval . "\n";
>   print $FH "New authname val is " . $newval . "\n";
> 
>   # Reset headers so client auth's again
>   $r->note_basic_auth_failure;
> 
>   # ask for second pw
>   return AUTH_REQUIRED;
> 
> 
> } # closes 'handler'
> 
> 1;
> ------- END Auth Handler Skeleton ---------------
> 
> ------- Debug File Output -----------------
> response is 0
> Sent pw is pw1
> Old authname val is Testing The Thing
> New authname val is Testing The Thing
> ------- END Debug File Output -----------------
> 
> 
> ------- ModPerl Config ----------------------
> LoadFile "C:/Documents and Settings/Matt/My
> Documents/xampp/perl/bin/perl510.dll"
> LoadModule perl_module modules/mod_perl.so
> LoadModule apreq_module modules/mod_apreq2.so
> 
> PerlSwitches -T
> PerlPostConfigRequire "C:/Documents and Settings/Matt/My
> Documents/xampp/apache/conf/extra/startup.pl"
> 
> 
> ...[ snip ]...
> 
> 
> <Directory "C:/Documents and Settings/Matt/My
> Documents/xampp/htdocs/authenticatedstuff">
>   SetHandler perl-script
>   AuthName "Testing The Thing"
>   AuthType Basic
>   PerlOptions +GlobalRequest
>   PerlAuthenHandler CustomAuth::AuthTwoPW
>   require valid-user
> </Directory>
> 
> 
> # ASP settings
> Include "conf/extra/asp.conf"
> ------- END ModPerl Config ----------------------
>