improvements to login/logout for API
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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')) {
|
||||||
@@ -37,7 +42,7 @@ hook 'before' => sub {
|
|||||||
session(logged_in_user_realm => 'users');
|
session(logged_in_user_realm => 'users');
|
||||||
}
|
}
|
||||||
elsif (setting('api_token_lifetime')
|
elsif (setting('api_token_lifetime')
|
||||||
and (index(request->path,uri_for('/api/')->path) == 0
|
and (index(request->path, uri_for('/api/')->path) == 0
|
||||||
or request->path eq uri_for('/swagger.json')->path)) {
|
or request->path eq uri_for('/swagger.json')->path)) {
|
||||||
|
|
||||||
my $token = request->header('Authorization');
|
my $token = request->header('Authorization');
|
||||||
@@ -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({
|
||||||
|
|||||||
Reference in New Issue
Block a user