[Catalyst-commits] r10301 -
branches/Catalyst-Plugin-Authentication/credential_remote/lib/Catalyst/Authentication/Credential
kmx at dev.catalyst.perl.org
kmx at dev.catalyst.perl.org
Tue May 26 21:36:24 GMT 2009
Author: kmx
Date: 2009-05-26 21:36:24 +0000 (Tue, 26 May 2009)
New Revision: 10301
Added:
branches/Catalyst-Plugin-Authentication/credential_remote/lib/Catalyst/Authentication/Credential/Remote.pm
Log:
Catalyst::Authentication::Credential::Remote - first try, more or less works, needs some testing
Added: branches/Catalyst-Plugin-Authentication/credential_remote/lib/Catalyst/Authentication/Credential/Remote.pm
===================================================================
--- branches/Catalyst-Plugin-Authentication/credential_remote/lib/Catalyst/Authentication/Credential/Remote.pm (rev 0)
+++ branches/Catalyst-Plugin-Authentication/credential_remote/lib/Catalyst/Authentication/Credential/Remote.pm 2009-05-26 21:36:24 UTC (rev 10301)
@@ -0,0 +1,237 @@
+package Catalyst::Authentication::Credential::Remote;
+
+use strict;
+use warnings;
+
+use base 'Class::Accessor::Fast';
+
+BEGIN {
+ __PACKAGE__->mk_accessors(qw/allow_re deny_re cutname_re source realm/);
+}
+
+sub new {
+ my ( $class, $config, $app, $realm ) = @_;
+
+ my $self = { };
+ bless $self, $class;
+
+ # we are gonna compile regular expresions defined in config parameters
+ # and explicitly throw an exception saying what parameter was invalid
+ if (defined($config->{allow_regexp}) && ($config->{allow_regexp} ne "")) {
+ eval { $self->allow_re( qr/$config->{allow_regexp}/ ) };
+ Catalyst::Exception->throw( "Invalid regular expression in ".
+ "'allow_regexp' configuration parameter") if $@;
+ }
+ if (defined($config->{deny_regexp}) && ($config->{deny_regexp} ne "")) {
+ eval { $self->deny_re( qr/$config->{deny_regexp}/ ) };
+ Catalyst::Exception->throw( "Invalid regular expression in ".
+ "'deny_regexp' configuration parameter") if $@;
+ }
+ if (defined($config->{cutname_regexp}) && ($config->{cutname_regexp} ne "")) {
+ eval { $self->cutname_re( qr/$config->{cutname_regexp}/ ) };
+ Catalyst::Exception->throw( "Invalid regular expression in ".
+ "'cutname_regexp' configuration parameter") if $@;
+ }
+ $self->source($config->{source} || 'REMOTE_USER');
+ $self->realm($realm);
+ return $self;
+}
+
+sub authenticate {
+ my ( $self, $c, $realm, $authinfo ) = @_;
+
+ my $remuser;
+ if ($self->source eq "REMOTE_USER") {
+ # BEWARE: $c->engine->env was broken prior 5.80005
+ $remuser = $c->engine->env->{REMOTE_USER};
+ # the original idea was to use $c->req->remote_user but ...
+ }
+ elsif ($self->source eq "SSL_CLIENT_DN") {
+ # if user is authenticated via SSL certificate his distinguished name
+ # is available in SSL_CLIENT_DN variable
+ # BEWARE: $c->engine->env was broken prior 5.80005
+ $remuser = $c->engine->env->{SSL_CLIENT_DN};
+ }
+ else {
+ Catalyst::Exception->throw( "Invalid value of 'source' parameter");
+ }
+ return unless defined($remuser);
+ return if ($remuser eq "");
+
+ # $authinfo hash can contain item username (it is optional) - if it is so
+ # this username has to be equal to remote_user
+ my $authuser = $authinfo->{username};
+ return if (defined($authuser) && ($authuser ne $remuser));
+
+ # handle deny / allow checks
+ return if (defined($self->deny_re) && ($remuser =~ $self->deny_re));
+ return if (defined($self->allow_re) && ($remuser !~ $self->allow_re));
+
+ # if param cutname_regexp is specified we try to cut the final usename as a
+ # substring from remote_user
+ my $usr = $remuser;
+ if (defined($self->cutname_re)) {
+ if (($remuser =~ $self->cutname_re) && ($1 ne "")) {
+ $usr = $1;
+ }
+ }
+
+ $authinfo->{id} = $authinfo->{username} = $usr;
+ $authinfo->{remote_user} = $remuser; # just to keep the original value
+ my $user_obj = $realm->find_user( $authinfo, $c );
+ return ref($user_obj) ? $user_obj : undef;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Authentication::Credential::Remote - Let the webserver (e.g. Apache)
+authenticate Catalyst application users
+
+=head1 SYNOPSIS
+
+ # in your MyApp.pm
+ __PACKAGE__->config(
+
+ 'Plugin::Authentication' => {
+ default_realm => 'remoterealm',
+ realms => {
+ remoterealm => {
+ credential => {
+ class => 'Remote',
+ allow_regexp => '^(user.*|admin|guest)$',
+ deny_regexp => 'test',
+ },
+ store => {
+ class => 'Null',
+ # if you want to have some additional user attributes
+ # like user roles, user full name etc. you can specify
+ # here the store where you keep this data
+ }
+ },
+ },
+ },
+
+ );
+
+ # in your Controller/Root.pm you can implement "auto-login" in this way
+ sub begin : Private {
+ my ( $self, $c ) = @_;
+ if(defined($c->req->remote_user) and !$c->user_exists) {
+ # authenticate() for this module does not need any user info
+ # as the username is taken from $c->req->remote_user and
+ # password is not needed
+ $c->authenticate( {} );
+ }
+ }
+
+ # or you can implement in any controller an ordinary login action like this
+ sub login : Global {
+ my ( $self, $c ) = @_;
+ $c->authenticate( {} );
+ }
+
+=head1 DESCRIPTION
+
+This module allows you to authenticate the users of your Catalyst application
+on underlaying webserver. The complete list of authentication method available
+via this module depends just on what your webserver (e.g. Apache, IIS, Lighttpd)
+is able to handle.
+
+Besides the common methods like HTTP Basic and Digest authentication you can
+also use sophisticated ones like so called "integrated authentication" via
+NTLM or Kerberos (popular in corporate intranet applications running in Windows
+Active Directory enviroment) or even the SSL authentication when users
+authenticate themself using their client SSL certificates.
+
+The main idea of this module is based on a fact that webserver passes the name
+of authenticated user into Catalyst application as REMOTE_USER variable (or in
+case of SSL client authentication SSL_CLIENT_DN) - from this point referenced as
+WEBUSER. This module simply takes this value - perfoms some optional checks (see
+below) - and if everything is OK the WEBUSER is declared as authenticated on
+Catalyst level. In fact this module does not perform any check for password or
+other credential; it simply believes the webserver that user was properly
+authenticated.
+
+=head1 CONFIG
+
+=head2 class
+
+This config item is B<REQUIRED>.
+
+B<class> is part of the core L<Catalyst::Plugin::Authentication> module, it
+contains the class name of the store to be used.
+
+The classname used for Credential. This is part of L<Catalyst::Plugin::Authentication>
+and is the method by which Catalyst::Authentication::Credential::Remote is
+loaded as the credential validator. For this module to be used, this must be set
+to 'Remote'.
+
+=head2 source
+
+This config item is B<OPTIONAL> - default is REMOTE_USER.
+
+B<source> contains a name of a variable passed from webserver that contains the
+user identification - supported values: REMOTE_USER, SSL_CLIENT_DN
+
+=head2 deny_regexp
+
+This config item is B<OPTIONAL> - no default value.
+
+B<deny_regexp> contains a regular expression used for check against WEBUSER (details see below)
+
+=head2 allow_regexp
+
+This config item is B<OPTIONAL> - no default value.
+
+B<deny_regexp> contains a regular expression used for check against WEBUSER.
+
+Allow/deny checking of WEBUSER values goes in this way:
+
+1) If B<deny_regexp> is defined and WEBUSER matches deny_regexp then
+authentication FAILS otherwise continues with next step. If deny_regexp is not
+defined or is an empty string we skip this step.
+
+2) If B<allow_regexp> is defined and WEBUSER matches allow_regexp then
+authentication PASSES otherwise FAILS. If allow_regexp is not
+defined or is an empty string we skip this step.
+
+The order deny-allow is fixed.
+
+=head2 cutname_regexp
+
+This config item is B<OPTIONAL> - no default value.
+
+If param B<cutname_regexp> is specified we try to cut the final usename passed to
+Catalyst application as a substring from WEBUSER. This is usefull for
+example in case of SSL authentication when WEBUSER looks like this
+'CN=john, OU=Unit Name, O=Company, C=CZ' - from this format we can simply cut
+pure usename by cutname_regexp set to 'CN=(.*), OU=Unit Name, O=Company, C=CZ'.
+
+Substring is always taken as '$1' regexp substring. If WEBUSER does not
+match cutname_regexp at all or if '$1' regexp substring is empty we pass the
+original WEBUSER value (without cutting) to Catalyst application.
+
+=head1 METHODS
+
+=head2 new ( $config, $app, $realm )
+
+Instantiate a new Catalyst::Authentication::Credential::Remote object using the
+configuration hash provided in $config. In case of invalid value of any
+configuration parameter (e.g. invalid regular expression) throws an exception.
+
+=cut
+
+=head2 authenticate ( $realm, $authinfo )
+
+Takes the username form WEBUSER set by webserver, performs additional
+checks using optional allow_regexp/deny_regexp configuration params, optionaly
+takes substring from WEBUSER and the sets the resulting value as
+a Catalyst username.
+
+=cut
More information about the Catalyst-commits
mailing list