release 2.012000

Squashed commit of the following:

commit 94ed51c799fa605f5debc262dd9ccfd756bc9ee5
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 18:34:13 2013 +0100

    ready for 2.012000

commit b26bdbeb5df65011bf79baa7beccefbbfbfe6614
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 18:29:38 2013 +0100

    add note to clarify cron spec

commit 6271f08f2b6c44668ca772a3478fbc42a76d3f01
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 17:34:33 2013 +0100

    update TODO

commit 221b062bb80cd29263d1f2dbf3cf674140cad972
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 17:33:12 2013 +0100

    Manual topology is preserved when re-discovering neighbors

commit 50fd829c9e986afd47640abbeae06b09cd0796ec
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 16:40:09 2013 +0100

    Pseudo device ports being counted properly since Port Utilization report

commit 252f136f6a4226a78c859c68ea0c1245109c71ca
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 16:24:47 2013 +0100

    Fix blur events on editable cells

commit 3136e3b899ce697ed43a1347c61bd11fc4011b77
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 15:58:23 2013 +0100

    move port control features from common device js

commit dba012ea1c169993dd80e9aef0067597def54f79
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 15:41:50 2013 +0100

    Floating table headers not compatible with in-header drop-down menus

commit e728258f74cb1ebddc47acfa1e152ee8ba91f0e8
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Aug 6 15:13:56 2013 +0100

    RW snmp community strings now in the "community" table

commit d01ac4d8060bb6eaa152987a4a1b0c35cd580ade
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 19:04:56 2013 +0100

    fixes to deal with Extensible auth redirects

commit 0529003a4b408a3725ec61d5f18f09fce741c2c2
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:42:47 2013 +0100

    cute bug icon in the report bug message

commit c7a77f791e6a2130c3a0c776a9de37c89e68bdeb
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:28:20 2013 +0100

    shift ports legend over to line up with colums controls

commit 09d94a66916aef1e41835bfab105805184e523a7
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:19:18 2013 +0100

    move Auth::Extensible settings into core config

commit 05cba664a50ee2abd062e24270e0fcab442ba8ac
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:17:33 2013 +0100

    fix no_port_control setting after authN changes

commit 679f776b821f8cf4299032ab87006807bfeb6c8c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:05:55 2013 +0100

    bit more efficient checking of roles

commit 3535d2a4c8d97582b0297d0ee2c07d2a5e62b713
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 18:00:55 2013 +0100

    set require_login on almost all handlers

commit 32ae6391fef6ebca6973f7227dc1b68d91db6d68
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 5 17:50:38 2013 +0100

    Implement extensible authN and role based access control

commit f06f11628f5cf63e627c01eb9c8ab927a064fecd
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 4 23:28:08 2013 +0100

    Device re-discover/arpnip/macsuck is async with toastr notify

commit aeceb4235fc2e7b51673a4fca37c8e25343ec23d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 4 22:58:27 2013 +0100

    simplify template logic

commit 6b19f47283d6597d46a5af530e5605f8df8e17ec
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 4 22:41:09 2013 +0100

    Always offer to discover device on site homepage

commit a7a01fb794418feb86c2d5bc5214127c85bd14b2
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 4 22:26:50 2013 +0100

    use fontawesome icons for legend

commit 3f1730957b6accbc11737e46c201453d7219d03e
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jul 29 08:01:59 2013 +0100

    ready for 2.011000

commit e1873ca58375b458d9543576951f1003e1c28d35
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jul 28 00:02:20 2013 +0100

    Find the RW snmp community string correctly now

commit 039780bc66ca0d8b19767c38a21aa208feafeaf7
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jul 27 23:07:05 2013 +0100

    User Management (for admins only)

commit 213352d54ee8e71cbca5ae2c1c75696800c4216b
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jul 27 21:17:57 2013 +0100

    Table headers float on the page when scrolling

commit 598960e9141b0d9fc4f9a234a7d8fe02a81ba0f9
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jul 27 18:05:00 2013 +0100

    Port Utilization report

commit d25e41894476c74bee747e38960a277e2f5b2072
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jul 27 15:20:23 2013 +0100

    Button to empty the job queue, and improve display when the queue is empty

commit 18125d1a758b5707ab4c0ff8b65dfdd90dc32664
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jul 27 14:23:48 2013 +0100

    Swap play/pause icons in jobqueue

commit 9eead5328a127689701ac28d5bcf1cfa39edaf99
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jul 25 23:11:17 2013 +0100

    Revert "No longer depend on Moo"

    This reverts commit 0a87ad4b410fa784bfbe823f3e6ede7c979144f3.

    Conflicts:

    	Netdisco/Changes

