package Authen::Simple::Adapter; use strict; use warnings; use base qw[Class::Accessor::Fast Class::Data::Inheritable]; use Authen::Simple::Log qw[]; use Authen::Simple::Password qw[]; use Carp qw[]; use Params::Validate qw[]; __PACKAGE__->mk_classdata( _options => { } ); __PACKAGE__->mk_accessors( qw[ cache callback log ] ); sub new { my $proto = shift; my $class = ref($proto) || $proto; my $params = Params::Validate::validate_with( params => \@_, spec => $class->options, called => "$class\::new" ); return $class->SUPER::new->init($params); } sub init { my ( $self, $params ) = @_; while ( my ( $method, $value ) = each( %{ $params } ) ) { $self->$method($value); } return $self; } sub authenticate { my $self = shift; my $class = ref($self) || $self; my ( $username, $password ) = Params::Validate::validate_with( params => \@_, spec => [ { type => Params::Validate::SCALAR }, { type => Params::Validate::SCALAR } ], called => "$class\::authenticate" ); my $status; if ( $self->callback ) { $status = $self->callback->( \$username, \$password ); if ( defined $status ) { my $boolean = $status ? 'true' : 'false'; $self->log->debug( qq/Callback returned a $boolean value '$status' for user '$username'./ ) if $self->log; return $status; } } if ( $self->cache ) { $status = $self->cache->get("$username:$password"); if ( defined $status ) { $self->log->debug( qq/Successfully authenticated user '$username' from cache./ ) if $self->log; return $status; } } $status = $self->check( $username, $password ); if ( $self->cache && $status ) { $self->cache->set( "$username:$password" => $status ); $self->log->debug( qq/Caching successful authentication status '$status' for user '$username'./ ) if $self->log; } return $status; } sub check { Carp::croak( __PACKAGE__ . qq/->check is an abstract method/ ); } sub check_password { my $self = shift; return Authen::Simple::Password->check(@_); } sub options { my $proto = shift; my $class = ref($proto) || $proto; if ( @_ ) { my ($options) = Params::Validate::validate_pos( @_, { type => Params::Validate::HASHREF } ); if ( my @create = grep { ! $class->can($_) } keys %{ $options } ) { $class->mk_accessors(@create); } $options->{cache} ||= { type => Params::Validate::OBJECT, can => [ qw[get set] ], optional => 1 }; $options->{callback} ||= { type => Params::Validate::CODEREF, optional => 1 }; $options->{log} ||= { type => Params::Validate::OBJECT, can => [ qw[debug info error warn] ], default => Authen::Simple::Log->new, optional => 1 }; $class->_options($options); } return $class->_options; } 1; __END__ =head1 NAME Authen::Simple::Adapter - Adapter class for implementations =head1 SYNOPSIS package Authenticate::Simple::Larry; use strict; use base 'Authen::Simple::Adapter'; __PACKAGE__->options({ secret => { type => Params::Validate::SCALAR, default => 'wall', optional => 1 } }); sub check { my ( $self, $username, $password ) = @_; if ( $username eq 'larry' && $password eq $self->secret ) { $self->log->debug( qq/Successfully authenticated user '$username'./ ) if $self->log; return 1; } $self->log->debug( qq/Failed to authenticate user '$username'. Reason: 'Invalid credentials'/ ) if $self->log; return 0; } 1; =head1 DESCRIPTION Adapter class for implementations. =head1 METHODS =over 4 =item * new ( %parameters ) If overloaded, this method should take a hash of parameters. The following options should be valid: =over 8 =item * cache ( $ ) Any object that supports C, C. Only successful authentications are cached. cache => Cache::FastMmap->new =item * callback ( \& ) A subref that gets called with two scalar references, username and password. callback = sub { my ( $username, $password ) = @_; if ( length($$password) < 6 ) { return 0; # abort, invalid credintials } if ( $$password eq 'secret' ) { return 1; # abort, successful authentication } return; # proceed; } =item * log ( $ ) Any object that supports C, C, C and C. log => Log::Log4perl->get_logger('Authen::Simple') log => $r->log log => $r->server->log =back =item * init ( \%parameters ) This method is called after construction. It should assign parameters and return the instance. sub init { my ( $self, $parameters ) = @_; # mock with parameters return $self->SUPER::init($parameters); } =item * authenticate ( $username, $password ) End user method. Applies callback, checks cache and calls C unless aborted by callback or a cache hit. =item * check ( $username, $password ) Must be implemented in sublcass, should return true on success and false on failure. =item * check_password( $password, $encrypted ) =item * options ( \%options ) Must be set in subclass, should be a valid L specification. Accessors for options will be created unless defined in sublcass. __PACKAGE__->options({ host => { type => Params::Validate::SCALAR, optional => 0 }, port => { type => Params::Validate::SCALAR, default => 80, optional => 1 } }); =back =head1 SEE ALSO L L L =head1 AUTHOR Christian Hansen C =head1 COPYRIGHT This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut