diff --git a/doc/sources/admin/captcha.rst b/doc/sources/admin/captcha.rst index 22aa87c948affa069df33f45cfbf2a1f639f02ad..4b0e3aceb0068cabd9d8251c1fe23dc3377d50f2 100644 --- a/doc/sources/admin/captcha.rst +++ b/doc/sources/admin/captcha.rst @@ -38,6 +38,11 @@ Go in ``General parameters`` > ``Portal`` > ``Captcha``: .. _customcaptcha: +Alternatives +------------ + +- :doc:`Google reCaptcha` + Custom Captcha modules ---------------------- diff --git a/doc/sources/admin/index_portal.rst b/doc/sources/admin/index_portal.rst index 85aa431514d762768004ed17be3dafc4cfcf7efc..648fde0e86e1adde64a0f0d8ebd1dca31c355bda 100644 --- a/doc/sources/admin/index_portal.rst +++ b/doc/sources/admin/index_portal.rst @@ -11,6 +11,7 @@ Portal configuration portalservers captcha public_pages + recaptcha secondfactor index_protocols index_authdb diff --git a/doc/sources/admin/recaptcha.rst b/doc/sources/admin/recaptcha.rst new file mode 100644 index 0000000000000000000000000000000000000000..dadc4f3040003e5cf8954250fefaced57f77b3a3 --- /dev/null +++ b/doc/sources/admin/recaptcha.rst @@ -0,0 +1,29 @@ +reCaptcha +========= + +Presentation +------------ + +Captcha system provided by `Google `__. + +See `Google reCAPTCHA `__ +for more. + +Configuration +------------- + +Configure captcha like :doc:`LLNG internal captcha` but use a +"custom captcha module", set: + +- **Captcha module** to "``::Captcha::ReCaptcha``" +- in **Captcha module options**, add the following keys + + - ``dataSiteKey``: the key ID given in Google console + - ``secretKey``: the secret key + +Then adapt the "Content-Security-Policy" headers, cspDefault and cspScript +should be set to : + +:: + + https://www.google.com https://www.gstatic.com 'self' diff --git a/doc/sources/admin/start.rst b/doc/sources/admin/start.rst index f914abbe584662e9bb3802d9a55200e81215542f..d731f8126f6d6fb2661daed5a87dd47e21dcaf9a 100644 --- a/doc/sources/admin/start.rst +++ b/doc/sources/admin/start.rst @@ -108,6 +108,7 @@ Portal - :doc:`Portal menu` - :doc:`REST/SOAP servers` - :doc:`Captcha` +- :doc:`reCaptcha` - :doc:`Public pages` diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index c7a269af0cc293d40ea6106796d54cc05535683c..8d42669fd7249436f70c4e9820e9497278f6ceb7 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -51,6 +51,7 @@ 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.pod +lib/Lemonldap/NG/Portal/Captcha/ReCaptcha.pm lib/Lemonldap/NG/Portal/Captcha/SecurityImage.pm lib/Lemonldap/NG/Portal/CDC.pm lib/Lemonldap/NG/Portal/CertificateResetByMail/Custom.pm diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Captcha/ReCaptcha.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Captcha/ReCaptcha.pm new file mode 100644 index 0000000000000000000000000000000000000000..a4a1a6d41884faefef2e16c1e6d1d15cd3f881f3 --- /dev/null +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Captcha/ReCaptcha.pm @@ -0,0 +1,79 @@ +package Lemonldap::NG::Portal::Captcha::ReCaptcha; + +use strict; +use Mouse; +use Lemonldap::NG::Common::UserAgent; + +# Add constants used by this module + +our $VERSION = '2.20.0'; + +extends 'Lemonldap::NG::Portal::Main::Plugin'; + +has ua => ( + is => 'rw', + lazy => 1, + builder => sub { + my $ua = Lemonldap::NG::Common::UserAgent->new( $_[0]->{conf} ); + $ua->env_proxy(); + return $ua; + } +); + +sub init { + my ($self) = @_; + unless ($self->conf->{captchaOptions}->{dataSiteKey} + and $self->conf->{captchaOptions}->{secretKey} ) + { + $self->logger->error('Missing required options for reCaptcha'); + return 0; + } + return 1; +} + +sub init_captcha { + my ( $self, $req ) = @_; + + $req->data->{customScript} .= + ''; + + # Read option from the manager configuration + my $dataSiteKey = $self->conf->{captchaOptions}->{dataSiteKey}; + my $html = +qq'
'; + $req->captchaHtml($html); +} + +sub check_captcha { + my ( $self, $req ) = @_; + + my $captcha_input = $req->param('g-recaptcha-response'); + unless ($captcha_input) { + $self->logger->info('No captcha value submitted'); + return 0; + } + my $response = $self->ua->post( + 'https://www.google.com/recaptcha/api/siteverify', + { + secret => $self->conf->{captchaOptions}->{secretKey}, + response => $captcha_input, + } + ); + if ( $response->is_success ) { + my $res = eval { JSON::from_json( $response->decoded_content ) }; + if ($@) { + $self->logger->error("reCaptcha: $@"); + return 0; + } + unless ( $res->{success} ) { + $self->logger->info( + 'reCaptcha errors:' . $response->decoded_content ); + } + return $res->{success}; + } + $self->logger->error( 'reCaptcha error: ' . $response->status_line ); + return 0; +} + +1; +