commit d0c31effa834201f1592c1fc3da9a6a689a3a43c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jul 25 23:01:32 2013 +0100

    REMOTE_USER is an env var, not an HTTP Header

commit 0a87ad4b410fa784bfbe823f3e6ede7c979144f3
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jul 25 22:35:05 2013 +0100

    No longer depend on Moo

commit 7ccbb04e6f7c1701194d996baa557affcda48103
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Wed Jul 24 23:44:42 2013 +0100

    ready for 2.010004

commit 6314c5a054d56d7829797d37c6627b2cbccde4ab
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Wed Jul 24 23:41:51 2013 +0100

    Navbar query box was being cleared sometimes under admin task panels

commit 271a5d9db17b288aeff43ee29a6bbf753bf823de
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Wed Jul 24 00:03:05 2013 +0100

    update TODO

commit 3103f968a9fb128726ed929589137cb6011e2591
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Jul 23 23:58:19 2013 +0100

    ready for 2.010002

commit 0368df1dbdfe6d764eec05f2bf37587fff795995
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Jul 23 23:17:17 2013 +0100

    fix bugs in topo update code

commit 43b7203ca3270dc2e02a097472179517087522d2
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Jul 23 23:12:36 2013 +0100

    fix FF bug with forms embedded in tables

commit f86c5d7d3d8d293a781c2ec7dc7a18bfb3c8bf78
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Jul 23 17:15:35 2013 +0100

    Nullify unused schema changes

commit 649e4c471d524013f87257e11fffa7789dccd01d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 20 13:48:20 2013 +0100

    version bump

commit ac6ce399b2bd596444a629f24ddea5eca0fff56a
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 20 13:41:08 2013 +0100

    Handle UTF-8 data in the device port remote_id

commit c73b86c0204ddd98e9d27437028a7000d70338bf
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 20 13:35:32 2013 +0100

    revert bytea conversion on remote_id

commit a144f42cf93803882bb8492cd3ce3a8e5679d383
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jun 17 23:09:50 2013 +0100

    bump version for beta release

commit 3b791c93d7d9b7358bf46f31e322a9b807823d9d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jun 17 22:57:59 2013 +0100

    Pass event param to all js functions which require it

commit da38badef893fc1503a797a99c34504db71e7c20
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jun 17 22:35:48 2013 +0100

    Change data type on device_port remote_id to bytea

commit 727237951a5576b476dee127b3cef777afb51df8
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jun 17 10:52:28 2013 +0100

    fix help message in netdisco-web-fg

commit 25bc026dc5e0177cd3aa81c11cdace091eb68f36
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Jun 17 08:16:56 2013 +0100

    bump version for new release

commit d4042f6e8db42c7a85df4dcf9690fec72ad2db69
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 18:27:52 2013 +0100

    Job Queue page play/pause/refresh controls

commit b6c9152516d7800409b7a73c5d0cdce6dd405492
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 17:50:06 2013 +0100

    limit size of job queue table

commit ac9e5feb8b774071fcf4423dd862dced74dee9e6
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 17:47:55 2013 +0100

    update bugs link

commit 9c0fb0e9aedc6297f4462c3cf88343f6d0df40b6
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 17:41:29 2013 +0100

    update MANIFEST

commit 7aaa2fff91ed2b1839bdbb79081d90ad3e144f47
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 17:40:35 2013 +0100

    Fix Plack middleware config for Expiry

commit 313e2cf014cf0da7cf85074e390ad394b28bf42d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 17:23:00 2013 +0100

    Support for delegated authentication with REMOTE_USER and X-REMOTE_USER

commit 85e21f2bf296c4a5ca6b5afb5091694e56e3031f
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 14:24:08 2013 +0100

    Add tooltip showing the job queue item logged status message

commit 9b14f53ebed51eb46ea278807cfe8a2fbd28743c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 13:43:26 2013 +0100

    Increase default frequency of job queue polling to 2 seconds

commit 6ba46818d8ab2100c652c8eb8e98bc6f5a54e273
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 12:57:43 2013 +0100

    workaround for https://github.com/PerlDancer/Dancer/issues/935

commit c7a2d8a9d45716959bedbbb8db4cdd82a5950642
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Jun 16 11:54:18 2013 +0100

    Fix hyperlinks when running behind reverse proxy on custom path

commit 0620efa404bc25cb0a9ada5aa6f1b092d5c4d482
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jun 15 18:31:19 2013 +0100

    update deploy docs

commit 857b1c7aa0fe832f8948349eda5211eb38ba3099
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jun 15 18:16:50 2013 +0100

    add note about compiler dependency

