Skip to content
Snippets Groups Projects
Controller.pm 5.34 KiB
Newer Older
package AccountManager::App::Controller;

use Mojo::Base qw(Mojolicious::Controller);

use English qw(-no_match_vars);
use Syntax::Keyword::Try;

use AccountManager::DB;
Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
use AccountManager::Entity;
use AccountManager::L10N;
use AccountManager::Token;

sub init_l10n {
    my $self = shift;

    my $log = $self->app()->log();

    # lang identification first, as needed for any further error message
    my ($l10n, $lang);
    if ($self->param('lang')) {
        $lang = $self->param('lang');
        $l10n = AccountManager::L10N->get_handle($lang);
        $log->debug(sprintf("setting language from parameter: %s", $lang));
    } elsif ($self->session('lang')) {
        $lang = $self->session('lang');
        $l10n = AccountManager::L10N->get_handle($lang);
        $log->debug(sprintf("setting language from session: %s", $lang));
    } elsif ($self->req()->headers->header('Accept-Language')) {
        $l10n = AccountManager::L10N->get_handle();
        $lang = $l10n->language_tag();
        $log->debug(sprintf("setting language from Accept-Language header: %s", $lang));
    } else {
        $lang = 'en';
        $l10n = AccountManager::L10N->get_handle($lang);
    }

    $self->session(lang => $lang);
    $self->stash(lang => $lang);
    $self->stash(l10n => $l10n);

    return $l10n;
}

sub init_db {
    my $self = shift;

    my $config = $self->app()->config();

    AccountManager::DB->register_db(
        driver   => $config->{database}->{type},
        database => $config->{database}->{name},
        host     => $config->{database}->{host},
        password => $config->{database}->{password},
        username => $config->{database}->{username},
        options  => [ $self->string_to_list($config->{database}->{options}) ]
    );

    my $db;
    try {
        $db = AccountManager::DB->new();
    } catch {
    }

    $self->stash(db => $db);

    return $db;
}

Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
sub init_user {
    my $self = shift;

Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
    my $headers = $self->req()->headers();

    my $idp = 
Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
        $ENV{'Shib_Identity_Provider'} ||           # local SP
        $headers->header('Shib-Identity-Provider'); # remote SP

    my $name =
        $ENV{displayName} ||             # local SP
        $headers->header('displayName'); # remote SP

    my $user = {
        idp => $idp,
        name => $name
    };

    $self->stash(user => $user);

    return $user;
}

sub check_authentication {
    my $self = shift;

    return $self->abort(
        status       => 401,
        log_message  => sprintf("unauthenticated user for action %s",  $self->current_route()),
        user_message => Registry::Error::AuthenticationRequired->new()
Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
    ) if !$self->stash('user');

    return 1;
}

sub check_token {
    my ($self, %args) = @_;

    my $secret = $args{token};

    my $token = AccountManager::Token->new(
        db     => $self->{db},
        secret => $secret
    );

    return $self->abort(
        status       => 400,
        log_message  => "No such authentication token $secret",
        user_message => "wrong_token"
    ) if !$token->load(speculative => 1);

    return $self->abort(
        status       => 400,
        log_message  => "Authentication token $secret cannot be used for SP $args{entityid}",
        user_message => "wrong_token_for_sp"
    ) if $token->entityid() ne $args{entityid};

    ## delete the token
    try {
        $token->delete();
    } catch {
        $self->app()->log()->error(
            sprintf("Failed to delete authentication token %s", $secret)
        );
    }

    return 1;
}

Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
sub get_sp {
    my ($self, %args) = @_;

    my $entityid = $args{entityid};

    return $self->abort(
        log_message  => "Missing parameter: entityid",
        user_message => "missing_entityid"
    ) if !$entityid;

    my $pattern = qr{
        ^
        (?:
            https?://[\w.:/-]+
        |
            urn:[\w.:-]+
        )
        $
    }x;

    return $self->abort(
        log_message  => "Invalid parameter: entityid",
        user_message => "invalid_entityid"
Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
    ) if $entityid !~ $pattern;

    my $db = $self->stash('db');

    my $sp = AccountManager::Entity->new(
        db       => $db,
        entityid => $entityid
    );

    return $self->abort(
        log_message  => sprintf("No such SP '%s' in database", $entityid),
        user_message => "no_such_entity"
    ) if !$sp->load(speculative => 1);

    return $sp;
}

sub abort {
    my $self = shift;
    my %args = @_;

    my $status = $args{status} || 200;
    my $format = $args{format} || 'html';

    my $db = $self->stash('db');
    $db->rollback() if $db && $db->in_transaction();

    $self->app()->log()->error($args{log_message}) if $args{log_message};

    $self->stash(error => $args{user_message});
    $self->render(status => $status, template => 'errors', format => 'html');

    return;
}

sub loc {
    my $self = shift;

    return $self->stash('l10n')->maketext(@_);
}

Guillaume ROUSSE's avatar
Guillaume ROUSSE committed
sub mock_contacts {
    my $self = shift;
    my $sp = shift;

    my $config    = $self->app()->config();
    my $entityid = $sp->entityid();

    my $contacts =
        $config->{$entityid}->{contacts} ||
        $config->{service}->{contacts};

    if ($contacts) {
        if ($contacts =~ /^\+(.+)/) {
            # complement original contacts
            $sp->contacts($sp->contacts(), $self->string_to_list($1));
        } else {
            # replace original contacts
            $sp->contacts($self->string_to_list($contacts));
        }
    }
}