1#!/usr/bin/perl 2# 3# Authen::PluggableCaptcha::KeyManager 4# 5###################################################### 6 7=head1 NAME 8 9Authen::PluggableCaptcha::KeyManager 10 11=head1 DESCRIPTION 12 13This is the base class for managing captcha keys ( public facing captcha identifiers) 14 15=head1 DESCRIPTION 16 17This is the base class for managing captcha keys ( public facing captcha identifiers) 18 19This class consolidates the routines previously available in the KeyGenerator and KeyValidator classes 20 21By default , this class always returns true on validate_publickey 22There is no validation supported other than the timeliness provided by the key generation element. 23 24This should be subclassed to provide for better implementations 25 26This module supports the following functions: 27 28 new 29 validate_publickey 30 generate_publickey 31 expire_publickey 32 33 34=head1 CONSTRUCTOR 35 36=over 4 37 38=item B<new PARAMS> 39 40Returns a new L<Authen::PluggableCaptcha::KeyManager> ( or dervied ) object constructed according to PARAMS, where PARAMS are name/value pairs. 41 42PARAMS are required name/value pairs. Required PARAMS are: 43 44=over 8 45 46=item C<seed TYPE> 47 48seed used for key management. this could be a session id, a session id + url, an empty string, or any other defined value. 49 50=item C<site_secret TYPE> 51 52site_secret used for key management. this could be a shared value for your website. 53 54=item C<time_expiry INT> 55 56time_expiry - how many seconds is the captcha good for? 57 58=item C<time_expiry_future INT> 59 60time_expiry_future - how many seconds in the future can a captcha be valid for ( for use in clusters where clocks may not be in sync ) 61 62=item C<time_now INT> 63 64time_now - current unix timestamp 65 66=back 67 68=back 69 70=head1 OBJECT METHODS 71 72=over 4 73 74=item B<validate_publickey> 75 76this is where you'd subclass and toss in functions that handles: 77 78 is this key in the right format ? ( regex ) 79 was this key ever used before? ( one time user ) 80 was this key accessed by more than one ip ? 81 etc. 82 83returns 84 1 : valid 85 0 : invalid 86 -1 : error 87 88=item B<expire_publickey> 89 90handle expiring the key here. this is a null function by default ( you shouldn't be able to expire a non-db backed key ) 91 92if this passed, we should do 93 $self->EXPIRED(1); 94 $self->INVALID(1); 95 96so that the captcha won't be used again. 97 98=item B<generate_publickey> 99 100Returns a hash to be used for creating captchas. 101 102By default,this hash is based on the time , seed , and site_secrect. 103 104It is implemented as a seperate function to be replaced by subclasses 105 106=item B<init_existing> 107hoook called when initializing an existing captcha 108 109 returns: 110 1 on valid key 111 0 on expired/invalid key 112 -1 on error (wrong format , missing args ) 113 114=back 115 116=head1 DEBUGGING 117 118Set the Following envelope variables for debugging 119 120 $ENV{'Authen::PluggableCaptcha::KeyManager-DEBUG_FUNCTION_NAME'} 121 122debug messages are sent to STDERR via the ErrorLoggingObject package 123 124 125 126=cut 127 128 129 130 131use strict; 132 133package Authen::PluggableCaptcha::KeyManager; 134use vars qw(@ISA $VERSION); 135$VERSION= '0.01'; 136 137 138use Authen::PluggableCaptcha::ErrorLoggingObject (); 139use Authen::PluggableCaptcha::Helpers (); 140use Authen::PluggableCaptcha::StandardAttributesObject (); 141use Authen::PluggableCaptcha::ValidityObject (); 142our @ISA= qw( Authen::PluggableCaptcha::ErrorLoggingObject Authen::PluggableCaptcha::ValidityObject Authen::PluggableCaptcha::StandardAttributesObject ); 143 144###################################################### 145 146use Digest::MD5 qw ( md5_hex ); 147 148###################################################### 149 150use constant DEBUG_FUNCTION_NAME=> $ENV{'Authen::PluggableCaptcha::KeyManager-DEBUG_FUNCTION_NAME'} || 0; 151 152###################################################### 153 154sub new { 155 my ( $proto , %kw_args )= @_; 156 my $class= ref($proto) || $proto; 157 my $self= bless ( {} , $class ); 158 159 # required elements 160 my @_requires= qw( seed site_secret time_expiry time_expiry_future time_now ); 161 Authen::PluggableCaptcha::Helpers::check_requires( 162 kw_args__ref=> \%kw_args, 163 error_message=> "Missing required element '%s' in KeyManager::New", 164 requires_array__ref=> \@_requires 165 ); 166 $self->seed( $kw_args{'seed'} ); 167 $self->site_secret( $kw_args{'site_secret'} ); 168 $self->time_expiry( $kw_args{'time_expiry'} ); 169 $self->time_expiry_future( $kw_args{'time_expiry_future'} ); 170 $self->time_now( $kw_args{'time_now'} ); 171 172 return $self; 173} 174 175sub validate_publickey { 176 my ( $self , %kw_args )= @_; 177 DEBUG_FUNCTION_NAME && Authen::PluggableCaptcha::ErrorLoggingObject::log_function_name('validate_publickey'); 178 179 if ( defined $kw_args{'publickey'} ) { 180 $self->publickey( $kw_args{'publickey'} ); 181 } 182 183 if ( !$self->publickey ) { 184 $self->INVALID(1); 185 $self->ACCEPTABLE_ERROR(1); 186 $self->set_error( 'validate_publickey','no publickey' ); 187 return -1; 188 } 189 190 #if we have an existing key, we need to perform a referential check 191 192 # first check is on the format 193 if ( $self->publickey !~ m/[\w]{32}_[\d]{9,11}/ ) { 194 # key is not in the right format 195 $self->INVALID(1); 196 $self->ACCEPTABLE_ERROR(1); 197 $self->set_error( 'validate_publickey','invalid key format' ); 198 return -1; 199 } 200 201 # if its in the format, then split the format into hash and time_start 202 my ( $hash , $time_start )= split '_' , $self->publickey; 203 $self->{'_hash'}= $hash; 204 $self->time_start( $time_start ); 205 206 # next check is on the timeliness 207 if ( 208 $self->time_now 209 > 210 ( $self->time_start + $self->time_expiry ) 211 ) 212 { 213 $self->EXPIRED(1); 214 $self->ACCEPTABLE_ERROR(1); 215 $self->set_error( 'validate_publickey','EXPIRED captcha time' ); 216 return 0; 217 } 218 219 # is the captcha too new? 220 if ( 221 $self->time_start 222 > 223 ( $self->time_now + $self->time_expiry_future ) 224 ) 225 { 226 $self->INVALID(1); 227 $self->set_error( 'validate_publickey','FUTURE captcha time' ); 228 return 0; 229 } 230 231 return 1; 232} 233 234 235 236sub generate_publickey { 237 my ( $self )= @_; 238 DEBUG_FUNCTION_NAME && Authen::PluggableCaptcha::ErrorLoggingObject::log_function_name('generate_publickey'); 239 240 $self->{'_hash'}= md5_hex( 241 sprintf( 242 "%s|%s|%s" , 243 $self->site_secret, 244 $self->time_now, 245 $self->seed 246 ) 247 ); 248 249 #by default we just use a '_' join : KEY_TIMESTART 250 $self->publickey( 251 join '_' , ( $self->{'_hash'} , $self->time_now ) 252 ); 253} 254 255 256 257sub expire_publickey { 258 my ( $self , %kw_args )= @_; 259 DEBUG_FUNCTION_NAME && Authen::PluggableCaptcha::ErrorLoggingObject::log_function_name('expire_publickey'); 260 return -1; 261} 262 263 264### 2651;