From f5ef05d320b77c597a1ab92ebee630c196a25955 Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Fri, 23 Feb 2018 09:11:19 +0100 Subject: [PATCH] REST external 2F skeleton (#1379) --- lemonldap-ng-portal/MANIFEST | 1 + .../lib/Lemonldap/NG/Portal/2F/REST.pm | 130 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 8d6500b67..b4b0ca459 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -11,6 +11,7 @@ lib/Lemonldap/NG/Portal.pm lib/Lemonldap/NG/Portal/2F/External2F.pm lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm lib/Lemonldap/NG/Portal/2F/Register/U2F.pm +lib/Lemonldap/NG/Portal/2F/REST.pm lib/Lemonldap/NG/Portal/2F/TOTP.pm lib/Lemonldap/NG/Portal/2F/U2F.pm lib/Lemonldap/NG/Portal/Auth.pod diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm new file mode 100644 index 000000000..6e65533e5 --- /dev/null +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm @@ -0,0 +1,130 @@ +package Lemonldap::NG::Portal::2F::REST; + +use strict; +use Mouse; +use Lemonldap::NG::Portal::Main::Constants qw( + PE_BADCREDENTIALS + PE_ERROR + PE_FORMEMPTY + PE_OK + PE_SENDRESPONSE +); + +our $VERSION = '2.0.0'; + +extends 'Lemonldap::NG::Portal::Main::SecondFactor', + 'Lemonldap::NG::Portal::Lib::REST'; + +# INITIALIZATION + +has prefix => ( is => 'ro', default => 'ext' ); + +has initAttrs => ( is => 'ro', default => sub { {} } ); + +has vrfyAttrs => ( is => 'ro', default => sub { {} } ); + +sub init { + my ($self) = @_; + unless ( $self->conf->{rest2fVerifyUrl} ) { + $self->logger->error('Missing REST verification URL'); + return 0; + } + foreach my $k ( keys %{ $self->conf->{rest2fInitArgs} } ) { + my $attr = $self->conf->{rest2fInitArgs}->{$k}; + $attr =~ s/^$//; + unless ( $attr =~ /^\w+$/ ) { + $self->logger->error( + "2F REST: $k key must point to a single attribute or macro"); + return 0; + } + $self->initAttrs->{$k} = $attr; + } + foreach my $k ( keys %{ $self->conf->{rest2fVerifyArgs} } ) { + my $attr = $self->conf->{rest2fVerifyArgs}->{$k}; + $attr =~ s/^$//; + unless ( $attr =~ /^\w+$/ ) { + $self->logger->error( + "2F REST: $k key must point to a single attribute or macro"); + return 0; + } + $self->vrfyAttrs->{$k} = $attr; + } + return 1; +} + +sub run { + my ( $self, $req, $token ) = @_; + + if ( $self->conf->{rest2fInitUrl} ) { + + # Prepare args + my $args; + foreach my $k ( keys %{ $self->{initAttrs} } ) { + $args->{$k} = $req->sessionInfo->{ $self->{initAttrs}->{$k} }; + } + + # Launch REST request + $self->logger->debug('Call REST init URL'); + my $res = + eval { $self->restCall( $self->conf->{rest2fInitUrl}, $args ); }; + if ($@) { + $self->logger->error("REST 2F error: $@"); + return PE_ERROR; + } + unless ( $res->{result} ) { + $self->logger->error("REST 2F initialization has failed"); + return PE_ERROR; + } + } + else { + $self->logger->debug('No init URL, skipping initialization'); + } + + # Prepare form + my $tmp = $self->p->sendHtml( + $req, + 'ext2fcheck', + params => { + SKIN => $self->conf->{portalSkin}, + TOKEN => $token + } + ); + $self->logger->debug("Prepare external REST verification"); + + $req->response($tmp); + return PE_SENDRESPONSE; +} + +sub verify { + my ( $self, $req, $session ) = @_; + my $code; + unless ( $code = $req->param('code') ) { + $self->userLogger->error('External REST 2F: no code'); + return PE_FORMEMPTY; + } + + # Prepare args + my $args; + foreach my $k ( keys %{ $self->{vrfyAttrs} } ) { + $args->{$k} = $req->sessionInfo->{ $self->{vrfyAttrs}->{$k} }; + } + + # Launch REST request + $self->logger->debug('Call REST vrfy URL'); + my $res = + eval { $self->restCall( $self->conf->{rest2fVrfyUrl}, $args ); }; + if ($@) { + $self->logger->error("REST 2F error: $@"); + return PE_ERROR; + } + + # Result + unless ( $res->{result} ) { + $self->userLogger->warn( 'REST Second factor failed for ' + . $session->{ $self->conf->{whatToTrace} } ); + return PE_BADCREDENTIALS; + } + PE_OK; +} + +1;