mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Add global NAC page and refactor the per-device one (#15228)
* Adding a NAC global port page * style * filter_menu_entry * typo * ->when() * device_id always returned * use request * laravel conversion, let see how it goes * styleci * ->with('device') to avoid 1 query per item processed * and rewrote on @murrant advice * any -> get Suggested by @murrant Co-authored-by: Tony Murray <murraytony@gmail.com> * @push('scripts') * style * @endpush --------- Co-authored-by: Tony Murray <murraytony@gmail.com>
This commit is contained in:
13
app/Http/Controllers/NacController.php
Normal file
13
app/Http/Controllers/NacController.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
class NacController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
return view('nac', $data);
|
||||||
|
}
|
||||||
|
}
|
@@ -34,7 +34,7 @@ class PortNacController extends TableController
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'device_id' => 'required|int',
|
'device_id' => 'int',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ class PortNacController extends TableController
|
|||||||
protected function sortFields($request)
|
protected function sortFields($request)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
'device_id',
|
||||||
'port_id',
|
'port_id',
|
||||||
'mac_address',
|
'mac_address',
|
||||||
'mac_oui',
|
'mac_oui',
|
||||||
@@ -72,10 +73,11 @@ class PortNacController extends TableController
|
|||||||
*/
|
*/
|
||||||
public function baseQuery($request)
|
public function baseQuery($request)
|
||||||
{
|
{
|
||||||
return PortsNac::select('port_id', 'mac_address', 'ip_address', 'vlan', 'domain', 'host_mode', 'username', 'authz_by', 'timeout', 'time_elapsed', 'time_left', 'authc_status', 'authz_status', 'method')
|
return PortsNac::select('device_id', 'port_id', 'mac_address', 'ip_address', 'vlan', 'domain', 'host_mode', 'username', 'authz_by', 'timeout', 'time_elapsed', 'time_left', 'authc_status', 'authz_status', 'method')
|
||||||
->where('device_id', $request->device_id)
|
->when($request->device_id, fn ($q, $id) => $q->where('device_id', $id))
|
||||||
->hasAccess($request->user())
|
->hasAccess($request->user())
|
||||||
->with('port');
|
->with('port')
|
||||||
|
->with('device');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +90,7 @@ class PortNacController extends TableController
|
|||||||
$item['mac_oui'] = Rewrite::readableOUI($item['mac_address']);
|
$item['mac_oui'] = Rewrite::readableOUI($item['mac_address']);
|
||||||
$item['mac_address'] = Rewrite::readableMac($item['mac_address']);
|
$item['mac_address'] = Rewrite::readableMac($item['mac_address']);
|
||||||
$item['port'] = null; //free some unused data to be sent to the browser
|
$item['port'] = null; //free some unused data to be sent to the browser
|
||||||
|
$item['device_id'] = Url::deviceLink($nac->device);
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ use App\Models\Location;
|
|||||||
use App\Models\Notification;
|
use App\Models\Notification;
|
||||||
use App\Models\Package;
|
use App\Models\Package;
|
||||||
use App\Models\PortGroup;
|
use App\Models\PortGroup;
|
||||||
|
use App\Models\PortsNac;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\UserPref;
|
use App\Models\UserPref;
|
||||||
use App\Models\Vminfo;
|
use App\Models\Vminfo;
|
||||||
@@ -117,6 +118,8 @@ class MenuComposer
|
|||||||
|
|
||||||
$vars['port_groups'] = PortGroup::hasAccess($user)->orderBy('name')->get(['port_groups.id', 'name', 'desc']);
|
$vars['port_groups'] = PortGroup::hasAccess($user)->orderBy('name')->get(['port_groups.id', 'name', 'desc']);
|
||||||
|
|
||||||
|
$vars['port_nac'] = PortsNac::hasAccess($user)->exists();
|
||||||
|
|
||||||
// Sensor menu
|
// Sensor menu
|
||||||
$vars['sensor_menu'] = ObjectCache::sensors();
|
$vars['sensor_menu'] = ObjectCache::sensors();
|
||||||
|
|
||||||
|
@@ -295,6 +295,12 @@
|
|||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
@if($port_nac)
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
<li><a href="{{ url('nac') }}"><i class="fa fa-lock fa-fw fa-lg"
|
||||||
|
aria-hidden="true"></i> NAC</a></li>
|
||||||
|
@endif
|
||||||
@if(auth()->user()->hasGlobalRead())
|
@if(auth()->user()->hasGlobalRead())
|
||||||
@if($port_groups_exist)
|
@if($port_groups_exist)
|
||||||
<li role="presentation" class="divider"></li>
|
<li role="presentation" class="divider"></li>
|
||||||
|
132
resources/views/nac.blade.php
Normal file
132
resources/views/nac.blade.php
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
@extends('layouts.librenmsv1')
|
||||||
|
|
||||||
|
@section('title', __('NAC'))
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
|
||||||
|
<x-panel title="{{ __('NAC') }}" id="nac-panel">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="nac-grid" data-toggle="bootgrid" class="table table-hover table-condensed table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-column-id="device_id" data-order="asc" data-width="140px">{{ __('Devices') }}</th>
|
||||||
|
<th data-column-id="port_id" data-width="100px">{{ __('Ports') }}</th>
|
||||||
|
<th data-column-id="mac_address" data-formatter="tooltip" data-width="170px">{{ __('Mac Address') }}</th>
|
||||||
|
<th data-column-id="mac_oui" data-formatter="tooltip" data-sortable="false" data-width="130px">{{ __('Vendor') }}</th>
|
||||||
|
<th data-column-id="ip_address" data-formatter="tooltip" data-width="140px">{{ __('IP Address') }}</th>
|
||||||
|
<th data-column-id="vlan" data-formatter="tooltip" data-width="60px">{{ __('Vlan') }}</th>
|
||||||
|
<th data-column-id="domain" data-formatter="nac_domain" data-formatter="tooltip">{{ __('Domain') }}</th>
|
||||||
|
<th data-column-id="host_mode" data-formatter="nac_mode">{{ __('Host Mode') }}</th>
|
||||||
|
<th data-column-id="username" data-formatter="tooltip" data-width="250px">{{ __('Username') }}</th>
|
||||||
|
<th data-column-id="authz_by" data-formatter="tooltip">{{ __('Auth By') }}</th>
|
||||||
|
<th data-column-id="timeout" data-formatter="time_interval">{{ __('Timeout') }}</th>
|
||||||
|
<th data-column-id="time_elapsed" data-formatter="time_interval" >{{ __('Time Elapsed') }}</th>
|
||||||
|
<th data-column-id="time_left" data-formatter="time_interval" data-visible="false">{{ __('Time Left') }}</th>
|
||||||
|
<th data-column-id="authc_status" data-formatter="nac_authc" data-formatter="tooltip">{{ __('NAC Authc') }}</th>
|
||||||
|
<th data-column-id="authz_status" data-formatter="nac_authz">{{ __('NAC Authz') }}</th>
|
||||||
|
<th data-column-id="method" data-formatter="nac_method">{{ __('NAC Method') }}</th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</x-panel>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('css')
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
locations_grid = $("#nac-grid").bootgrid({
|
||||||
|
ajax: true,
|
||||||
|
rowCount: [25, 50, 100, -1],
|
||||||
|
url: "{{ route('table.port-nac') }}",
|
||||||
|
post: function () {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
formatters: {
|
||||||
|
"time_interval": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
var res = humanize_duration(value);
|
||||||
|
var res_light = res.split(' ').slice(0, 2).join(' ');
|
||||||
|
return "<span title=\'" + res.trim() + "\' data-toggle=\'tooltip\'>" + res_light + "</span>";
|
||||||
|
},
|
||||||
|
"tooltip": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
var vendor = '';
|
||||||
|
if (column.id == 'mac_address' && ((vendor = row['mac_oui']) != '' )) {
|
||||||
|
return "<span title=\'" + value + " (" + vendor + ")\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
return "<span title=\'" + value + "\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
},
|
||||||
|
"nac_authz": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
if (value === 'authorizationSuccess' || value === 'sussess') {
|
||||||
|
//typo in huawei MIB so we must keep sussess
|
||||||
|
return "<i class=\"fa fa-check-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:green;\"></i>";
|
||||||
|
} else if (value === 'authorizationFailed') {
|
||||||
|
return "<i class=\"fa fa-times-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:red;\"></i>";
|
||||||
|
} else {
|
||||||
|
return "<span class=\'label label-default\' title=\'" + value + "\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nac_domain": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
if (value === 'voice') {
|
||||||
|
return "<i class=\"fa fa-phone fa-lg icon-theme\" aria-hidden=\"true\"></i>";
|
||||||
|
} else if (value === 'data') {
|
||||||
|
return "<i class=\"fa fa-desktop fa-lg icon-theme\" aria-hidden=\"true\"></i>";
|
||||||
|
} else if (value === 'Disabled') {
|
||||||
|
return "<i class=\"fa fa-desktop fa-lg icon-theme\" aria-hidden=\"true\"></i>";
|
||||||
|
} else {
|
||||||
|
return "<span class=\'label label-default\' title=\'" + value + "\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nac_authc": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
if (value === 'notRun') {
|
||||||
|
return "<span class=\"label label-primary\">notRun</span>";
|
||||||
|
} else if (value === 'running') {
|
||||||
|
return "<span class=\"label label-primary\">running</span>";
|
||||||
|
} else if (value === 'failedOver') {
|
||||||
|
return "<i class=\"fa fa-times-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:red;\"></i>";
|
||||||
|
} else if (value === 'authcSuccess') {
|
||||||
|
return "<i class=\"fa fa-check-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:green;\">";
|
||||||
|
} else if (value === 'authcFailed') {
|
||||||
|
return "<i class=\"fa fa-times-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:red;\"></i>";
|
||||||
|
} else if (value === '6') {
|
||||||
|
return "<i class=\"fa fa-times-circle fa-lg icon-theme\" aria-hidden=\"true\" style=\"color:red;\"></i>";
|
||||||
|
} else {
|
||||||
|
return "<span class=\'label label-default\' title=\'" + value + "\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nac_method": function (column, row) {
|
||||||
|
var value = row[column.id];
|
||||||
|
if (value === 'dot1x') {
|
||||||
|
return "<span class=\"label label-success\">802.1x</span>";
|
||||||
|
} else if (value === 'macAuthBypass') {
|
||||||
|
return "<span class=\"label label-primary\">MAB</span>";
|
||||||
|
} else if (value === 'other') {
|
||||||
|
return "<span class=\"label label-danger\">Disabled</span>";
|
||||||
|
} else {
|
||||||
|
return "<span class=\'label label-default\' title=\'" + value + "\' data-toggle=\'tooltip\'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
@@ -66,6 +66,8 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::get('/', 'OverviewController@index')->name('home');
|
Route::get('/', 'OverviewController@index')->name('home');
|
||||||
Route::view('vminfo', 'vminfo');
|
Route::view('vminfo', 'vminfo');
|
||||||
|
|
||||||
|
Route::get('nac', 'NacController@index');
|
||||||
|
|
||||||
// Device Tabs
|
// Device Tabs
|
||||||
Route::prefix('device/{device}')->namespace('Device\Tabs')->name('device.')->group(function () {
|
Route::prefix('device/{device}')->namespace('Device\Tabs')->name('device.')->group(function () {
|
||||||
Route::put('notes', 'NotesController@update')->name('notes.update');
|
Route::put('notes', 'NotesController@update')->name('notes.update');
|
||||||
@@ -194,7 +196,7 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::post('location', 'LocationController');
|
Route::post('location', 'LocationController');
|
||||||
Route::post('mempools', 'MempoolsController');
|
Route::post('mempools', 'MempoolsController');
|
||||||
Route::post('outages', 'OutagesController');
|
Route::post('outages', 'OutagesController');
|
||||||
Route::post('port-nac', 'PortNacController');
|
Route::post('port-nac', 'PortNacController')->name('table.port-nac');
|
||||||
Route::post('port-stp', 'PortStpController');
|
Route::post('port-stp', 'PortStpController');
|
||||||
Route::post('ports', 'PortsController')->name('table.ports');
|
Route::post('ports', 'PortsController')->name('table.ports');
|
||||||
Route::post('routes', 'RoutesTablesController');
|
Route::post('routes', 'RoutesTablesController');
|
||||||
|
Reference in New Issue
Block a user