Split SecurityImage Captcha into a dedicated module (#2692)
Lib::Captcha is now only a compatibility wrapper
This commit is contained in:
parent
b666f1416a
commit
fc626c752a
|
@ -48,6 +48,7 @@ lib/Lemonldap/NG/Portal/Auth/Slave.pm
|
|||
lib/Lemonldap/NG/Portal/Auth/SSL.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/Twitter.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/WebID.pm
|
||||
lib/Lemonldap/NG/Portal/Captcha/SecurityImage.pm
|
||||
lib/Lemonldap/NG/Portal/CDC.pm
|
||||
lib/Lemonldap/NG/Portal/CertificateResetByMail/Custom.pm
|
||||
lib/Lemonldap/NG/Portal/CertificateResetByMail/Demo.pm
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
package Lemonldap::NG::Portal::Captcha::SecurityImage;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use MIME::Base64;
|
||||
use GD::SecurityImage use_magick => 1;
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||
|
||||
has width => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaWidth} || 220 }
|
||||
);
|
||||
has height => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaHeight} || 40 }
|
||||
);
|
||||
has lines => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaLines} || 5 }
|
||||
);
|
||||
has scramble => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaScramble} || 1 }
|
||||
);
|
||||
has fgColor => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaFg} || '#403030' }
|
||||
);
|
||||
has bgColor => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaBg} || '#FF644B' }
|
||||
);
|
||||
has rndmax => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captcha_size} || 6 }
|
||||
);
|
||||
has timeout => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{formTimeout} }
|
||||
);
|
||||
|
||||
has ott => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
my $ott = $_[0]->{p}->loadModule('::Lib::OneTimeToken');
|
||||
$ott->timeout( $_[0]->timeout );
|
||||
return $ott;
|
||||
}
|
||||
);
|
||||
|
||||
sub init {
|
||||
my ($self) = @_;
|
||||
if ( $self->conf->{captcha_mail_enabled}
|
||||
|| $self->conf->{captcha_login_enabled}
|
||||
|| $self->conf->{captcha_register_enabled} )
|
||||
{
|
||||
$self->addUnauthRoute( renewcaptcha => '_sendCaptcha', ['GET'] );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Internal methods
|
||||
sub _getCaptcha {
|
||||
my ($self) = @_;
|
||||
my $image = GD::SecurityImage->new(
|
||||
width => $self->width,
|
||||
height => $self->height,
|
||||
lines => $self->lines,
|
||||
gd_font => 'Giant',
|
||||
scramble => $self->scramble,
|
||||
rndmax => $self->rndmax,
|
||||
);
|
||||
$image->random;
|
||||
$image->create( 'normal', 'default', $self->fgColor, $self->bgColor );
|
||||
my ( $imageData, $mimeType, $rdm ) = $image->out( force => 'png' );
|
||||
my $img = 'data:image/png;base64,' . encode_base64( $imageData, '' );
|
||||
my $token = $self->ott->createToken( { captcha => $rdm } );
|
||||
return ( $token, $img );
|
||||
}
|
||||
|
||||
sub _sendCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->logger->info("User request for captcha renew");
|
||||
my ( $token, $image ) = $self->_getCaptcha($req);
|
||||
|
||||
return $self->p->sendJSONresponse( $req,
|
||||
{ newtoken => $token, newimage => $image } );
|
||||
}
|
||||
|
||||
sub _validate_captcha_token {
|
||||
my ( $self, $token, $value ) = @_;
|
||||
my $s = $self->ott->getToken($token);
|
||||
unless ($s) {
|
||||
$self->logger->warn("Captcha token $token isn't valid");
|
||||
return 0;
|
||||
}
|
||||
unless ( $s->{captcha} eq $value ) {
|
||||
$self->logger->notice('Bad captcha response');
|
||||
return 0;
|
||||
}
|
||||
$self->logger->debug('Good captcha response');
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _get_captcha_html {
|
||||
my ( $self, $req, $src ) = @_;
|
||||
|
||||
my $sp = $self->p->staticPrefix;
|
||||
$sp =~ s/\/*$/\//;
|
||||
|
||||
return $self->loadTemplate(
|
||||
$req,
|
||||
'captcha',
|
||||
params => {
|
||||
STATIC_PREFIX => $sp,
|
||||
CAPTCHA_SRC => $src,
|
||||
CAPTCHA_SIZE => $self->rndmax,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
# New API
|
||||
sub check_captcha {
|
||||
my ( $self, $req ) = @_;
|
||||
my $token = $req->param('token');
|
||||
unless ($token) {
|
||||
$self->logger->warn("No token provided for Captcha::SecurityImage");
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $value = $req->param('captcha');
|
||||
unless ($value) {
|
||||
$self->logger->warn("No response provided for Captcha::SecurityImage");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $self->_validate_captcha_token( $token, $value );
|
||||
}
|
||||
|
||||
sub init_captcha {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my ( $token, $image ) = $self->_getCaptcha;
|
||||
$self->logger->debug('Prepare captcha');
|
||||
$req->token($token);
|
||||
$req->captchaHtml( $self->_get_captcha_html( $req, $image ) );
|
||||
|
||||
# DEPRECATED: Compatibility with old templates
|
||||
$req->captcha($image);
|
||||
}
|
||||
|
||||
# #######
|
||||
# Old API
|
||||
# TODO: Remove this in 3.0
|
||||
# #######
|
||||
|
||||
sub validateCaptcha {
|
||||
my ( $self, $token, $value ) = @_;
|
||||
return $self->_validate_captcha_token( $token, $value );
|
||||
}
|
||||
|
||||
sub setCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->init_captcha($req);
|
||||
}
|
||||
|
||||
sub sendCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
return $self->_sendCaptcha($req);
|
||||
}
|
||||
|
||||
sub getCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
return $self->_getCaptcha($req);
|
||||
}
|
||||
|
||||
1;
|
|
@ -1,109 +1,40 @@
|
|||
package Lemonldap::NG::Portal::Lib::Captcha;
|
||||
|
||||
# Old Captcha API, this is only a wrapper around Captcha::SecurityImage
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use MIME::Base64;
|
||||
use GD::SecurityImage use_magick => 1;
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Module';
|
||||
|
||||
has width => (
|
||||
has module => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaWidth} || 220 }
|
||||
);
|
||||
has height => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaHeight} || 40 }
|
||||
);
|
||||
has lines => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaLines} || 5 }
|
||||
);
|
||||
has scramble => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaScramble} || 1 }
|
||||
);
|
||||
has fgColor => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaFg} || '#403030' }
|
||||
);
|
||||
has bgColor => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captchaBg} || '#FF644B' }
|
||||
);
|
||||
has rndmax => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{captcha_size} || 6 }
|
||||
);
|
||||
has timeout => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { $_[0]->{conf}->{formTimeout} }
|
||||
);
|
||||
|
||||
has ott => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
my $ott = $_[0]->{p}->loadModule('::Lib::OneTimeToken');
|
||||
$ott->timeout( $_[0]->timeout );
|
||||
return $ott;
|
||||
}
|
||||
handles => [
|
||||
qw(setCaptcha validateCaptcha getCaptcha ott width height lines scramble fgColor bgColor rndmax timeout )
|
||||
]
|
||||
);
|
||||
|
||||
sub init {
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Returns secret + a HTML image src content
|
||||
sub getCaptcha {
|
||||
my ($self) = @_;
|
||||
my $image = GD::SecurityImage->new(
|
||||
width => $self->width,
|
||||
height => $self->height,
|
||||
lines => $self->lines,
|
||||
gd_font => 'Giant',
|
||||
scramble => $self->scramble,
|
||||
rndmax => $self->rndmax,
|
||||
);
|
||||
$image->random;
|
||||
$image->create( 'normal', 'default', $self->fgColor, $self->bgColor );
|
||||
my ( $imageData, $mimeType, $rdm ) = $image->out( force => 'png' );
|
||||
my $img = 'data:image/png;base64,' . encode_base64( $imageData, '' );
|
||||
my $token = $self->ott->createToken( { captcha => $rdm } );
|
||||
return ( $token, $img );
|
||||
}
|
||||
|
||||
sub validateCaptcha {
|
||||
my ( $self, $token, $value ) = @_;
|
||||
my $s = $self->ott->getToken($token);
|
||||
unless ($s) {
|
||||
$self->logger->warn("Captcha token $token isn't valid");
|
||||
if ( $self->conf->{captcha} ) {
|
||||
$self->logger->error( "The Lib::Captcha API is not compatible"
|
||||
. " with custom Captcha module" );
|
||||
return 0;
|
||||
}
|
||||
unless ( $s->{captcha} eq $value ) {
|
||||
$self->logger->notice('Bad captcha response');
|
||||
return 0;
|
||||
else {
|
||||
my $module = $self->p->loadModule("::Captcha::SecurityImage");
|
||||
if ($module) {
|
||||
$self->module($module);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$self->logger->debug('Good captcha response');
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub setCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
my ( $token, $image ) = $self->getCaptcha;
|
||||
$self->logger->debug('Prepare captcha');
|
||||
$req->token($token);
|
||||
$req->captcha($image);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# * DELETE /sessions/my : ask for global logout (if GlobalLogout plugin is on)
|
||||
#
|
||||
# - Authentication
|
||||
# * GET /renewcaptcha : get token and captcha image
|
||||
# * POST /sessions/<type>/<session-id>?auth : authenticate with a fixed
|
||||
# sessionId
|
||||
# * Note that the "getCookie" method (authentification via SOAP) exists for
|
||||
|
@ -71,7 +70,6 @@ our $VERSION = '2.0.14';
|
|||
|
||||
extends qw(
|
||||
Lemonldap::NG::Portal::Main::Plugin
|
||||
Lemonldap::NG::Portal::Lib::Captcha
|
||||
);
|
||||
|
||||
has configStorage => (
|
||||
|
@ -116,7 +114,6 @@ has exportedAttr => (
|
|||
}
|
||||
}
|
||||
);
|
||||
has captcha => ( is => 'rw' );
|
||||
has ott => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
|
@ -134,13 +131,6 @@ sub init {
|
|||
my ($self) = @_;
|
||||
my @parents = ('Lemonldap::NG::Portal::Main::Plugin');
|
||||
my $add = 0;
|
||||
if ( $self->conf->{captcha_mail_enabled}
|
||||
|| $self->conf->{captcha_login_enabled}
|
||||
|| $self->conf->{captcha_register_enabled} )
|
||||
{
|
||||
$self->captcha( $self->p->loadModule('::Lib::Captcha') ) or return 0;
|
||||
$self->addUnauthRoute( renewcaptcha => 'sendCaptcha', ['GET'] );
|
||||
}
|
||||
if ( $self->conf->{restConfigServer} ) {
|
||||
push @parents, 'Lemonldap::NG::Common::Conf::RESTServer';
|
||||
$add++;
|
||||
|
@ -641,15 +631,6 @@ sub removeSessions {
|
|||
return $self->p->sendJSONresponse( $req, { result => $nbr } );
|
||||
}
|
||||
|
||||
sub sendCaptcha {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->logger->info("User request for captcha renew");
|
||||
my ( $token, $image ) = $self->captcha->getCaptcha($req);
|
||||
|
||||
return $self->p->sendJSONresponse( $req,
|
||||
{ newtoken => $token, newimage => $image } );
|
||||
}
|
||||
|
||||
sub pwdReset {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
|
|
Loading…
Reference in New Issue