Mail2F.pm 3.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
package Lemonldap::NG::Portal::2F::Mail2F;

use strict;
use Mouse;
use String::Random;
use Lemonldap::NG::Portal::Main::Constants qw(
  PE_BADCREDENTIALS
  PE_ERROR
  PE_FORMEMPTY
  PE_OK
  PE_SENDRESPONSE
  PE_MUSTHAVEMAIL
);

our $VERSION = '2.0.2';

extends 'Lemonldap::NG::Portal::Main::SecondFactor',
  'Lemonldap::NG::Portal::Lib::SMTP';

# INITIALIZATION

has prefix => ( is => 'ro', default => 'mail' );
has random => (
    is      => 'rw',
    default => sub {
        return String::Random->new;
    }
);

has ott => (
    is      => 'rw',
    lazy    => 1,
    default => sub {
        my $ott =
          $_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
        $ott->timeout( $_[0]->{conf}->{mail2fTimeout}
              || $_[0]->{conf}->{formTimeout} );
        return $ott;
    }
);

sub init {
    my ($self) = @_;
    foreach (qw(mail2fCodeRegex mailSessionKey)) {
        unless ( $self->conf->{$_} ) {
            $self->error("Missing $_ parameter, aborting");
            return 0;
        }
    }
    $self->logo( $self->conf->{mail2fLogo} )
      if ( $self->conf->{mail2fLogo} );
    return $self->SUPER::init();
}

# RUNNING METHODS

sub run {
    my ( $self, $req, $token ) = @_;

    my $checkLogins = $req->param('checkLogins');

    my $code = $self->random->randregex( $self->conf->{mail2fCodeRegex} );
    $self->logger->debug("Generated two-factor code: $code");
    $self->ott->updateToken( $token, __mail2fcode => $code );

    my $dest = $req->{sessionInfo}->{ $self->conf->{mailSessionKey} };
    unless ($dest) {
        $self->logger->error( "Could not find mail attribute for login "
              . $req->{sessionInfo}->{_user} );
        return PE_MUSTHAVEMAIL;
    }

    # Build mail content
    my %tplPrms;
    $tplPrms{MAIN_LOGO} = $self->conf->{portalMainLogo};
    my $tr      = $self->translate($req);
    my $subject = $self->conf->{mail2fSubject};

    unless ($subject) {
        $subject = 'mail2fSubject';
        $tr->( \$subject );
    }
    my $body;
    my $html;
    if ( $self->conf->{mail2fBody} ) {

        # We use a specific text message, no html
        $body = $self->conf->{mail2fBody};
    }
    else {

        # Use HTML template
        $body = $self->loadTemplate(
            'mail_2fcode',
            filter => $tr,
            params => \%tplPrms
        );
        $html = 1;
    }

    # Replace variables in body
    $body =~ s/\$code/$code/g;
    $body =~ s/\$(\w+)/$req->{sessionInfo}->{$1} || ''/ge;

    # Send mail
    unless ( $self->send_mail( $dest, $subject, $body, $html ) ) {
        $self->logger->error( 'Unable to send 2F code mail to ' . $dest );
        return PE_ERROR;
    }

    # Prepare form
    my $tmp = $self->p->sendHtml(
        $req,
        'ext2fcheck',
        params => {
            MAIN_LOGO   => $self->conf->{portalMainLogo},
            SKIN        => $self->conf->{portalSkin},
            TOKEN       => $token,
            TARGET      => '/' . $self->prefix . '2fcheck',
            CHECKLOGINS => $checkLogins
        }
    );
    $req->response($tmp);
    return PE_SENDRESPONSE;
}

sub verify {
    my ( $self, $req, $session ) = @_;
    my $usercode;
    unless ( $usercode = $req->param('code') ) {
        $self->logger->error('Mail2F: no code');
        return PE_FORMEMPTY;
    }
    my $savedcode = $session->{__mail2fcode};

    unless ($savedcode) {
        $self->logger->error(
            'Unable to find generated 2F code in token session');
        return PE_ERROR;
    }

    $self->logger->debug("Verifying Mail 2F code: $usercode againt $savedcode");

    if ( $usercode eq $savedcode ) {
        return PE_OK;
    }
    else {
        $self->userLogger->warn( 'Second factor failed for '
              . $session->{ $self->conf->{whatToTrace} } );
        return PE_BADCREDENTIALS;
    }
}

1;