inital import of Catalyst::Plugin::Authentication::Credential::HTTP::Proxy
Marcus Ramberg [Mon, 3 Apr 2006 10:17:23 +0000 (10:17 +0000)]
Build.PL
lib/Catalyst/Plugin/Authentication/Credential/HTTP/Proxy.pm [new file with mode: 0644]
lib/Catalyst/Plugin/Authentication/Credential/HTTP/User.pm [new file with mode: 0644]
lib/Catalyst/Plugin/Authentication/Credential/TypeKey.pm [deleted file]

index efe2e2c..77b8414 100644 (file)
--- a/Build.PL
+++ b/Build.PL
@@ -4,12 +4,12 @@ use Module::Build;
 my $build = Module::Build->new(
     create_makefile_pl => 'traditional',
     license            => 'perl',
-    module_name => 'Catalyst::Plugin::Authentication::Credential::TypeKey',
+    module_name => 'Catalyst::Plugin::Authentication::Credential::HTTP::Proxy',
     requires    => {
         'Catalyst'                         => '5.5',
         'Catalyst::Plugin::Authentication' => 0,
-        'Authen::TypeKey'                  => 0,
         'Test::MockObject'                 => '1.01',
+        'LWP::Simple'                      => 0,
     },
     create_readme => 1,
     sign          => 1,
diff --git a/lib/Catalyst/Plugin/Authentication/Credential/HTTP/Proxy.pm b/lib/Catalyst/Plugin/Authentication/Credential/HTTP/Proxy.pm
new file mode 100644 (file)
index 0000000..6a8e847
--- /dev/null
@@ -0,0 +1,190 @@
+package Catalyst::Plugin::Authentication::Credential::HTTP::Proxy;
+use base qw/Catalyst::Plugin::Authentication::Credential::Password/;
+
+use strict;
+use warnings;
+
+use String::Escape ();
+use URI::Escape    ();
+use Catalyst       ();
+use Catalyst::Plugin::Authentication::Credential::HTTP::User;
+use Carp qw/croak/;
+
+our $VERSION = "0.01";
+
+
+sub authenticate_http_proxy {
+    my $c = shift;
+
+    my $headers = $c->req->headers;
+
+    croak "url setting required for authentication" 
+        unless $c->config->{authentication}{http_proxy}{url};
+    if ( my ( $user, $password ) = $headers->authorization_basic ) {
+
+        my $ua=Catalyst::Plugin::Authentication::Credential::HTTP::User->new;
+        $ua->credentials($user,$password);
+        my $resp= $ua->get($c->config->{authentication}{http_proxy}{url});
+        if ( $resp->is_success ) {
+            if ( my $store = $c->config->{authentication}{http_proxy}{store} ) {
+                $user = $store->get_user($user);
+            } elsif ( my $user_obj = $c->get_user($user) ) {
+                $user = $user_obj;
+            }
+            unless ($user) {
+                $c->log->debug("User '$user' doesn't exist in the default store")
+                    if $c->debug;
+                return;
+            }
+            $c->set_authenticated($user);
+            return 1;
+        } elsif ( $c->debug ) {
+            $c->log->info('Remote authentication failed:'.$resp->message);
+            return 0;
+        }
+    } elsif ( $c->debug ) {
+        $c->log->info('No credentials provided for basic auth');
+        return 0;
+    }
+}
+
+sub authorization_required {
+    my ( $c, %opts ) = @_;
+
+    return 1 if $c->authenticate_http_proxy;
+
+    $c->authorization_required_response( %opts );
+
+    die $Catalyst::DETACH;
+}
+
+sub authorization_required_response {
+    my ( $c, %opts ) = @_;
+    
+    $c->res->status(401);
+
+    my @opts;
+
+    if ( my $realm = $opts{realm} ) {
+        push @opts, sprintf 'realm=%s', String::Escape::qprintable($realm);
+    }
+
+    if ( my $domain = $opts{domain} ) {
+        Catalyst::Excpetion->throw("domain must be an array reference")
+          unless ref($domain) && ref($domain) eq "ARRAY";
+
+        my @uris =
+          $c->config->{authentication}{http}{use_uri_for}
+          ? ( map { $c->uri_for($_) } @$domain )
+          : ( map { URI::Escape::uri_escape($_) } @$domain );
+
+        push @opts, qq{domain="@uris"};
+    }
+
+    $c->res->headers->www_authenticate(join " ", "Basic", @opts);
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::Credential::HTTP - HTTP Basic authentication
+for Catlayst.
+
+=head1 SYNOPSIS
+
+    use Catalyst qw/
+        Authentication
+        Authentication::Store::Moose
+        Authentication::Store::Elk
+        Authentication::Credential::HTTP::Proxy
+    /;
+
+    $c->config->{authentication}{http_proxy}= {
+        url  =>'http://elkland.no/auth',
+        store => 'Authentication::Store::Moose'
+    };
+    
+    sub foo : Local { 
+        my ( $self, $c ) = @_;
+
+        $c->authorization_required( realm => "foo" ); # named after the status code ;-)
+
+        # either user gets authenticated or 401 is sent
+
+        do_stuff();
+    }
+
+    # with ACL plugin
+    __PACKAGE__->deny_access_unless("/path", sub { $_[0]->authenticate_http });
+
+    sub end : Private {
+        my ( $self, $c ) = @_;
+
+        $c->authorization_required_response( realm => "foo" );
+        $c->error(0);
+    }
+
+=head1 DESCRIPTION
+
+This moduule lets you use HTTP Proxy authentication with
+L<Catalyst::Plugin::Authentication>.
+
+Currently this module only supports the Basic scheme, but upon request Digest
+will also be added. Patches welcome!
+
+
+=head1 CONFIG
+
+This module reads config from $c->config->{authentication}{http_proxy}. The following settings
+are supported:
+
+=over 4
+
+=item url
+
+Required. A url protected with basic authentication to authenticate against.
+
+=item store
+
+To specify what store to use. will use the default store if not set.
+
+=cut
+
+=head1 METHODS
+
+=over 4
+
+=item authorization_required
+
+Tries to C<authenticate_http_proxy>, and if that fails calls
+C<authorization_required_response> and detaches the current action call stack.
+
+=item authenticate_http_proxy
+
+Looks inside C<< $c->request->headers >> and processes the basic (badly named)
+authorization header. Then authenticates this against the provided url.
+
+=item authorization_required_response
+
+Sets C<< $c->response >> to the correct status code, and adds the correct
+header to demand authentication data from the user agent.
+
+=back
+
+=head1 AUTHORS
+
+Marcus Ramberg <mramberg@cpan.org
+
+=head1 COPYRIGHT & LICENSE
+
+        Copyright (c) 2005 the aforementioned authors. All rights
+        reserved. This program is free software; you can redistribute
+        it and/or modify it under the same terms as Perl itself.
+
+=cut
+
diff --git a/lib/Catalyst/Plugin/Authentication/Credential/HTTP/User.pm b/lib/Catalyst/Plugin/Authentication/Credential/HTTP/User.pm
new file mode 100644 (file)
index 0000000..09527ec
--- /dev/null
@@ -0,0 +1,40 @@
+package Catalyst::Plugin::Authentication::Credential::HTTP::User;
+
+use base 'LWP::UserAgent';
+
+sub credentials {
+   my ($self,$user,$pass)=@_;
+   @{$self->{credentials}}=($user,$pass);
+}
+sub get_basic_credentials {
+    my $self = shift;
+    return @{$self->{credentials}};
+}
+
+1;
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::Credential::HTTP::User - Wrapper for LWP::UserAgent
+
+=head1 DESCRIPTION
+
+A thin wrapper for L<LWP::UserAgent> to make basic auth simpler.
+
+=head1 METHODS
+
+=head2 credentials
+
+now takes just a username and password
+
+=head2 get_basic_credentials
+
+Returns the set credentials, takes no options.
+
+=head1 AUTHOR
+
+Marcus Ramberg <mramberg@cpan.org
+
+=head1 LICENSE
+
+This software is licensed under the same terms as perl itself.
diff --git a/lib/Catalyst/Plugin/Authentication/Credential/TypeKey.pm b/lib/Catalyst/Plugin/Authentication/Credential/TypeKey.pm
deleted file mode 100644 (file)
index cb74ae5..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-package Catalyst::Plugin::Authentication::Credential::TypeKey;
-
-use strict;
-use warnings;
-
-use Authen::TypeKey;
-use File::Spec;
-use Catalyst::Utils ();
-use NEXT;
-use UNIVERSAL::require;
-use Scalar::Util ();
-
-our $VERSION = '0.3';
-
-sub setup {
-    my $c = shift;
-
-    my $config = $c->config->{authentication}{typekey} ||= {};
-
-    $config->{typekey_object} ||= do {
-        ( $config->{user_class} ||=
-              "Catalyst::Plugin::Authentication::User::Hash" )->require;
-
-        $config->{key_cache} ||=
-          File::Spec->catfile( Catalyst::Utils::class2tempdir( $c, 1 ),
-            'regkeys.txt' );
-
-        my $typekey = Authen::TypeKey->new;
-
-        for ( grep { exists $config->{$_} }
-            qw/expires key_cache key_url token version skip_expiry_check/ )
-        {
-            $typekey->$_( $config->{$_} );
-        }
-
-        $typekey;
-    };
-
-    $c->NEXT::setup(@_);
-}
-
-sub authenticate_typekey {
-    my ( $c, @p ) = @_;
-
-    my ( $user, $p );
-    if ( @p == 1 ) {
-        if ( Scalar::Util::blessed( $p[0] ) ) {
-            $user = $p[0];
-            Catalyst::Exception->throw(
-                    "Attempted to authenticate user object, but "
-                  . "user doesnt't support 'typekey_credentials'" )
-              unless $user->supports(qw/typekey_credentials/);
-            $p = $user->typekey_credentials;
-        }
-        else {
-            $p = $p[0];
-        }
-    }
-    else {
-        $p = @p ? {@p} : undef;
-    }
-
-    my $config = $c->config->{authentication}{typekey};
-
-    my $typekey = $p && delete( $p->{typekey_object} )
-      || $config->{typekey_object};
-
-    $p ||= $c->req;
-
-    if ( my $res = $typekey->verify($p) ) {
-        $c->log->debug("Successfully authenticated user '$res->{name}'.")
-          if $c->debug;
-
-        if ( !$user and my $store = $config->{auth_store} ) {
-            $store = $c->get_auth_store($store) unless ref $store;
-            $user = $store->get_user( $res->{name}, $p, $res );
-        }
-
-        if ( !$user ) {
-            my $user_class = $config->{user_class};
-            $user = $user_class->new($res);
-        }
-
-        $c->set_authenticated($user);
-
-        return 1;
-    }
-    else {
-        $c->log->debug(
-            sprintf "Failed to authenticate user '%s'. Reason: '%s'",
-            $p->{name} || $p->param("name"),
-            $typekey->errstr
-          )
-          if $c->debug;
-
-        return;
-    }
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Catalyst::Plugin::Authentication::Credential::TypeKey - TypeKey Authentication
-for Catalyst.
-
-=head1 SYNOPSIS
-
-    use Catalyst qw/Authentication::Credential::TypeKey/;
-
-    MyApp->config->{authentication}{typekey} = {
-        token => 'xxxxxxxxxxxxxxxxxxxx',
-    };
-
-    sub foo : Local {
-               my ( $self, $c ) = @_;
-
-               if ( $c->authenticate_typekey ) {
-
-               # you can also specify the params manually: $c->authenticate_typekey(
-               #       name => $name,
-               #       email => $email,
-               #       ...
-               #)
-
-                       # successful autentication
-
-                       $c->user; # this is set
-               }
-       }
-
-
-       sub auto : Private {
-               my ( $self, $c ) = @_;
-
-               $c->authenticate_typekey; # uses $c->req
-
-               return 1;
-       }
-
-=head1 DESCRIPTION
-
-This module integrates L<Authen::TypeKey> with
-L<Catalyst::Plugin::Authentication>.
-
-=head1 METHODS
-
-=head3 authenticate_typekey %parameters
-
-=head3 authenticate_typekey
-
-=head3 EXTENDED METHODS
-
-=head3 setup
-
-Fills the config with defaults.
-
-=head1 CONFIGURATION
-
-C<<$c->config->{autentication}{typekey}>> is a hash with these fields (all can
-be left out):
-
-=over 4
-
-=item typekey_object
-
-If this field does not exist an L<Authen::TypeKey> object will be created based
-on the other param and put here.
-
-=item expires
-
-=item key_url
-
-=item token
-
-=item version
-
-See L<Authen::TypeKey> for all of these. If they aren't specified
-L<Authen::TypeKey>'s defaults will be used.
-
-=item key_cache
-
-Also see L<Authen::TypeKey>.
-
-Defaults to C<regkeys.txt> under L<Catalyst::Utils/class2tempdir>.
-
-=item auth_store
-
-A store (or store name) to retrieve the user from.
-
-When a user is successfully authenticated it will call this:
-
-       $store->get_user( $name, $parameters, $result_of_verify );
-
-Where C<$parameters> is a the hash reference passed to
-L<Authen::TypeKey/verify>, and C<$result_of_verify> is the value returned by
-L<Authen::TypeKey/verify>.
-
-If this is unset, L<Catalyst::Plugin::Authentication/default_auth_store> will
-be used instead.
-
-=item user_class
-
-If C<auth_store> or the default store returns nothing from get_user, this class
-will be used to instantiate an object by calling C<new> on the class with the
-return value from L<Authen::TypeKey/verify>.
-
-=back
-
-=head1 SEE ALSO
-
-L<Authen::TypeKey>, L<Catalyst>, L<Catalyst::Plugin::Authentication>.
-
-=head1 AUTHOR
-
-Christian Hansen
-
-Yuval Kogman, C<nothingmuch@woobling.org>
-
-=head1 LICENSE
-
-This library is free software . You can redistribute it and/or modify it under
-the same terms as perl itself.
-
-=cut