better version of API login, and filtered api calls
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
package App::Netdisco::Util::Web;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Dancer ':syntax';
|
||||
|
||||
use base 'Exporter';
|
||||
use Time::Piece;
|
||||
use Time::Seconds;
|
||||
|
||||
use base 'Exporter';
|
||||
our @EXPORT = ();
|
||||
our @EXPORT_OK = qw/
|
||||
sort_port sort_modules interval_to_daterange sql_match
|
||||
request_is_api
|
||||
sort_port sort_modules
|
||||
interval_to_daterange
|
||||
sql_match
|
||||
/;
|
||||
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
||||
|
||||
@@ -25,6 +28,18 @@ subroutines.
|
||||
|
||||
=head1 EXPORT_OK
|
||||
|
||||
=head2 request_is_api
|
||||
|
||||
Whether the request should be interpreted as an API call.
|
||||
|
||||
=cut
|
||||
|
||||
sub request_is_api {
|
||||
return (setting('api_token_lifetime')
|
||||
and request->accept =~ m/(?:json|javascript)/
|
||||
and index(request->path, uri_for('/api')->path) == 0);
|
||||
}
|
||||
|
||||
=head2 sql_match( $value, $exact? )
|
||||
|
||||
Convert wildcard characters "C<*>" and "C<?>" to "C<%>" and "C<_>"
|
||||
|
||||
@@ -13,7 +13,8 @@ use HTML::Entities (); # to ensure dependency is met
|
||||
use URI::QueryParam (); # part of URI, to add helper methods
|
||||
use Path::Class 'dir';
|
||||
use Module::Load ();
|
||||
use App::Netdisco::Util::Web 'interval_to_daterange';
|
||||
use App::Netdisco::Util::Web
|
||||
qw/request_is_api interval_to_daterange/;
|
||||
|
||||
use App::Netdisco::Web::AuthN;
|
||||
use App::Netdisco::Web::Static;
|
||||
@@ -82,7 +83,7 @@ $swagger->{schemes} = ['http','https'];
|
||||
$swagger->{consumes} = 'application/json';
|
||||
$swagger->{produces} = 'application/json';
|
||||
$swagger->{tags} = [
|
||||
{name => 'Global'},
|
||||
{name => 'General'},
|
||||
{name => 'Devices',
|
||||
description => 'Operations relating to Devices (switches, routers, etc)'},
|
||||
{name => 'Nodes',
|
||||
@@ -234,6 +235,9 @@ hook 'after' => sub {
|
||||
|
||||
# forward API calls to AJAX route handlers
|
||||
any '/api/:type/:identifier/:method' => require_login sub {
|
||||
pass unless setting('api_enabled')
|
||||
->{ params->{'type'} }->{ params->{'method'} };
|
||||
|
||||
vars->{'is_api'} = 1;
|
||||
my $target =
|
||||
sprintf '/ajax/content/%s/%s', params->{'type'}, params->{'method'};
|
||||
@@ -241,9 +245,15 @@ any '/api/:type/:identifier/:method' => require_login sub {
|
||||
};
|
||||
|
||||
any qr{.*} => sub {
|
||||
if (request_is_api()) {
|
||||
status(404);
|
||||
return to_json { error => 'not found' };
|
||||
}
|
||||
else {
|
||||
var('notfound' => true);
|
||||
status 'not_found';
|
||||
template 'index';
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
@@ -5,14 +5,9 @@ use Dancer::Plugin::DBIC;
|
||||
use Dancer::Plugin::Auth::Extensible;
|
||||
use Dancer::Plugin::Swagger;
|
||||
|
||||
use App::Netdisco::Util::Web 'request_is_api';
|
||||
use MIME::Base64;
|
||||
|
||||
sub request_is_api {
|
||||
return (setting('api_token_lifetime')
|
||||
and request->header('Authorization')
|
||||
and request->accept =~ m/(?:json|javascript)/);
|
||||
}
|
||||
|
||||
hook 'before' => sub {
|
||||
params->{return_url} ||= ((request->path ne uri_for('/')->path)
|
||||
? request->uri : uri_for('/inventory')->path);
|
||||
@@ -22,7 +17,9 @@ hook 'before' => sub {
|
||||
|
||||
if (! session('logged_in_user')
|
||||
and request->path ne uri_for('/login')->path
|
||||
and request->path ne uri_for('/api/login')->path
|
||||
and request->path ne uri_for('/logout')->path
|
||||
and request->path ne uri_for('/api/logout')->path
|
||||
and request->path ne uri_for('/swagger.json')->path
|
||||
and index(request->path, uri_for('/swagger-ui')->path) != 0) {
|
||||
|
||||
@@ -53,7 +50,7 @@ hook 'before' => sub {
|
||||
session(logged_in_user_realm => 'users');
|
||||
}
|
||||
elsif (request_is_api()
|
||||
and index(request->path, uri_for('/api')->path) == 0) {
|
||||
and request->header('Authorization')) {
|
||||
|
||||
my $token = request->header('Authorization');
|
||||
my $user = $provider->validate_api_token($token)
|
||||
@@ -85,18 +82,24 @@ get qr{^/(?:login(?:/denied)?)?} => sub {
|
||||
|
||||
# override default login_handler so we can log access in the database
|
||||
swagger_path {
|
||||
description => 'Obtain an API Key using HTTP BasicAuth',
|
||||
tags => ['Global'],
|
||||
parameters => [],
|
||||
description => 'Obtain an API Key using BasicAuth or parameters',
|
||||
path => '/api/login',
|
||||
tags => ['General'],
|
||||
parameters => [
|
||||
{ name => 'username', in => 'formData', required => false, type => 'string' },
|
||||
{ name => 'password', in => 'formData', required => false, type => 'string' },
|
||||
],
|
||||
responses => {
|
||||
default => {
|
||||
examples => {
|
||||
'application/json' => { api_key => 'cc9d5c02d8898e5728b7d7a0339c0785' } } },
|
||||
},
|
||||
},
|
||||
post '/login' => sub {
|
||||
post qr{^/(?:api/)?login$} => sub {
|
||||
my $mode = (request_is_api() ? 'API' : 'WebUI');
|
||||
|
||||
my $x = params; use DDP; p $x;
|
||||
|
||||
# get authN data from request (HTTP BasicAuth or Form params)
|
||||
my $authheader = request->header('Authorization');
|
||||
if (defined $authheader and $authheader =~ /^Basic (.*)$/i) {
|
||||
@@ -158,13 +161,13 @@ post '/login' => sub {
|
||||
|
||||
# ugh, *puke*, but D::P::Swagger has no way to set this with swagger_path
|
||||
# must be after the path is declared, above.
|
||||
Dancer::Plugin::Swagger->instance->doc->{paths}->{'/login'}
|
||||
->{post}->{security}->[0]->{BasicAuth} = [];
|
||||
Dancer::Plugin::Swagger->instance->doc->{paths}->{'/api/login'}
|
||||
->{post}->{security} = [ {}, {BasicAuth => []} ];
|
||||
|
||||
# we override the default login_handler, so logout has to be handled as well
|
||||
swagger_path {
|
||||
description => 'Destroy user API Key and session cookie',
|
||||
tags => ['Global'],
|
||||
tags => ['General'],
|
||||
parameters => [],
|
||||
responses => { default => { examples => { 'application/json' => {} } } },
|
||||
},
|
||||
|
||||
@@ -90,6 +90,28 @@ web_plugins:
|
||||
- Device::Addresses
|
||||
- Device::Vlans
|
||||
extra_web_plugins: []
|
||||
api_enabled:
|
||||
device:
|
||||
details: true
|
||||
port: false
|
||||
ports: false
|
||||
modules: false
|
||||
addresses: false
|
||||
vlans: false
|
||||
node: false
|
||||
vlan: false
|
||||
report: false
|
||||
admin:
|
||||
topology: false
|
||||
pseudodevice: false
|
||||
user: false
|
||||
report:
|
||||
slowdevices: false
|
||||
performance: false
|
||||
timedoutdevices: false
|
||||
duplicaedevices: false
|
||||
orphaned: false
|
||||
userlog: false
|
||||
sidebar_defaults:
|
||||
search_node:
|
||||
stamps: { default: checked }
|
||||
|
||||
Reference in New Issue
Block a user