package AccountManager::App::Step3; use Mojo::Base qw(AccountManager::App::Controller); use DateTime; use Email::MIME; use Email::Sender::Simple; use English qw(-no_match_vars); use Syntax::Keyword::Try; use Template::Constants qw(:chomp); use AccountManager::Token; use AccountManager::Tools; sub run { my $self = shift; my $config = $self->app()->config(); my $log = $self->app()->log(); $self->init_db(); $self->init_l10n(); $self->init_user(); if ($config->{app}->{login_url}) { return if !$self->check_authentication(); } my $entityid = $self->param('entityid'); my $email = $self->param('email'); my $db = $self->stash('db'); my $l10n = $self->stash('l10n'); my $user = $self->stash('user'); my $sp = $self->get_sp(entityid => $entityid); return if !$sp; # override metadata contacts if needed my $contacts = $config->{$entityid}->{contacts} || $config->{service}->{contacts}; if ($contacts) { if ($contacts =~ /^\+(.+)/) { # complement original contacts $sp->contacts($sp->contacts(), split(/, */, $1)); } else { # replace original contacts $sp->contacts(split(/, */, $contacts)); } } ## Check that email is a known contact for this SP return $self->abort( log_message => "Requested a token for SP $entityid with unautorized address $email", user_message => "internal", ) if !$sp->is_contact($email); # delete any previous token for the same email/service couple my $old_token = AccountManager::Token->new( db => $db, email_address => $email, entityid => $entityid, ); if ($old_token->load(speculative => 1)) { try { $old_token->delete(); } catch { return $self->abort( log_message => "Failed to delete old authentication token", user_message => "internal" ); } } # compute a new token my $validity_period = $config->{service}->{tokens_validity_period}; my $token = AccountManager::Token->new( db => $db, email_address => $email, entityid => $entityid, creation_date => DateTime->now(), expiration_date => DateTime->now()->add(hours => $validity_period), secret => AccountManager::Tools::generate_secret(20) ); try { $token->save(); } catch { return $self->abort( log_message => "Failed to save creation authentication token", user_message => "internal" ); } # build content my $theme = $config->{setup}->{templates_theme} || 'default'; my $base_templates_dir = $self->app()->home()->child('templates'); my $tt2 = Template->new({ ENCODING => 'utf8', PRE_CHOMP => CHOMP_ONE, INCLUDE_PATH => [ $base_templates_dir->child('mail', $theme), $base_templates_dir->child('mail'), ] }); my $data = { app => { url => $config->{app}->{url}, support_email => $config->{app}->{support_email}, version => $config->{app}->{version}, name => $config->{app}->{name}, }, user => $user->{name}, source_ip => $self->client_ip(), idp => { entityid => $user->{idp}, }, sp => { entityid => $entityid, }, to => $email, token => $token->secret(), challenge_url => $self->url_for('step3')->query(entityid => $entityid, email => $email)->to_abs(), lh => $l10n }; my $text_content; my $html_content; $tt2->process('send_authentication_token.tt2.txt', $data, \$text_content); $tt2->process('send_authentication_token.tt2.html', $data, \$html_content); my $message = Email::MIME->create( header_str => [ 'From' => sprintf('%s <%s>', $config->{app}->{name}, $config->{mailer}->{from}), 'To' => $email, 'Subject' => sprintf('[%s] %s', $config->{app}->{name}, $l10n->maketext("Test accounts request")), 'Content-Type' => 'multipart/alternative' ], parts => [ Email::MIME->create( attributes => { content_type => "text/plain", charset => 'utf-8', encoding => 'quoted-printable' }, body_str => $text_content ), Email::MIME->create( attributes => { content_type => "text/html", charset => 'utf-8', encoding => 'quoted-printable' }, body_str => $html_content ), ] ); try { local $ENV{PATH} = '/bin:/sbin:/usr/bin:/usr/sbin'; Email::Sender::Simple->send($message); } catch($error) { return $self->abort( log_message => "Mail notification error: $error", user_message => "mail_notification_failure" ); } $log->info( sprintf( "Token send to %s for entityid=%s;token=%s", $email, $entityid, $token->secret(), ) ); my $profiles = $base_templates_dir ->child('accounts') ->list() ->map(sub { m/([^\/]+).tt2$/}) ->to_array(); $self->stash(entityid => $entityid); $self->stash(email => $email); $self->stash(validity => $config->{service}->{account_validity_period}); $self->stash(profiles => $profiles); $self->render( status => 200, template => 'step3', format => 'html' ); } 1;