commit 02a2ad6b2c52db9fbc1e24bc8888f658dc7084ad
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jun 15 17:44:29 2013 +0100

    sort vlans, macs, ips in device port view

commit 097bad77310728a98b261a2cfca4de7ab50be94b
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jun 15 16:32:20 2013 +0100

    hint when calling web in fg without starman

commit 6425d89ddb2b56129c610482134482d8f9455d40
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Jun 15 15:53:26 2013 +0100

    macwalk and arpwalk refactored

commit d527b9d05addc82fb38c84f6fea1aa5818fc68d5
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 22:27:34 2013 +0100

    implement is_macsuckable and is_arpnipable

commit 7af10ed313e25f5d99a22b53ba438225c2259069
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 22:17:39 2013 +0100

    version bump

commit 8ace3bf8fa48cf3e14bdf86fad5a4862aad50a4b
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 22:14:05 2013 +0100

    tidy up user menu

commit e6eef605c248471dbfe7ec62cd04d73d653523ca
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 22:02:52 2013 +0100

    Add discoverall, macwalk, arpwalk items to the Admin Tasks menu

commit 2631fabd1eccd8a3971e4762eebe57f406623bee
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 21:21:50 2013 +0100

    remove length() which only became sane in 5.12

commit a7b7169070a58685cacde26a3b6d462e74be9928
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Thu Jun 13 19:07:56 2013 +0100

    Use DBIx::Class new collapsed query support when we can

commit 77cddab8ba7033ccb1ecae257bafa4eef8f99f47
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Wed Jun 12 17:26:47 2013 +0100

    Database config simplified to only four essential settings

commit 6ed0802bf2ab0fd898ce6945451b8ca6566ae551
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Wed Jun 12 13:03:20 2013 +0100

    Ask to set up guest user for Admin/Port Control rights in deploy script
This commit is contained in:
Oliver Gorwits
2013-08-06 18:35:15 +01:00
parent 86d74b0100
commit 5bddeb5515
61 changed files with 1033 additions and 397 deletions

View File

@@ -7,7 +7,7 @@ use 5.010_000;
use File::ShareDir 'dist_dir';
use Path::Class;
our $VERSION = '2.011000';
our $VERSION = '2.012000';
BEGIN {
if (not ($ENV{DANCER_APPDIR} || '')
@@ -58,6 +58,7 @@ if (ref {} eq ref setting('database')) {
options => {
AutoCommit => 1,
RaiseError => 1,
auto_savepoint => 1,
},
schema_class => 'App::Netdisco::DB',
};

View File

@@ -754,7 +754,7 @@ sub _set_manual_topology {
return unless ($left->in_storage and $right->in_storage);
$left->ports
->single({port => $link->port1}, {for => 'update'})
->single({port => $link->port1})
->update({
remote_ip => $right->ip,
remote_port => $link->port2,
@@ -765,7 +765,7 @@ sub _set_manual_topology {
});
$right->ports
->single({port => $link->port2}, {for => 'update'})
->single({port => $link->port2})
->update({
remote_ip => $left->ip,
remote_port => $link->port1,

View File

@@ -8,7 +8,7 @@ use base 'DBIx::Class::Schema';
__PACKAGE__->load_namespaces;
our $VERSION = 24; # schema version used for upgrades, keep as integer
our $VERSION = 26; # schema version used for upgrades, keep as integer
use Path::Class;
use File::Basename;

View File

@@ -0,0 +1,17 @@
use utf8;
package App::Netdisco::DB::Result::Community;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table("community");
__PACKAGE__->add_columns(
"ip",
{ data_type => "inet", is_nullable => 0 },
"snmp_comm_rw",
{ data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("ip");
1;

View File

@@ -180,6 +180,15 @@ __PACKAGE__->has_many(
'ip', { join_type => 'RIGHT' }
);
=head2 community
Returns the row from the community string table, if one exists.
=cut
__PACKAGE__->might_have(
community => 'App::Netdisco::DB::Result::Community', 'ip');
=head1 ADDITIONAL COLUMNS
=head2 port_count

View File

@@ -40,6 +40,7 @@ __PACKAGE__->set_primary_key("username");
# Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-07 14:20:02
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2awpSJkzXP7+8eyT4vGjfw
__PACKAGE__->has_many( roles => 'App::Netdisco::DB::Result::Virtual::UserRole', 'username' );
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View File

@@ -0,0 +1,27 @@
use utf8;
package App::Netdisco::DB::Result::Virtual::UserRole;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
__PACKAGE__->table("user_role");
__PACKAGE__->result_source_instance->is_virtual(1);
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL
SELECT username, 'port_control' AS role FROM users
WHERE port_control
UNION
SELECT username, 'admin' AS role FROM users
WHERE admin
ENDSQL
);
__PACKAGE__->add_columns(
'username' => { data_type => 'text' },
'role' => { data_type => 'text' },
);
1;

View File

@@ -0,0 +1,5 @@
BEGIN;
ALTER TABLE device DROP COLUMN snmp_comm_rw;
COMMIT;

View File

@@ -0,0 +1,9 @@
BEGIN;
CREATE TABLE "community" (
"ip" inet NOT NULL,
"snmp_comm_rw" text,
PRIMARY KEY ("ip")
);
COMMIT;

View File

@@ -73,7 +73,7 @@ sub worker_body {
# due to a table constraint, this will (intentionally) fail if a
# similar job is already queued.
try {
debug "sched ($wid): queueing $a job";
info "sched ($wid): queueing $a job";
schema('netdisco')->resultset('Admin')->create({
action => $a,
device => ($sched->{device} || undef),

View File

@@ -387,7 +387,12 @@ hour fields (which accept same types as C<cron> notation). For example:
min: 30
macwalk:
when:
min: 15
hour: '*/2'
wday: 'mon-fri'
Note that the fields default to "all" (i.e. "C<*>") when not specified. See
L<Algorithm::Cron> for further details.
=head2 Dancer Internal

View File

@@ -90,8 +90,8 @@ sub _snmp_connect_generic {
unshift @communities, $device->snmp_comm
if defined $device->snmp_comm
and defined $comm_type and $comm_type eq 'community';
unshift @communities, $device->snmp_comm_rw
if defined $device->snmp_comm_rw
unshift @communities, $device->community->snmp_comm_rw
if eval { $device->community->snmp_comm_rw }
and defined $comm_type and $comm_type eq 'community_rw';
my $info = undef;
@@ -126,7 +126,7 @@ sub _try_write {
debug sprintf '[%s] try_write with comm: %s', $device->ip, $comm;
$info->clear_cache;
my $rv = $info->set_location( $info->location );
$device->update({snmp_comm_rw => $comm})
$device->update_or_create_related('community', {snmp_comm_rw => $comm})
if $device->in_storage;
$happy = 1 if $rv;
}

View File

@@ -4,6 +4,7 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use Socket6 (); # to ensure dependency is met
use HTML::Entities (); # to ensure dependency is met
@@ -56,6 +57,9 @@ hook 'before_template' => sub {
# allow portable dynamic content
$tokens->{uri_for} = sub { uri_for(@_)->path_query };
# access to logged in user's roles
$tokens->{user_has_role} = sub { user_has_role(@_) };
# allow very long lists of ports
$Template::Directive::WHILE_MAX = 10_000;
@@ -63,13 +67,7 @@ hook 'before_template' => sub {
$Template::Stash::PRIVATE = undef;
};
get '/' => sub {
if (var('user') and var('user')->admin) {
if (schema('netdisco')->resultset('Device')->count == 0) {
var('nodevices' => true);
}
}
get qr{^/(?:login(?:/denied)?)?} => sub {
template 'index';
};

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::AdminTask;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use Try::Tiny;
@@ -21,7 +22,7 @@ sub add_job {
($device ? (device => $device->addr) : ()),
action => $jobtype,
status => 'queued',
username => session('user'),
username => session('logged_in_user'),
userip => request->remote_address,
});
@@ -30,14 +31,14 @@ sub add_job {
action => 'macwalk',
subaction => 'after-discoverall',
status => 'queued',
username => session('user'),
username => session('logged_in_user'),
userip => request->remote_address,
});
schema('netdisco')->resultset('Admin')->create({
action => 'arpwalk',
subaction => 'after-discoverall',
status => 'queued',
username => session('user'),
username => session('logged_in_user'),
userip => request->remote_address,
});
}
@@ -58,18 +59,14 @@ my %jobs_all = map {$_ => 1} qw/
/;
foreach my $jobtype (keys %jobs_all, keys %jobs) {
ajax "/ajax/control/admin/$jobtype" => sub {
send_error('Forbidden', 403)
unless var('user')->admin;
ajax "/ajax/control/admin/$jobtype" => require_role admin => sub {
send_error('Missing device', 400)
if exists $jobs{$jobtype} and not param('device');
add_job($jobtype, param('device'));
};
post "/admin/$jobtype" => sub {
send_error('Forbidden', 403)
unless var('user')->admin;
post "/admin/$jobtype" => require_role admin => sub {
send_error('Missing device', 400)
if exists $jobs{$jobtype} and not param('device');
@@ -78,13 +75,9 @@ foreach my $jobtype (keys %jobs_all, keys %jobs) {
};
}
get '/admin/*' => sub {
get '/admin/*' => require_role admin => sub {
my ($tag) = splat;
if (! eval { var('user')->admin }) {
return redirect uri_for('/')->as_string;
}
# trick the ajax into working as if this were a tabbed page
params->{tab} = $tag;

View File

@@ -0,0 +1,72 @@
package App::Netdisco::Web::Auth::Provider::DBIC;
use strict;
use warnings FATAL => 'all';
use base 'Dancer::Plugin::Auth::Extensible::Provider::Base';
# with thanks to yanick's patch at
# https://github.com/bigpresh/Dancer-Plugin-Auth-Extensible/pull/24
use Dancer qw(:syntax);
use Dancer::Plugin::DBIC;
use Digest::MD5;
sub authenticate_user {
my ($self, $username, $password) = @_;
return unless defined $username;
my $user = $self->get_user_details($username) or return;
return $self->match_password($password, $user);
}
sub match_password {
my( $self, $password, $user ) = @_;
return unless $user and $password and $user->password;
my $settings = $self->realm_settings;
my $password_column = $settings->{users_password_column} || 'password';
my $sum = Digest::MD5::md5_hex($password);
return ($sum eq $user->$password_column ? 1 : 0);
}
sub get_user_details {
my ($self, $username) = @_;
my $settings = $self->realm_settings;
my $database = schema($settings->{schema_name})
or die "No database connection";
my $users_table = $settings->{users_resultset} || 'User';
my $username_column = $settings->{users_username_column} || 'username';
my $user = $database->resultset($users_table)->find({
$username_column => $username
}) or debug("No such user $username");
return $user;
}
sub get_user_roles {
my ($self, $username) = @_;
return unless defined $username;
my $settings = $self->realm_settings;
my $database = schema($settings->{schema_name})
or die "No database connection";
# Get details of the user first; both to check they exist, and so we have
# their ID to use.
my $user = $self->get_user_details($username)
or return;
my $roles = $settings->{roles_relationship} || 'roles';
my $role_column = $settings->{role_column} || 'role';
return [ $user->$roles->get_column( $role_column )->all ];
}
1;

View File

@@ -2,56 +2,26 @@ package App::Netdisco::Web::AuthN;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Digest::MD5 ();
use Dancer::Plugin::Auth::Extensible;
hook 'before' => sub {
if (! session('user') && request->path ne uri_for('/login')->path) {
params->{return_url} ||= '/inventory';
if (! session('logged_in_user') && request->path ne uri_for('/login')->path) {
if (setting('trust_x_remote_user') and scalar request->header('X-REMOTE_USER')) {
session(user => scalar request->header('X-REMOTE_USER'));
session(logged_in_user => scalar request->header('X-REMOTE_USER'));
}
elsif (setting('trust_remote_user') and $ENV{REMOTE_USER}) {
session(user => $ENV{REMOTE_USER});
session(logged_in_user => $ENV{REMOTE_USER});
}
elsif (setting('no_auth')) {
session(user => 'guest');
session(logged_in_user => 'guest');
}
else {
# user has no AuthN - force to handler for '/'
request->path_info('/');
}
}
if (session('user') && session->id) {
var(user => schema('netdisco')->resultset('User')
->find(session('user')));
# really just for dev work, to quieten the logs
var('user')->port_control(0)
if var('user') and setting('no_port_control');
}
};
post '/login' => sub {
if (param('username') and param('password')) {
my $user = schema('netdisco')->resultset('User')
->find(param('username'));
if ($user) {
my $sum = Digest::MD5::md5_hex(param('password'));
if (($sum and $user->password) and ($sum eq $user->password)) {
session(user => $user->username);
return redirect uri_for('/inventory')->as_string;
}
}
}
redirect uri_for('/', {failed => 1})->as_string;
};
get '/logout' => sub {
session->destroy;
redirect uri_for('/', {logout => 1})->as_string;
};
true;

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Device;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
hook 'before' => sub {
my @default_port_columns_left = (
@@ -106,7 +107,7 @@ hook 'before_template' => sub {
$tokens->{self_options} = $self_uri->query_form_hash;
};
get '/device' => sub {
get '/device' => require_login sub {
my $q = param('q');
my $dev = schema('netdisco')->resultset('Device')->single({
-or => [

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::AdminTask::JobQueue;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
@@ -11,8 +12,7 @@ register_admin_task({
label => 'Job Queue',
});
ajax '/ajax/control/admin/jobqueue/del' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/control/admin/jobqueue/del' => require_role admin => sub {
send_error('Missing job', 400) unless param('job');
schema('netdisco')->txn_do(sub {
@@ -21,17 +21,13 @@ ajax '/ajax/control/admin/jobqueue/del' => sub {
});
};
ajax '/ajax/control/admin/jobqueue/delall' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/control/admin/jobqueue/delall' => require_role admin => sub {
schema('netdisco')->txn_do(sub {
my $device = schema('netdisco')->resultset('Admin')->delete;
});
};
ajax '/ajax/content/admin/jobqueue' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/content/admin/jobqueue' => require_role admin => sub {
my $set = schema('netdisco')->resultset('Admin')
->with_times
->search({}, {

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::AdminTask::PseudoDevice;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
use NetAddr::IP::Lite ':lower';
@@ -13,8 +14,6 @@ register_admin_task({
});
sub _sanity_ok {
return 0 unless var('user') and var('user')->admin;
return 0 unless param('dns')
and param('dns') =~ m/^[[:print:]]+$/
and param('dns') !~ m/[[:space:]]/;
@@ -28,7 +27,7 @@ sub _sanity_ok {
return 1;
}
ajax '/ajax/control/admin/pseudodevice/add' => sub {
ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -42,13 +41,20 @@ ajax '/ajax/control/admin/pseudodevice/add' => sub {
return unless $device;
$device->ports->populate([
['port'],
map {["Port$_"]} @{[1 .. param('ports')]},
[qw/port type/],
map {["Port$_", 'other']} @{[1 .. param('ports')]},
]);
# device_ip table is used to show whether topo is "broken"
schema('netdisco')->resultset('DeviceIp')
->create({
ip => param('ip'),
alias => param('ip'),
});
});
};
ajax '/ajax/control/admin/pseudodevice/del' => sub {
ajax '/ajax/control/admin/pseudodevice/del' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -60,7 +66,7 @@ ajax '/ajax/control/admin/pseudodevice/del' => sub {
});
};
ajax '/ajax/control/admin/pseudodevice/update' => sub {
ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -72,8 +78,8 @@ ajax '/ajax/control/admin/pseudodevice/update' => sub {
if (param('ports') > $count) {
my $start = $count + 1;
$device->ports->populate([
['port'],
map {["Port$_"]} @{[$start .. param('ports')]},
[qw/port type/],
map {["Port$_", 'other']} @{[$start .. param('ports')]},
]);
}
elsif (param('ports') < $count) {
@@ -85,9 +91,7 @@ ajax '/ajax/control/admin/pseudodevice/update' => sub {
});
};
ajax '/ajax/content/admin/pseudodevice' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/content/admin/pseudodevice' => require_role admin => sub {
my $set = schema('netdisco')->resultset('Device')
->search(
{vendor => 'netdisco'},

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::AdminTask::Topology;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
use App::Netdisco::Util::Device 'get_device';
@@ -16,8 +17,6 @@ register_admin_task({
});
sub _sanity_ok {
return 0 unless var('user') and var('user')->admin;
my $dev1 = NetAddr::IP::Lite->new(param('dev1'));
return 0 unless ($dev1 and $dev1->addr ne '0.0.0.0');
@@ -30,7 +29,7 @@ sub _sanity_ok {
return 1;
}
ajax '/ajax/control/admin/topology/add' => sub {
ajax '/ajax/control/admin/topology/add' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
my $device = schema('netdisco')->resultset('Topology')
@@ -79,7 +78,7 @@ ajax '/ajax/control/admin/topology/add' => sub {
};
};
ajax '/ajax/control/admin/topology/del' => sub {
ajax '/ajax/control/admin/topology/del' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -93,9 +92,7 @@ ajax '/ajax/control/admin/topology/del' => sub {
});
};
ajax '/ajax/content/admin/topology' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/content/admin/topology' => require_role admin => sub {
my $set = schema('netdisco')->resultset('Topology')
->search({},{order_by => [qw/dev1 dev2 port1/]});

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::AdminTask::Users;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
use Digest::MD5 ();
@@ -13,8 +14,6 @@ register_admin_task({
});
sub _sanity_ok {
return 0 unless var('user') and var('user')->admin;
return 0 unless param('username')
and param('username') =~ m/^[[:print:]]+$/
and param('username') !~ m/[[:space:]]/;
@@ -22,7 +21,7 @@ sub _sanity_ok {
return 1;
}
ajax '/ajax/control/admin/users/add' => sub {
ajax '/ajax/control/admin/users/add' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -37,7 +36,7 @@ ajax '/ajax/control/admin/users/add' => sub {
});
};
ajax '/ajax/control/admin/users/del' => sub {
ajax '/ajax/control/admin/users/del' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -46,7 +45,7 @@ ajax '/ajax/control/admin/users/del' => sub {
});
};
ajax '/ajax/control/admin/users/update' => sub {
ajax '/ajax/control/admin/users/update' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
@@ -65,9 +64,7 @@ ajax '/ajax/control/admin/users/update' => sub {
});
};
ajax '/ajax/content/admin/users' => sub {
send_error('Forbidden', 403) unless var('user')->admin;
ajax '/ajax/content/admin/users' => require_role admin => sub {
my $set = schema('netdisco')->resultset('User')
->search(undef, { order_by => [qw/fullname username/]});

View File

@@ -3,13 +3,14 @@ package App::Netdisco::Web::Plugin::Device::Addresses;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_device_tab({ tag => 'addresses', label => 'Addresses' });
# device interface addresses
ajax '/ajax/content/device/addresses' => sub {
ajax '/ajax/content/device/addresses' => require_login sub {
my $q = param('q');
my $device = schema('netdisco')->resultset('Device')

View File

@@ -3,13 +3,14 @@ package App::Netdisco::Web::Plugin::Device::Details;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_device_tab({ tag => 'details', label => 'Details' });
# device details table
ajax '/ajax/content/device/details' => sub {
ajax '/ajax/content/device/details' => require_login sub {
my $q = param('q');
my $device = schema('netdisco')->resultset('Device')
->with_times()->search_for_device($q) or send_error('Bad device', 400);

View File

@@ -2,12 +2,13 @@ package App::Netdisco::Web::Plugin::Device::Modules;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_device_tab({ tag => 'modules', label => 'Modules' });
ajax '/ajax/content/device/:thing' => sub {
ajax '/ajax/content/device/:thing' => require_login sub {
return "<p>Hello, this is where the ". param('thing') ." content goes.</p>";
};

View File

@@ -3,12 +3,13 @@ package App::Netdisco::Web::Plugin::Device::Neighbors;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_device_tab({ tag => 'netmap', label => 'Neighbors' });
ajax '/ajax/content/device/netmap' => sub {
ajax '/ajax/content/device/netmap' => require_login sub {
content_type('text/html');
template 'ajax/device/netmap.tt', {}, { layout => undef };
};
@@ -39,7 +40,7 @@ sub _add_children {
}
# d3 seems not to use proper ajax semantics, so get instead of ajax
get '/ajax/data/device/netmap' => sub {
get '/ajax/data/device/netmap' => require_login sub {
my $q = param('q');
my $device = schema('netdisco')->resultset('Device')
@@ -75,7 +76,7 @@ get '/ajax/data/device/netmap' => sub {
to_json(\%tree);
};
ajax '/ajax/data/device/alldevicelinks' => sub {
ajax '/ajax/data/device/alldevicelinks' => require_login sub {
my @devices = schema('netdisco')->resultset('Device')->search({}, {
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
columns => ['ip', 'dns'],

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::Device::Ports;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Util::Web (); # for sort_port
use App::Netdisco::Web::Plugin;
@@ -10,7 +11,7 @@ use App::Netdisco::Web::Plugin;
register_device_tab({ tag => 'ports', label => 'Ports' });
# device ports with a description (er, name) matching
ajax '/ajax/content/device/ports' => sub {
ajax '/ajax/content/device/ports' => require_login sub {
my $q = param('q');
my $device = schema('netdisco')->resultset('Device')

View File

@@ -2,6 +2,7 @@ package App::Netdisco::Web::Plugin::Inventory;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
@@ -11,7 +12,7 @@ register_navbar_item({
label => 'Inventory',
});
get '/inventory' => sub {
get '/inventory' => require_login sub {
my $models = schema('netdisco')->resultset('Device')->get_models();
my $releases = schema('netdisco')->resultset('Device')->get_releases();

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::Report::DuplexMismatch;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
@@ -12,7 +13,7 @@ register_report({
label => 'Duplex Mismatches Between Devices',
});
ajax '/ajax/content/report/duplexmismatch' => sub {
ajax '/ajax/content/report/duplexmismatch' => require_login sub {
my $set = schema('netdisco')->resultset('Virtual::DuplexMismatch');
return unless $set->count;

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::Report::PortUtilization;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
@@ -12,7 +13,7 @@ register_report({
label => 'Port Utilization',
});
ajax '/ajax/content/report/portutilization' => sub {
ajax '/ajax/content/report/portutilization' => require_login sub {
return unless schema('netdisco')->resultset('Device')->count;
my $set = schema('netdisco')->resultset('Virtual::PortUtilization');

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::Search::Device;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use List::MoreUtils ();
@@ -11,7 +12,7 @@ use App::Netdisco::Web::Plugin;
register_search_tab({ tag => 'device', label => 'Device' });
# device with various properties or a default match-all
ajax '/ajax/content/search/device' => sub {
ajax '/ajax/content/search/device' => require_login sub {
my $has_opt = List::MoreUtils::any {param($_)}
qw/name location dns ip description model os_ver vendor/;
my $set;

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Plugin::Search::Node;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use NetAddr::IP::Lite ':lower';
use Net::MAC ();
@@ -12,7 +13,7 @@ use App::Netdisco::Web::Plugin;
register_search_tab({ tag => 'node', label => 'Node' });
# nodes matching the param as an IP or DNS hostname or MAC
ajax '/ajax/content/search/node' => sub {
ajax '/ajax/content/search/node' => require_login sub {
my $node = param('q');
send_error('Missing node', 400) unless $node;
content_type('text/html');

View File

@@ -3,13 +3,14 @@ package App::Netdisco::Web::Plugin::Search::Port;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_search_tab({ tag => 'port', label => 'Port' });
# device ports with a description (er, name) matching
ajax '/ajax/content/search/port' => sub {
ajax '/ajax/content/search/port' => require_login sub {
my $q = param('q');
send_error('Missing query', 400) unless $q;
my $set;

View File

@@ -3,13 +3,14 @@ package App::Netdisco::Web::Plugin::Search::VLAN;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_search_tab({ tag => 'vlan', label => 'VLAN' });
# devices carrying vlan xxx
ajax '/ajax/content/search/vlan' => sub {
ajax '/ajax/content/search/vlan' => require_login sub {
my $q = param('q');
send_error('Missing query', 400) unless $q;
my $set;

View File

@@ -3,10 +3,9 @@ package App::Netdisco::Web::PortControl;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
ajax '/ajax/portcontrol' => sub {
send_error('Forbidden', 403)
unless var('user')->port_control;
ajax '/ajax/portcontrol' => require_role port_control => sub {
send_error('No device/port/field', 400)
unless param('device') and (param('port') or param('field'));
@@ -37,7 +36,7 @@ ajax '/ajax/portcontrol' => sub {
action => $action,
subaction => $subaction,
status => 'queued',
username => session('user'),
username => session('logged_in_user'),
userip => request->remote_address,
log => $log,
});
@@ -46,13 +45,11 @@ ajax '/ajax/portcontrol' => sub {
to_json({});
};
ajax '/ajax/userlog' => sub {
my $user = session('user');
send_error('No username', 400) unless $user;
ajax '/ajax/userlog' => require_login sub {
my $rs = schema('netdisco')->resultset('Admin')->search({
username => $user,
action => [qw/location contact portcontrol portname vlan power/],
username => session('logged_in_user'),
action => [qw/location contact portcontrol portname vlan power
discover macsuck arpnip/],
finished => { '>' => \"(now() - interval '5 seconds')" },
});

View File

@@ -1,8 +1,9 @@
package App::Netdisco::Web::Report;
use Dancer ':syntax';
use Dancer::Plugin::Auth::Extensible;
get '/report/*' => sub {
get '/report/*' => require_login sub {
my ($tag) = splat;
# trick the ajax into working as if this were a tabbed page

View File

@@ -3,6 +3,7 @@ package App::Netdisco::Web::Search;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
hook 'before' => sub {
# view settings for node options
@@ -59,7 +60,7 @@ hook 'before_template' => sub {
}
};
get '/search' => sub {
get '/search' => require_login sub {
my $q = param('q');
my $s = schema('netdisco');

View File

@@ -3,10 +3,11 @@ package App::Netdisco::Web::TypeAhead;
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Util::Web (); # for sort_port
ajax '/ajax/data/devicename/typeahead' => sub {
ajax '/ajax/data/devicename/typeahead' => require_login sub {
my $q = param('query') || param('term');
my $set = schema('netdisco')->resultset('Device')->search_fuzzy($q);
@@ -14,7 +15,7 @@ ajax '/ajax/data/devicename/typeahead' => sub {
to_json [map {$_->dns || $_->name || $_->ip} $set->all];
};
ajax '/ajax/data/deviceip/typeahead' => sub {
ajax '/ajax/data/deviceip/typeahead' => require_login sub {
my $q = param('query') || param('term');
my $set = schema('netdisco')->resultset('Device')->search_fuzzy($q);
@@ -32,7 +33,7 @@ ajax '/ajax/data/deviceip/typeahead' => sub {
to_json \@data;
};
ajax '/ajax/data/port/typeahead' => sub {
ajax '/ajax/data/port/typeahead' => require_login sub {
my $dev = param('dev1') || param('dev2');
my $port = param('port1') || param('port2');
send_error('Missing device', 400) unless $dev;