package AccountManager::App::Controller; use Mojo::Base qw(Mojolicious::Controller); use English qw(-no_match_vars); use Syntax::Keyword::Try; use AccountManager::DB; 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; } sub init_user { my $self = shift; my $headers = $self->req()->headers(); my $idp = $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() ) 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; } 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" ) 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(@_); } 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)); } } } 1;