5
votes

I would like to have my Plack app try several different means of authorizing the user. Specifically, check if the user is already authorized via a session cookie, then check for Digest authentication and then fall back to Basic.

I figured I could just enable a bunch of Auth handlers in the order I wanted them to be checked (Session, Digest, Basic). Unfortunately, the way that Plack::Middleware::Auth::Digest and Plack::Middleware::Auth::Basic are written they both return 401 if digest or basic auth doesn't exist, respectively.

How is this normally dealt with in Plack?

2
Don't have an answer for you, but isn't 404 is completely wrong for that?ysth
Right, 40one11111 (damn comment limit)Schwern
@ysth Yeah, that's one of the things miyagawa suggested when I asked him. More importantly, I'm more deeply redesigning this project so it doesn't require effectively writing its own framework in raw Plack to match its historical quirks. Then I can use Catalyst or Dancer or something.Schwern

2 Answers

4
votes

I do not have an implementation but I think I have the approach. You can do this "in-line" with Plack::Middleware::Conditional. So it would look like this but you'll have to fill in the missing conditions/tests. I didn't see an easy/obvious way but I suspect you might. Since you have the $env to pass around you should be able to set/check HTTP_/session stuff in the order you want and keep the state for the next handler to know if it should be enabled or not.

use Plack::Builder;

my $app = sub {
    [ 200,
      [ "Content-Type" => "text/plain" ],
      [ "O HAI, PLAK!" ]
    ];
};

builder {
    enable "Session::Cookie";
    enable_if { my $env = shift;
                # I don't know...
            } "Auth::Digest",
                realm => "Secured", secret => "BlahBlah",
                    authenticator => sub { $_[0] eq $_[1] };
    enable_if { my $env = shift;
                # I don't know...
            } "Auth::Basic",
                authenticator => sub { $_[0] eq $_[1] };
    $app;
};
2
votes

I think you are going to need to write your own middleware, since ideally (based on a very quick read of RFC 2617) when not authenticated you would return a WWW-Authenticate header with both Basic and Digest challenges (with Basic first, for user agents that only understand Basic).