Further progress, still rough around the edges

- server settings and validation work
- configurable template via settings
- configurable via API as well

- Also trying to define the structure for future Plugin settings
- The idea is to have them in a separate tab all prepended with the plugin name
- since this is not yet part of the future flexible plugin system, it is still kept in the main codebase, but the idea is to get the naming conventions ready for the future version
pull/567/head
iglocska 2015-05-19 15:25:45 +02:00
parent 99f79ec318
commit 81bd84af11
6 changed files with 215 additions and 33 deletions

View File

@ -1792,12 +1792,56 @@ class AttributesController extends AppController {
$this->set('attributes', $attributes);
}
public function rpz($key='download', $tags=false, $eventId=false, $from=false, $to=false, $policy='DROP') {
$simpleFalse = array('eventId', 'tags', 'from', 'to');
public function rpz($key='download', $tags=false, $eventId=false, $from=false, $to=false, $policy=false, $garden = false, $ns = false, $email = false, $serial = false, $refresh = false, $retry = false, $expiry = false, $minimum_ttl = false, $ttl = false) {
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
// For Json: {"request":{"policy": "walled-garden","gargen":"garden.example.com"}}
// For XML: <request><policy>walled-garden</policy><gargen>garden.example.com</gargen></request>
// the response type is used to determine the parsing method (xml/json)
if ($this->request->is('post')) {
if ($this->response->type() === 'application/json') {
$data = $this->request->input('json_decode', true);
} elseif ($this->response->type() === 'application/xml') {
$data = $this->request->data;
} else {
throw new BadRequestException('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type.');
}
$paramArray = array('eventId', 'tags', 'from', 'to', 'policy', 'garden', 'ns', 'email', 'serial', 'refresh', 'retry', 'expiry', 'minimum_ttl', 'ttl');
foreach ($paramArray as $p) {
if (isset($data['request'][$p])) ${$p} = $data['request'][$p];
else ${$p} = null;
}
}
$simpleFalse = array('eventId', 'tags', 'from', 'to', 'policy','garden', 'ns', 'email', 'serial', 'refresh', 'retry', 'expiry', 'minimum_ttl', 'ttl');
foreach ($simpleFalse as $sF) {
if (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false') ${$sF} = false;
}
if (!in_array($policy, array('NXDOMAIN', 'NODATA', 'DROP'))) $policy = 'DROP';
if (!in_array($policy, array('NXDOMAIN', 'NODATA', 'DROP'))) $policy = false;
$lookupData = array(
'policy' => 'RPZ_policy',
'garden' => 'RPZ_walled_garden',
'ns' => 'RPZ_NS',
'email' => 'RPZ_EMAIL',
'serial' => 'RPZ_SOA_serial',
'refresh' => 'RPZ_SOA_refresh',
'retry' => 'RPZ_SOA_retry',
'expiry' => 'RPZ_SOA_expiry',
'minimum_ttl' => 'RPZ_SOA_minimum_ttl',
'ttl' => 'RPZ_ttl',
);
$this->loadModel('Server');
$rpzSettings = array();
foreach ($lookupData as $k => $v) {
if (${$k} !== false) $rpzSettings[$k] = ${$k};
else {
$tempSetting = Configure::read('Plugin.' . $v);
if (isset($tempSetting)) $rpzSettings[$k] = Configure::read('Plugin.' . $v);
else $rpzSettings[$k] = $this->Server->serverSettings['Plugin'][$v]['value'];
}
}
if ($from) $from = $this->Attribute->Event->dateFieldCheck($from);
if ($to) $from = $this->Attribute->Event->dateFieldCheck($to);
if ($key != 'download') {
@ -1819,12 +1863,12 @@ class AttributesController extends AppController {
if ($from) $file .= 'from-' . $from . '.';
if ($to) $file .= 'to-' . $to . '.';
if ($file == '') $file = 'all';
$this->header('Content-Disposition: download; filename="misp.rpz.' . $file . '.txt"');
#$this->header('Content-Disposition: download; filename="misp.rpz.' . $file . '.txt"');
$this->layout = 'text/default';
$this->loadModel('Whitelist');
$values = $this->Whitelist->removeWhitelistedValuesFromArray($values);
$this->set('values', $values);
$this->set('policy', $policy);
$this->set('rpzSettings', $rpzSettings);
//debug($values);
}

View File

@ -290,7 +290,8 @@ class ServersController extends AppController {
'GnuPG' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'Proxy' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'Security' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'misc' => array('count' => 0, 'errors' => 0, 'severity' => 5)
'misc' => array('count' => 0, 'errors' => 0, 'severity' => 5),
'Plugin' => array('count' => 0, 'errors' => 0, 'severity' => 5)
);
$writeableErrors = array(0 => 'OK', 1 => 'Directory doesn\'t exist', 2 => 'Directory is not writeable');
$gpgErrors = array(0 => 'OK', 1 => 'FAIL: settings not set', 2 => 'FAIL: bad GnuPG.*', 3 => 'FAIL: encrypt failed');

View File

@ -9,6 +9,7 @@ class RPZExport {
'hostname' => '# The following hostnames will '
);
$policy_explanations = array(
'walled-garden' => 'returns the defined alternate location.',
'NXDOMAIN' => 'return NXDOMAIN (name does not exist) irrespective of actual result received.',
'NODATA' => 'returns NODATA (name exists but no answers returned) irrespective of actual result received.',
'DROP' => 'timeout.',
@ -16,34 +17,51 @@ class RPZExport {
return $explanations[$type] . $policy_explanations[$policy] . PHP_EOL . PHP_EOL;
}
public function export($items, $policy) {
switch ($policy) {
case 'NXDOMAIN':
$action = '.';
break;
case 'NODATA':
$action = '*.';
break;
default:
private function __buildHeader() {
$header = '';
return $header;
}
public function export($items, $rpzSettings) {
$result = '';
switch ($rpzSettings['policy']) {
case 0:
$policy = 'DROP';
$action = 'rpz-drop.';
}
$result = '';
$result .= $this->explain('ip', $policy);
foreach ($items['ip'] as $item) {
$result .= $this->__convertIP($item, $action);
break;
case 1:
$policy = 'NXDOMAIN';
$action = '.';
break;
case 2:
$policy = 'NODATA';
$action = '*.';
break;
case 3:
$policy = 'walled-garden';
$action = $rpzSettings['walled'];
break;
}
$result .= $this->explain('domain', $policy);
foreach ($items['domain'] as $item) {
$result .= $this->__convertdomain($item, $action);
if (isset($items['ip'])) {
$result .= $this->explain('ip', $policy);
foreach ($items['ip'] as $item) {
$result .= $this->__convertIP($item, $action);
}
}
$result .= $this->explain('hostname', $policy);
foreach ($items['hostname'] as $item) {
$result .= $this->__converthostname($item, $action);
if (isset($items['domain'])) {
$result .= $this->explain('domain', $policy);
foreach ($items['domain'] as $item) {
$result .= $this->__convertdomain($item, $action);
}
}
if (isset($items['hostname'])) {
$result .= $this->explain('hostname', $policy);
foreach ($items['hostname'] as $item) {
$result .= $this->__converthostname($item, $action);
}
}
return $result;
}

View File

@ -515,6 +515,98 @@ class Server extends AppModel {
'type' => 'string',
),
),
'Plugin' => array(
'branch' => 1,
'RPZ_TTL' => array(
'level' => 2,
'description' => 'The duration (in seconds) of how long the user will be locked out when the allowed number of login attempts are exhausted.',
'value' => '',
'errorMessage' => '',
'test' => 'testForNumeric',
'type' => 'string',
),
'RPZ_policy' => array(
'level' => 1,
'description' => 'The duration (in seconds) of how long the user will be locked out when the allowed number of login attempts are exhausted.',
'value' => 0,
'errorMessage' => '',
'test' => 'testForRPZBehaviour',
'type' => 'numeric',
'options' => array(0 => 'DROP', 1 => 'NXDOMAIN', 2 => 'NODATA', 3 => 'walled-garden'),
),
'RPZ_walled_garden' => array(
'level' => 2,
'description' => 'The default walled garden used by the RPZ export if the walled garden setting is picked for the export.',
'value' => '127.0.0.1',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'RPZ_SOA_serial' => array(
'level' => 2,
'description' => 'The serial in the SOA portion of the zone file. (numeric, best practice is yyyymmddrr where rr is the two digit sub-revision of the file. $date will automatically get converted to the current yyyymmdd, so $date00 is a valid setting).',
'value' => '$date00',
'errorMessage' => '',
'test' => 'testForRPZSerial',
'type' => 'string',
),
'RPZ_SOA_refresh' => array(
'level' => 2,
'description' => 'The refresh specified in the SOA portion of the zone file. (in seconds, or shorthand duration such as 15m)',
'value' => '2h',
'errorMessage' => '',
'test' => 'testForRPZDuration',
'type' => 'string',
),
'RPZ_SOA_retry' => array(
'level' => 2,
'description' => 'The retry specified in the SOA portion of the zone file. (in seconds, or shorthand duration such as 15m)',
'value' => '30m',
'errorMessage' => '',
'test' => 'testForRPZDuration',
'type' => 'string',
),
'RPZ_SOA_expiry' => array(
'level' => 2,
'description' => 'The expiry specified in the SOA portion of the zone file. (in seconds, or shorthand duration such as 15m)',
'value' => '30d',
'errorMessage' => '',
'test' => 'testForRPZDuration',
'type' => 'string',
),
'RPZ_SOA_minimum_ttl' => array(
'level' => 2,
'description' => 'The minimum TTL specified in the SOA portion of the zone file. (in seconds, or shorthand duration such as 15m)',
'value' => '1h',
'errorMessage' => '',
'test' => 'testForRPZDuration',
'type' => 'string',
),
'RPZ_ttl' => array(
'level' => 2,
'description' => 'The TTL of the zone file. (in seconds, or shorthand duration such as 15m)',
'value' => '1w',
'errorMessage' => '',
'test' => 'testForRPZDuration',
'type' => 'string',
),
'RPZ_NS' => array(
'level' => 2,
'description' => '',
'value' => 'localhost.',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'RPZ_EMAIL' => array(
'level' => 2,
'description' => 'The e-mail address specified in the SOA portion of the zone file.',
'value' => 'root.localhost',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
),
'debug' => array(
'level' => 0,
'description' => 'The debug level of the instance, always use 0 for production instances.',
@ -1037,7 +1129,7 @@ class Server extends AppModel {
public function testPasswordLength($value) {
$numeric = $this->testforNumeric($value);
if ($numeric !== true) return $numeric;
if ($numeric < 0) return 'Length cannot be negative, set a positive integer or 0 (to choose the default option).';
if ($value < 0) return 'Length cannot be negative, set a positive integer or 0 (to choose the default option).';
return true;
}
@ -1046,6 +1138,34 @@ class Server extends AppModel {
return true;
}
public function testForRPZDuration($value) {
if (($this->testForNumeric($value) !== true && preg_match('/^[0-9]*[mhdw]$/i', $value)) || $value >= 0) {
return true;
} else {
return 'Negative seconds found. The following formats are accepted: seconds (positive integer), or duration (positive integer) followed by a letter denoting scale (such as m, h, d, w for minutes, hours, days, weeks)';
}
}
public function testForRPZBehaviour($value) {
$numeric = $this->testforNumeric($value);
if ($numeric !== true) return $numeric;
if ($value < 0 || $value > 3) return 'Invalid setting, valid range is 0-3 (0 = DROP, 1 = NXDOMAIN, 2 = NODATA, 3 = walled garden.';
return true;
}
public function testForRPZSerial($value) {
if ($this->testForEmpty($value) !== true) return $this->testForEmpty($value);
if (!preg_match('/^((\$date(\d*)|\d*))$/', $value)) return 'Invalid format.';
//if (!preg_match('/^\w+(\.\w+)*(\.?) \w+(\.\w+)* \((\$date(\d*)|\d*)( ((\d*)|(\d*)[hHmMdD])){4}\)$/', $value)) return 'Invalid format.';
return true;
}
public function testForRPZNS($value) {
if ($this->testForEmpty($value) !== true) return $this->testForEmpty($value);
if (!preg_match('/^\w+(\.\w+)*(\.?) \w+(\.\w+)*$/', $value)) return 'Invalid format.';
return true;
}
// never come here directly, always go through a secondary check like testForTermsFile in order to also pass along the expected file path
private function __testForFile($value, $path) {
@ -1056,10 +1176,9 @@ class Server extends AppModel {
return true;
}
public function serverSettingsSaveValue($setting, $value) {
Configure::write($setting, $value);
Configure::dump('config.php', 'default', array('MISP', 'GnuPG', 'Proxy', 'SecureAuth', 'Security', 'debug'));
Configure::dump('config.php', 'default', array('MISP', 'GnuPG', 'Proxy', 'SecureAuth', 'Security', 'debug', 'Plugin'));
}
public function checkVersion($newest) {

View File

@ -1,4 +1,4 @@
<?php
App::uses('RPZExport', 'Export');
$rpzExport = new RPZExport();
echo ($rpzExport->export($values, $policy));
echo ($rpzExport->export($values, $rpzSettings));

View File

@ -2,7 +2,7 @@
<h2>Server settings</h2>
<?php
echo $this->element('healthElements/tabs');
if (in_array($tab, array('MISP', 'Security', 'GnuPG', 'Proxy', 'misc'))) {
if (in_array($tab, array('MISP', 'Security', 'GnuPG', 'Proxy', 'misc', 'Plugin'))) {
echo $this->element('healthElements/settings_tab');
} else if ($tab == 'diagnostics') {
echo $this->element('healthElements/diagnostics');