improvements to login/logout for API

This commit is contained in:
Oliver Gorwits
2019-01-01 10:56:09 +00:00
parent 3b0a9f6310
commit f362b0aee3
2 changed files with 33 additions and 7 deletions

View File

@@ -77,8 +77,12 @@ my $swagger = Dancer::Plugin::Swagger->instance->doc;
$swagger->{schemes} = ['http','https']; $swagger->{schemes} = ['http','https'];
$swagger->{consumes} = 'application/json'; $swagger->{consumes} = 'application/json';
$swagger->{produces} = 'application/json'; $swagger->{produces} = 'application/json';
$swagger->{securityDefinitions} = { APIKeyHeader => $swagger->{securityDefinitions} = {
{ type => 'apiKey', name => 'Authorization', in => 'header' } }; APIKeyHeader =>
{ type => 'apiKey', name => 'Authorization', in => 'header' },
BasicAuth =>
{ type => 'basic' },
};
$swagger->{security} = [ { APIKeyHeader => [] } ]; $swagger->{security} = [ { APIKeyHeader => [] } ];
# workaround for https://github.com/PerlDancer/Dancer/issues/935 # workaround for https://github.com/PerlDancer/Dancer/issues/935

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::AuthN;
use Dancer ':syntax'; use Dancer ':syntax';
use Dancer::Plugin::DBIC; use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible; use Dancer::Plugin::Auth::Extensible;
use Dancer::Plugin::Swagger;
use MIME::Base64; use MIME::Base64;
@@ -13,7 +14,11 @@ hook 'before' => sub {
# from the internals of Dancer::Plugin::Auth::Extensible # from the internals of Dancer::Plugin::Auth::Extensible
my $provider = Dancer::Plugin::Auth::Extensible::auth_provider('users'); my $provider = Dancer::Plugin::Auth::Extensible::auth_provider('users');
if (! session('logged_in_user') && request->path ne uri_for('/login')->path) { if (! session('logged_in_user')
and request->path ne uri_for('/login')->path
and request->path ne uri_for('/swagger.json')->path
and index(request->path, uri_for('/swagger-ui')->path) != 0) {
if (setting('trust_x_remote_user') if (setting('trust_x_remote_user')
and scalar request->header('X-REMOTE_USER') and scalar request->header('X-REMOTE_USER')
and length scalar request->header('X-REMOTE_USER')) { and length scalar request->header('X-REMOTE_USER')) {
@@ -61,7 +66,7 @@ hook 'before' => sub {
get qr{^/(?:login(?:/denied)?)?} => sub { get qr{^/(?:login(?:/denied)?)?} => sub {
# FIXME not sure this is the right approach # FIXME not sure this is the right approach
if (param('return_url') and param('return_url') =~ m{^/api/}) { if (param('return_url') and param('return_url') =~ m{^/api/}) {
status('unauthorized') status('unauthorized');
return to_json { return to_json {
error => 'not authorized', error => 'not authorized',
return_url => param('return_url'), return_url => param('return_url'),
@@ -73,6 +78,15 @@ get qr{^/(?:login(?:/denied)?)?} => sub {
}; };
# override default login_handler so we can log access in the database # override default login_handler so we can log access in the database
swagger_path {
description => 'Obtain an API Key using HTTP BasicAuth',
parameters => [],
responses => {
default => {
examples => {
'application/json' => { api_key => 'cc9d5c02d8898e5728b7d7a0339c0785' } } },
},
},
post '/login' => sub { post '/login' => sub {
my $mode = (request->is_ajax ? 'WebData' my $mode = (request->is_ajax ? 'WebData'
: request->header('Authorization') ? 'API' : request->header('Authorization') ? 'API'
@@ -112,7 +126,7 @@ post '/login' => sub {
token_from => time, token_from => time,
token => \'md5(random()::text)', token => \'md5(random()::text)',
})->discard_changes(); })->discard_changes();
return 'api_key:'. $user->token; return to_json { api_key => $user->token };
} }
redirect param('return_url'); redirect param('return_url');
@@ -127,9 +141,13 @@ post '/login' => sub {
details => param('return_url'), details => param('return_url'),
}); });
if ($mode ne 'WebUI') { if ($mode eq 'WebData') {
status('unauthorized'); status('unauthorized');
} }
elsif ($mode ne 'API') {
status('unauthorized');
return to_json { error => 'authentication failed' };
}
else { else {
vars->{login_failed}++; vars->{login_failed}++;
forward uri_for('/login'), forward uri_for('/login'),
@@ -139,6 +157,10 @@ post '/login' => sub {
} }
}; };
# ugh, *puke*, but D::P::Swagger has no way to set this with swagger_path
Dancer::Plugin::Swagger->instance->doc->{paths}->{'/login'}
->{post}->{security}->[0]->{BasicAuth} = [];
# we override the default login_handler, so logout has to be handled as well # we override the default login_handler, so logout has to be handled as well
any ['get', 'post'] => '/logout' => sub { any ['get', 'post'] => '/logout' => sub {
schema('netdisco')->resultset('UserLog')->create({ schema('netdisco')->resultset('UserLog')->create({