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;