Commit 06795584 authored by Ad Schellevis's avatar Ad Schellevis

(ids) add ssl fingerprint ui components

parent aa0fc181
...@@ -34,6 +34,7 @@ use \OPNsense\Base\Filters\QueryFilter; ...@@ -34,6 +34,7 @@ use \OPNsense\Base\Filters\QueryFilter;
use \OPNsense\Core\Backend; use \OPNsense\Core\Backend;
use \OPNsense\IDS\IDS; use \OPNsense\IDS\IDS;
use \OPNsense\Core\Config; use \OPNsense\Core\Config;
use \OPNsense\Base\UIModelGrid;
/** /**
* Class SettingsController Handles settings related API actions for the IDS module * Class SettingsController Handles settings related API actions for the IDS module
...@@ -487,4 +488,166 @@ class SettingsController extends ApiControllerBase ...@@ -487,4 +488,166 @@ class SettingsController extends ApiControllerBase
} }
return $result; return $result;
} }
/**
* search fingerprints
* @return array list of found fingerprints
*/
public function searchFingerprintAction()
{
if ($this->request->isPost()) {
$this->sessionClose();
// fetch query parameters
$itemsPerPage = $this->request->getPost('rowCount', 'int', 9999);
$currentPage = $this->request->getPost('current', 'int', 1);
$sortBy = array("number");
$sortDescending = false;
if ($this->request->hasPost('sort') && is_array($this->request->getPost("sort"))) {
$sortBy = array_keys($this->request->getPost("sort"));
if ($this->request->getPost("sort")[$sortBy[0]] == "desc") {
$sortDescending = true;
}
}
$searchPhrase = $this->request->getPost('searchPhrase', 'string', '');
// create model and fetch query resuls
$fields = array("enabled", "action", "description", "fingerprint");
$mdlIDS = $this->getModel();
$grid = new UIModelGrid($mdlIDS->rules->fingerprint);
return $grid->fetch($fields, $itemsPerPage, $currentPage, $sortBy, $sortDescending, $searchPhrase);
} else {
return array();
}
}
/**
* update fingerprint
* @param string $uuid fingerprint internal id
* @return array save result + validation output
* @throws \Phalcon\Validation\Exception
*/
public function setFingerprintAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("fingerprint")) {
$mdlIDS = $this->getModel();
if ($uuid != null) {
$node = $mdlIDS->getNodeByReference('rules.fingerprint.'.$uuid);
if ($node != null) {
$node->setNodes($this->request->getPost("fingerprint"));
$validations = $mdlIDS->validate($node->__reference, "fingerprint");
if (count($validations)) {
$result['validations'] = $validations;
} else {
// serialize model to config and save
$mdlIDS->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
}
}
return $result;
}
/**
* add new fingerprint
* @return array save result + validation output
* @throws \Phalcon\Validation\Exception
*/
public function addFingerprintAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("fingerprint")) {
$mdlIDS = $this->getModel();
$node = $mdlIDS->rules->fingerprint->Add();
$node->setNodes($this->request->getPost("fingerprint"));
$validations = $mdlIDS->validate($node->__reference, "fingerprint");
if (count($validations)) {
$result['validations'] = $validations;
} else {
// serialize model to config and save
$mdlIDS->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
/**
* get fingerprint properties
* @param null|string $uuid fingerprint internal id
* @return array fingerprint properties
*/
public function getFingerprintAction($uuid = null)
{
$mdlIDS = $this->getModel();
if ($uuid != null) {
$node = $mdlIDS->getNodeByReference('rules.fingerprint.'.$uuid);
if ($node != null) {
// return node
return array("fingerprint" => $node->getNodes());
}
} else {
// generate new node, but don't save to disc
$node = $mdlIDS->rules->fingerprint->add() ;
return array("fingerprint" => $node->getNodes());
}
return array();
}
/**
* delete fingerprint item
* @param string $uuid fingerprint internal id
* @return array
* @throws \Phalcon\Validation\Exception
*/
public function delFingerprintAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $uuid != null) {
$mdlIDS = $this->getModel();
if ($mdlIDS->rules->fingerprint->del($uuid)) {
// if item is removed, serialize to config and save
$mdlIDS->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
return $result;
}
/**
* toggle fingerprint by uuid (enable/disable)
* @param $uuid fingerprint internal id
* @param $enabled desired state enabled(1)/disabled(1), leave empty for toggle
* @return array status
*/
public function toggleFingerprintAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost() && $uuid != null) {
$mdlIDS = $this->getModel();
$node = $mdlIDS->getNodeByReference('rules.fingerprint.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ($node->enabled->__toString() == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
// if item has toggled, serialize to config and save
$mdlIDS->serializeToConfig();
Config::getInstance()->save();
}
}
return $result;
}
} }
...@@ -49,6 +49,8 @@ class IndexController extends \OPNsense\Base\IndexController ...@@ -49,6 +49,8 @@ class IndexController extends \OPNsense\Base\IndexController
$this->view->formGeneralSettings = $this->getForm("generalSettings"); $this->view->formGeneralSettings = $this->getForm("generalSettings");
// link alert list dialog // link alert list dialog
$this->view->formDialogRuleset = $this->getForm("dialogRuleset"); $this->view->formDialogRuleset = $this->getForm("dialogRuleset");
// link fingerprint dialog
$this->view->formDialogFingerprint = $this->getForm("DialogFingerprint");
// choose template // choose template
$this->view->pick('OPNsense/IDS/index'); $this->view->pick('OPNsense/IDS/index');
} }
......
<form>
<field>
<id>fingerprint.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>enable this fingerprint rule</help>
</field>
<field>
<id>fingerprint.fingerprint</id>
<label>Fingerprint</label>
<type>text</type>
<help>the SSL fingerprint, for example B5:E1:B3:70:5E:7C:FF:EB:92:C4:29:E5:5B:AC:2F:AE:70:17:E9:9E</help>
</field>
<field>
<id>fingerprint.action</id>
<label>Action</label>
<type>dropdown</type>
<help>set action to perform here, only used when in IPS mode</help>
</field>
<field>
<id>fingerprint.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>
...@@ -23,6 +23,31 @@ ...@@ -23,6 +23,31 @@
</OptionValues> </OptionValues>
</action> </action>
</rule> </rule>
<fingerprint type="ArrayField">
<!--SSL fingerprints -->
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<fingerprint type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-fA-F:]){59,59}$/u</mask>
<ValidationMessage>A SSL fingerprint should be a 59 character long hex value</ValidationMessage>
</fingerprint>
<description type="TextField">
<Required>Y</Required>
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){1,255}$/u</mask>
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
</description>
<action type="OptionField">
<Required>Y</Required>
<default>alert</default>
<OptionValues>
<alert>Alert</alert>
<drop>Drop</drop>
</OptionValues>
</action>
</fingerprint>
</rules> </rules>
<files> <files>
<file type="ArrayField"> <file type="ArrayField">
......
...@@ -252,6 +252,18 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -252,6 +252,18 @@ POSSIBILITY OF SUCH DAMAGE.
}, },
} }
}); });
} else if (e.target.id == 'ssl_tab') {
$('#grid-fingerprints').bootgrid('destroy'); // always destroy previous grid, so data is always fresh
$("#grid-fingerprints").UIBootgrid({
search:'/api/ids/settings/searchfingerprint',
get:'/api/ids/settings/getFingerprint/',
set:'/api/ids/settings/setFingerprint/',
add:'/api/ids/settings/addFingerprint/',
del:'/api/ids/settings/delFingerprint/',
toggle:'/api/ids/settings/toggleFingerprint/'
}
);
} }
}) })
...@@ -392,6 +404,7 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -392,6 +404,7 @@ POSSIBILITY OF SUCH DAMAGE.
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs"> <ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#settings" id="settings_tab">{{ lang._('Settings') }}</a></li> <li class="active"><a data-toggle="tab" href="#settings" id="settings_tab">{{ lang._('Settings') }}</a></li>
<li><a data-toggle="tab" href="#rules" id="rule_tab">{{ lang._('Rules') }}</a></li> <li><a data-toggle="tab" href="#rules" id="rule_tab">{{ lang._('Rules') }}</a></li>
<li><a data-toggle="tab" href="#ssl" id="ssl_tab">{{ lang._('SSL') }}</a></li>
<li><a data-toggle="tab" href="#alerts" id="alert_tab">{{ lang._('Alerts') }}</a></li> <li><a data-toggle="tab" href="#alerts" id="alert_tab">{{ lang._('Alerts') }}</a></li>
<li><a href="" id="scheduled_updates" style="display:none">{{ lang._('Schedule') }}</a></li> <li><a href="" id="scheduled_updates" style="display:none">{{ lang._('Schedule') }}</a></li>
</ul> </ul>
...@@ -474,6 +487,40 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -474,6 +487,40 @@ POSSIBILITY OF SUCH DAMAGE.
</tfoot> </tfoot>
</table> </table>
</div> </div>
<div id="ssl" class="tab-pane fade in">
<!-- tab page "ssl" -->
<div class="bootgrid-header container-fluid">
<div class="row">
<div class="col-sm-12">
<strong>SSL Fingerprints</strong>
</div>
</div>
</div>
<hr/>
<table id="grid-fingerprints" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogFingerprint">
<thead>
<tr>
<th data-column-id="enabled" data-formatter="rowtoggle" data-sortable="false" data-width="10em">{{ lang._('Enabled') }}</th>
<th data-column-id="fingerprint" data-type="string" data-sortable="true">{{ lang._('Fingerprint') }}</th>
<th data-column-id="description" data-type="string" data-sortable="true">{{ lang._('Description') }}</th>
<th data-column-id="action" data-type="string" data-sortable="true">{{ lang._('Action') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr >
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div id="alerts" class="tab-pane fade in"> <div id="alerts" class="tab-pane fade in">
<div class="bootgrid-header container-fluid"> <div class="bootgrid-header container-fluid">
<div class="row"> <div class="row">
...@@ -539,3 +586,4 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -539,3 +586,4 @@ POSSIBILITY OF SUCH DAMAGE.
{{ partial("layout_partials/base_dialog",['fields':formDialogRule,'id':'DialogRule','label':'Rule details','hasSaveBtn':'true','msgzone_width':1])}} {{ partial("layout_partials/base_dialog",['fields':formDialogRule,'id':'DialogRule','label':'Rule details','hasSaveBtn':'true','msgzone_width':1])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogAlert,'id':'DialogAlert','label':'Alert details','hasSaveBtn':'false','msgzone_width':1])}} {{ partial("layout_partials/base_dialog",['fields':formDialogAlert,'id':'DialogAlert','label':'Alert details','hasSaveBtn':'false','msgzone_width':1])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogRuleset,'id':'DialogRuleset','label':'Ruleset details','hasSaveBtn':'true','msgzone_width':1])}} {{ partial("layout_partials/base_dialog",['fields':formDialogRuleset,'id':'DialogRuleset','label':'Ruleset details','hasSaveBtn':'true','msgzone_width':1])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogFingerprint,'id':'DialogFingerprint','label':'Fingerprint details','hasSaveBtn':'true'])}}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment