diff --git a/.gitignore b/.gitignore
index a84039004..5cf0333ac 100755
--- a/.gitignore
+++ b/.gitignore
@@ -100,6 +100,7 @@ app/Lib/EventWarning/Custom/*
/app/tmp/cached_exports/sha256/*
/app/tmp/cached_exports/bro/*
/app/Plugin/CakeResque
+/app/Plugin/DebugKit
.gnupg
.smime
*.swp
diff --git a/INSTALL/MYSQL.sql b/INSTALL/MYSQL.sql
index 9afec4086..150d9aaa5 100644
--- a/INSTALL/MYSQL.sql
+++ b/INSTALL/MYSQL.sql
@@ -88,6 +88,12 @@ CREATE TABLE IF NOT EXISTS `attribute_tags` (
INDEX `tag_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+-- -------------------------------------------------------
+
+--
+-- Table structure for table `auth_keys`
+--
+
CREATE TABLE IF NOT EXISTS `auth_keys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
@@ -98,6 +104,8 @@ CREATE TABLE IF NOT EXISTS `auth_keys` (
`expiration` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`comment` text COLLATE utf8mb4_unicode_ci,
+ `allowed_ips` text COLLATE utf8mb4_unicode_ci,
+ `unique_ips` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`id`),
KEY `authkey_start` (`authkey_start`),
KEY `authkey_end` (`authkey_end`),
diff --git a/app/Controller/AuthKeysController.php b/app/Controller/AuthKeysController.php
index dbcb0ed91..ce77a2b33 100644
--- a/app/Controller/AuthKeysController.php
+++ b/app/Controller/AuthKeysController.php
@@ -238,6 +238,30 @@ class AuthKeysController extends AppController
]);
}
+ public function pin($id, $ip) {
+ if ($this->request->is('post')) {
+ // find entry, to confirm user is authorized
+ $conditions = $this->__prepareConditions();
+ $conditions['AND'][]['AuthKey.id'] = $id;
+ $authKey = $this->AuthKey->find(
+ 'first',
+ ['conditions' => $conditions,
+ 'recursive'=> 1
+ ]
+ );
+ // update the key with the source IP
+ if ($authKey) {
+ $authKey['AuthKey']['allowed_ips'] = $ip;
+ $this->AuthKey->save($authKey, ['fieldList' => ['allowed_ips']]);
+ $this->Flash->success(__('IP address set as allowed source for the Key.'));
+ } else {
+ $this->Flash->error(__('Failed to set IP as source'));
+ }
+ }
+ $this->redirect($this->referer());
+ // $this->redirect(['controller' => 'auth_keys', 'view' => 'index']);
+ }
+
/**
* Return conditions according to current user permission.
* @return array
diff --git a/app/Controller/Component/ACLComponent.php b/app/Controller/Component/ACLComponent.php
index 013610ad3..36152778e 100644
--- a/app/Controller/Component/ACLComponent.php
+++ b/app/Controller/Component/ACLComponent.php
@@ -72,8 +72,9 @@ class ACLComponent extends Component
'add' => ['AND' => ['perm_auth', 'not_read_only_authkey']],
'delete' => ['AND' => ['perm_auth', 'not_read_only_authkey']],
'edit' => ['AND' => ['perm_auth', 'not_read_only_authkey']],
+ 'pin' => ['AND' => ['perm_auth', 'not_read_only_authkey']],
'index' => ['perm_auth'],
- 'view' => ['perm_auth']
+ 'view' => ['perm_auth'],
],
'cerebrates' => [
'add' => [],
diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php
index dda95b94c..2ddc40ff8 100644
--- a/app/Model/AppModel.php
+++ b/app/Model/AppModel.php
@@ -84,7 +84,7 @@ class AppModel extends Model
87 => false, 88 => false, 89 => false, 90 => false, 91 => false, 92 => false,
93 => false, 94 => false, 95 => true, 96 => false, 97 => true, 98 => false,
99 => false, 100 => false, 101 => false, 102 => false, 103 => false, 104 => false,
- 105 => false, 106 => false
+ 105 => false, 106 => false, 107 => false
);
const ADVANCED_UPDATES_DESCRIPTION = array(
@@ -1944,6 +1944,9 @@ class AppModel extends Model
case 106:
$sqlArray[] = "ALTER TABLE `taxii_servers` MODIFY `baseurl` varchar(191) NOT NULL;";
break;
+ case 107:
+ $sqlArray[] = "ALTER TABLE `auth_keys` ADD `unique_ips` text COLLATE utf8mb4_unicode_ci";
+ break;
case 'fixNonEmptySharingGroupID':
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
diff --git a/app/Model/AuthKey.php b/app/Model/AuthKey.php
index e1caa4e10..b177180ff 100644
--- a/app/Model/AuthKey.php
+++ b/app/Model/AuthKey.php
@@ -104,6 +104,12 @@ class AuthKey extends AppModel
if (isset($val['AuthKey']['allowed_ips'])) {
$results[$key]['AuthKey']['allowed_ips'] = JsonTool::decode($val['AuthKey']['allowed_ips']);
}
+ if (isset($val['AuthKey']['unique_ips'])) {
+ $results[$key]['AuthKey']['unique_ips'] = JsonTool::decode($val['AuthKey']['unique_ips']);
+ } else {
+ $results[$key]['AuthKey']['unique_ips'] = [];
+ }
+
}
return $results;
}
@@ -117,6 +123,13 @@ class AuthKey extends AppModel
$this->data['AuthKey']['allowed_ips'] = JsonTool::encode($this->data['AuthKey']['allowed_ips']);
}
}
+ if (isset($this->data['AuthKey']['unique_ips'])) {
+ if (empty($this->data['AuthKey']['unique_ips'])) {
+ $this->data['AuthKey']['unique_ips'] = null;
+ } else {
+ $this->data['AuthKey']['unique_ips'] = JsonTool::encode($this->data['AuthKey']['unique_ips']);
+ }
+ }
return true;
}
@@ -162,12 +175,27 @@ class AuthKey extends AppModel
$possibleAuthkeys = $this->find('all', [
'recursive' => -1,
- 'fields' => ['id', 'authkey', 'user_id', 'expiration', 'allowed_ips', 'read_only'],
+ 'fields' => ['id', 'authkey', 'user_id', 'expiration', 'allowed_ips', 'read_only', 'unique_ips'],
'conditions' => $conditions,
]);
$passwordHasher = $this->getHasher();
foreach ($possibleAuthkeys as $possibleAuthkey) {
- if ($passwordHasher->check($authkey, $possibleAuthkey['AuthKey']['authkey'])) {
+ if ($passwordHasher->check($authkey, $possibleAuthkey['AuthKey']['authkey'])) { // valid authkey
+ // store IP in db if not there yet
+ $remote_ip = $this->_remoteIp();
+ $update_db_ip = true;
+ if (in_array($remote_ip, $possibleAuthkey['AuthKey']['unique_ips'])) {
+ $update_db_ip = false; // IP already seen, skip saving in DB
+ } else { // first time this IP is seen for this API key
+ $possibleAuthkey['AuthKey']['unique_ips'][] = $remote_ip;
+ }
+ if ($update_db_ip) {
+ // prevent double entries due to race condition
+ $possibleAuthkey['AuthKey']['unique_ips'] = array_unique($possibleAuthkey['AuthKey']['unique_ips']);
+ // save in db
+ $this->save($possibleAuthkey, ['fieldList' => ['unique_ips']]);
+ }
+ // fetch user
$user = $this->User->getAuthUser($possibleAuthkey['AuthKey']['user_id']);
if ($user) {
$user = $this->setUserData($user, $possibleAuthkey);
diff --git a/app/Model/Sighting.php b/app/Model/Sighting.php
index 5fe2eb61f..2562b404d 100644
--- a/app/Model/Sighting.php
+++ b/app/Model/Sighting.php
@@ -786,7 +786,7 @@ class Sighting extends AppModel
foreach ($values as $value) {
foreach (array('value1', 'value2') as $field) {
$conditions['OR'][] = array(
- 'LOWER(Attribute.' . $field . ') LIKE' => strtolower($value)
+ 'Attribute.' . $field => $value
);
}
}
diff --git a/app/View/AuthKeys/index.ctp b/app/View/AuthKeys/index.ctp
index 0fc6e0dd8..37110217d 100644
--- a/app/View/AuthKeys/index.ctp
+++ b/app/View/AuthKeys/index.ctp
@@ -73,6 +73,11 @@
'name' => __('Allowed IPs'),
'data_path' => 'AuthKey.allowed_ips',
],
+ [
+ 'name' => __('Seen IPs'),
+ 'data_path' => 'AuthKey.unique_ips',
+ 'element' => 'authkey_pin',
+ ]
],
'title' => empty($ajax) ? __('Authentication key Index') : false,
'description' => empty($ajax) ? __('A list of API keys bound to a user.') : false,
diff --git a/app/View/AuthKeys/view.ctp b/app/View/AuthKeys/view.ctp
index ff9c8262d..106063b27 100644
--- a/app/View/AuthKeys/view.ctp
+++ b/app/View/AuthKeys/view.ctp
@@ -48,7 +48,7 @@ echo $this->element('genericElements/SingleViews/single_view', [
'type' => 'custom',
'function' => function (array $data) {
if (is_array($data['AuthKey']['allowed_ips'])) {
- return implode("
", array_map('h', $data['AuthKey']['allowed_ips']));
+ return implode("
", array_map('h', $data['AuthKey']['allowed_ips']));
}
return __('All');
}
@@ -83,9 +83,9 @@ echo $this->element('genericElements/SingleViews/single_view', [
'requirement' => isset($keyUsage),
],
[
- 'key' => __('Unique IPs'),
- 'raw' => $uniqueIps,
- 'requirement' => isset($keyUsage),
+ 'key' => __('Seen IPs'),
+ 'path' => 'AuthKey.unique_ips',
+ 'type' => 'authkey_pin'
]
],
]);
diff --git a/app/View/Elements/genericElements/IndexTable/Fields/authkey_pin.ctp b/app/View/Elements/genericElements/IndexTable/Fields/authkey_pin.ctp
new file mode 100644
index 000000000..42bd93e5b
--- /dev/null
+++ b/app/View/Elements/genericElements/IndexTable/Fields/authkey_pin.ctp
@@ -0,0 +1,27 @@
+ $ip) {
+ $data_ip['ip'] = $ip;
+ $action = ['class' => 'modal-open',
+ 'url' => $baseurl. "/authKeys/pin/" . h($row['AuthKey']['id']) . '/' . h($ip),
+ 'icon' => 'thumbtack',
+ 'postLink' => true,
+ 'postLinkConfirm' => __('Use this as only possible source IP?'),
+ 'title' => __('Use this IP')];
+ $form = $this->Form->postLink(
+ '',
+ $action['url'],
+ array(
+ 'class' => $this->FontAwesome->getClass($action['icon']) . ' ' . (empty($action['class']) ? '' : h($action['class'])),
+ 'title' => empty($action['title']) ? '' : h($action['title']),
+ 'aria-label' => empty($action['title']) ? '' : h($action['title']),
+ ),
+ $action['postLinkConfirm']
+ ) . ' ';
+ $result[$key] = h($ip) . " " . $form;
+ }
+
+ $result = implode('
', $result);
+ echo $result;
+?>
diff --git a/app/View/Elements/genericElements/SingleViews/Fields/authkey_pinField.ctp b/app/View/Elements/genericElements/SingleViews/Fields/authkey_pinField.ctp
new file mode 100644
index 000000000..dcff3b254
--- /dev/null
+++ b/app/View/Elements/genericElements/SingleViews/Fields/authkey_pinField.ctp
@@ -0,0 +1,27 @@
+ $ip) {
+ $data_ip['ip'] = $ip;
+ $action = ['class' => 'modal-open',
+ 'url' => $baseurl. "/authKeys/pin/" . h($data['AuthKey']['id']) . '/' . h($ip),
+ 'icon' => 'thumbtack',
+ 'postLink' => true,
+ 'postLinkConfirm' => __('Use this as only possible source IP?'),
+ 'title' => __('Use this IP')];
+ $form = $this->Form->postLink(
+ '',
+ $action['url'],
+ array(
+ 'class' => $this->FontAwesome->getClass($action['icon']) . ' ' . (empty($action['class']) ? '' : h($action['class'])),
+ 'title' => empty($action['title']) ? '' : h($action['title']),
+ 'aria-label' => empty($action['title']) ? '' : h($action['title']),
+ ),
+ $action['postLinkConfirm']
+ ) . ' ';
+ $result[$key] = h($ip) . " " . $form;
+ }
+
+ $result = implode('
', $result);
+ echo $result;
+?>