X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FAuthentication%2FCredential%2FHTTP.pm;h=ba69bdccc77b570d2af0264908ed5d1e6b06f9ee;hb=f366138eaad19d73e63a638197e8c99e858d54d6;hp=b14e575d866c98cb7708f968b58a229d5cc3eebc;hpb=ac92fd52e650f58ec34dfb078551854880b73d2e;p=catagits%2FCatalyst-Authentication-Credential-HTTP.git diff --git a/lib/Catalyst/Plugin/Authentication/Credential/HTTP.pm b/lib/Catalyst/Plugin/Authentication/Credential/HTTP.pm index b14e575..ba69bdc 100644 --- a/lib/Catalyst/Plugin/Authentication/Credential/HTTP.pm +++ b/lib/Catalyst/Plugin/Authentication/Credential/HTTP.pm @@ -11,7 +11,7 @@ use URI::Escape (); use Catalyst (); use Digest::MD5 (); -our $VERSION = "0.05"; +our $VERSION = "0.09"; sub authenticate_http { my ( $c, @args ) = @_; @@ -22,7 +22,12 @@ sub authenticate_http { sub get_http_auth_store { my ( $c, %opts ) = @_; - $opts{store} || $c->config->{authentication}{http}{store}; + + my $store = $opts{store} || $c->config->{authentication}{http}{store} || return; + + return ref $store + ? $store + : $c->get_auth_store($store); } sub authenticate_basic { @@ -68,7 +73,7 @@ sub authenticate_digest { } split /,\s?/, substr( $authorization, 7 ); #7 == length "Digest " my $opaque = $res{opaque}; - my $nonce = $c->_get_digest_authorization_nonce( __PACKAGE__ . '::opaque:' . $opaque ); + my $nonce = $c->get_digest_authorization_nonce( __PACKAGE__ . '::opaque:' . $opaque ); next unless $nonce; $c->log->debug('Checking authentication parameters.') @@ -101,11 +106,12 @@ sub authenticate_digest { my $realm = $res{realm}; my $user; - my $store = $opts{store} - || $c->config->{authentication}{http}{store} - || $c->default_auth_store; - $user = $store->get_user($username) if $store; + unless ( $user = $opts{user} ) { + if ( my $store = $c->get_http_auth_store(%opts) || $c->default_auth_store ) { + $user = $store->get_user($username); + } + } unless ($user) { # no user, no authentication $c->log->debug('Unknown user: $user.') if $c->debug; @@ -189,6 +195,10 @@ sub authorization_required_response { my ( $c, %opts ) = @_; $c->res->status(401); + $c->res->content_type('text/plain'); + $c->res->body($c->config->{authentication}{http}{authorization_required_message} || + $opts{authorization_required_message} || + 'Authorization required.'); # *DONT* short circuit my $ok; @@ -247,7 +257,7 @@ sub _build_auth_header_domain { my ( $c, $opts ) = @_; if ( my $domain = $opts->{domain} ) { - Catalyst::Excpetion->throw("domain must be an array reference") + Catalyst::Exception->throw("domain must be an array reference") unless ref($domain) && ref($domain) eq "ARRAY"; my @uris = @@ -272,7 +282,7 @@ sub _build_auth_header_common { sub _build_basic_auth_header { my ( $c, $opts ) = @_; - return $c->_join_auth_header_parts( Basic => $c->_build_auth_header_common ); + return $c->_join_auth_header_parts( Basic => $c->_build_auth_header_common( $opts ) ); } sub _build_digest_auth_header { @@ -282,7 +292,7 @@ sub _build_digest_auth_header { my $key = __PACKAGE__ . '::opaque:' . $nonce->opaque; - $c->_store_digest_authorization_nonce( $key, $nonce ); + $c->store_digest_authorization_nonce( $key, $nonce ); return $c->_join_auth_header_parts( Digest => $c->_build_auth_header_common($opts), @@ -302,11 +312,9 @@ sub _digest_auth_nonce { my $nonce = $package->new; - my $algorithm = $opts->{algorithm} - || $c->config->{authentication}{http}{algorithm} - || $nonce->algorithm; - - $nonce->algorithm( $algorithm ); + if ( my $algorithm = $opts->{algorithm} || $c->config->{authentication}{http}{algorithm}) { + $nonce->algorithm( $algorithm ); + } return $nonce; } @@ -316,14 +324,14 @@ sub _join_auth_header_parts { return "$type " . join(", ", @parts ); } -sub _get_digest_authorization_nonce { +sub get_digest_authorization_nonce { my ( $c, $key ) = @_; $c->_check_cache; $c->cache->get( $key ); } -sub _store_digest_authorization_nonce { +sub store_digest_authorization_nonce { my ( $c, $key, $nonce ) = @_; $c->_check_cache; @@ -362,13 +370,13 @@ __END__ =head1 NAME Catalyst::Plugin::Authentication::Credential::HTTP - HTTP Basic and Digest authentication -for Catlayst. +for Catalyst. =head1 SYNOPSIS use Catalyst qw/ Authentication - Authentication::Store::Moose + Authentication::Store::Minimal Authentication::Credential::HTTP /; @@ -403,27 +411,112 @@ This moduule lets you use HTTP authentication with L. Both basic and digest authentication are currently supported. +When authentication is required, this module sets a status of 401, and +the body of the response to 'Authorization required.'. To override +this and set your own content, check for the C<< $c->res->status == +401 >> in your C action, and change the body accordingly. + +=head2 TERMS + +=over 4 + +=item Nonce + +A nonce is a one-time value sent with each digest authentication +request header. The value must always be unique, so per default the +last value of the nonce is kept using L. To +change this behaviour, override the +C and +C methods as shown below. + +=back + =head1 METHODS =over 4 -=item authorization_required +=item authorization_required %opts Tries to C, and if that fails calls C and detaches the current action call stack. -=item authenticate_http +This method just passes the options through untouched. + +=item authenticate_http %opts Looks inside C<< $c->request->headers >> and processes the digest and basic (badly named) authorization header. -=item authorization_required_response +This will only try the methods set in the configuration. First digest, then basic. + +See the next two methods for what %opts can contain. + +=item authenticate_basic %opts + +=item authenticate_digest %opts + +Try to authenticate one of the methods without checking if the method is +allowed in the configuration. + +%opts can contain C (either an object or a name), C (to disregard +%the username from the header altogether, overriding it with a username or user +%object). + +=item authorization_required_response %opts Sets C<< $c->response >> to the correct status code, and adds the correct header to demand authentication data from the user agent. +Typically used by C, but may be invoked manually. + +%opts can contain C, C and C, which are used to build +%the digest header. + +=item store_digest_authorization_nonce $key, $nonce + +=item get_digest_authorization_nonce $key + +Set or get the C<$nonce> object used by the digest auth mode. + +You may override these methods. By default they will call C and C on +C<< $c->cache >>. + =back +=head1 CONFIGURATION + +All configuration is stored in C<< YourApp->config->{authentication}{http} >>. + +This should be a hash, and it can contain the following entries: + +=over 4 + +=item store + +Either a name or an object -- the default store to use for HTTP authentication. + +=item type + +Can be either C (the default), C or C. + +This controls C and C, but +not the "manual" methods. + +=item authorization_required_message + +Set this to a string to override the default body content "Authorization required." + +=back + +=head1 RESTRICTIONS + +When using digest authentication, this module will only work together +with authentication stores whose User objects have a C +method that returns the plain-text password. It will not work together +with L, or +L stores whose +C methods return a hashed or salted version of the password. + =head1 AUTHORS Yuval Kogman, C @@ -432,6 +525,10 @@ Jess Robinson Sascha Kiefer C +=head1 SEE ALSO + +RFC 2617 (or its successors), L, L + =head1 COPYRIGHT & LICENSE Copyright (c) 2005-2006 the aforementioned authors. All rights