mirror of https://github.com/MISP/MISP
Feature/api log and pin ip (#8965)
* fix: [sightings] don't be case insensitive on code side * chg: [AuthKey] store IPs used to connect and show them * chg: [AuthKey] db change * fix: [AuthKeys] prevent race condition with double IPs * chg: [git] exclude DebugKit plugin from git * fix: [AuthKey] integrate mokaddem's remarks * chg: [authkey] One-click IP as only allowed IP * chg: [authkey] pin IP on view page ---------pull/8989/head
parent
13d99cfaca
commit
d5ce838ddc
|
@ -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
|
||||
|
|
|
@ -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`),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' => [],
|
||||
|
|
|
@ -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;';
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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("<br>", array_map('h', $data['AuthKey']['allowed_ips']));
|
||||
return implode("<br />", 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'
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
$data_path = Hash::extract($row, $field['data_path']);
|
||||
$result = [];
|
||||
foreach ($data_path as $key => $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('<br />', $result);
|
||||
echo $result;
|
||||
?>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
$data_path = Hash::extract($data, $field['path']);
|
||||
$result = [];
|
||||
foreach ($data_path as $key => $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('<br />', $result);
|
||||
echo $result;
|
||||
?>
|
Loading…
Reference in New Issue