diff --git a/PyMISP b/PyMISP index cca5287b2..9a7adb2e0 160000 --- a/PyMISP +++ b/PyMISP @@ -1 +1 @@ -Subproject commit cca5287b2b11a1951789680c75e10636dde98add +Subproject commit 9a7adb2e0d60d2edee9f541db808652875bae20e diff --git a/README.md b/README.md index f7516f8bb..2a28375fb 100644 --- a/README.md +++ b/README.md @@ -108,16 +108,16 @@ License This software is licensed under [GNU Affero General Public License version 3](http://www.gnu.org/licenses/agpl-3.0.html) -* Copyright (C) 2012-2022 Christophe Vandeplas +* Copyright (C) 2012-2023 Christophe Vandeplas * Copyright (C) 2012 Belgian Defence * Copyright (C) 2012 NATO / NCIRC -* Copyright (C) 2013-2022 Andras Iklody -* Copyright (C) 2015-2022 CIRCL - Computer Incident Response Center Luxembourg +* Copyright (C) 2013-2023 Andras Iklody +* Copyright (C) 2015-2023 CIRCL - Computer Incident Response Center Luxembourg * Copyright (C) 2016 Andreas Ziegler -* Copyright (C) 2018-2022 Sami Mokaddem -* Copyright (C) 2018-2022 Christian Studer -* Copyright (C) 2015-2022 Alexandre Dulaunoy +* Copyright (C) 2018-2023 Sami Mokaddem +* Copyright (C) 2018-2023 Christian Studer +* Copyright (C) 2015-2023 Alexandre Dulaunoy * Copyright (C) 2018-2022 Steve Clement -* Copyright (C) 2020-2022 Jakub Onderka +* Copyright (C) 2020-2023 Jakub Onderka For more information, [the list of authors and contributors](AUTHORS) is available. diff --git a/VERSION.json b/VERSION.json index 7b36fa445..6e1915b14 100644 --- a/VERSION.json +++ b/VERSION.json @@ -1 +1 @@ -{"major":2, "minor":4, "hotfix":167} +{"major":2, "minor":4, "hotfix":168} diff --git a/app/Controller/AppController.php b/app/Controller/AppController.php index 4b0d81383..ccb8e2201 100755 --- a/app/Controller/AppController.php +++ b/app/Controller/AppController.php @@ -34,7 +34,7 @@ class AppController extends Controller public $helpers = array('OrgImg', 'FontAwesome', 'UserName'); private $__queryVersion = '147'; - public $pyMispVersion = '2.4.167'; + public $pyMispVersion = '2.4.168'; public $phpmin = '7.2'; public $phprec = '7.4'; public $phptoonew = '8.0'; @@ -152,20 +152,25 @@ class AppController extends Controller } $this->User = ClassRegistry::init('User'); - if ($this->Auth->user()) { - if ($this->User->checkForSessionDestruction($this->Auth->user('id'))) { - $this->Auth->logout(); - $this->Session->destroy(); - $message = __('User deauthenticated on administrator request. Please reauthenticate.'); - if ($this->_isRest()) { - throw new ForbiddenException($message); - } else { - $this->Flash->warning($message); - $this->_redirectToLogin(); - } - } + + if (!empty($this->request->params['named']['disable_background_processing'])) { + Configure::write('MISP.background_jobs', 0); } + Configure::write('CurrentController', $controller); + Configure::write('CurrentAction', $action); + $versionArray = $this->User->checkMISPVersion(); + $this->mispVersion = implode('.', $versionArray); + $this->Security->blackHoleCallback = 'blackHole'; + + // send users away that are using ancient versions of IE + // Make sure to update this if IE 20 comes out :) + if (isset($_SERVER['HTTP_USER_AGENT'])) { + if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) { + throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact')); + } + } + // For fresh installation (salt empty) generate a new salt if (!Configure::read('Security.salt')) { $this->User->Server->serverSettingsSaveValue('Security.salt', $this->User->generateRandomPassword(32)); @@ -176,6 +181,10 @@ class AppController extends Controller $this->User->Server->serverSettingsSaveValue('MISP.uuid', CakeText::uuid()); } + /** + * Authentication related activities + */ + // Check if Apache provides kerberos authentication data $authUserFields = $this->User->describeAuthFields(); $envvar = Configure::read('ApacheSecureAuth.apacheEnv'); @@ -191,22 +200,7 @@ class AppController extends Controller } else { $this->Auth->authenticate[AuthComponent::ALL]['userFields'] = $authUserFields; } - if (!empty($this->request->params['named']['disable_background_processing'])) { - Configure::write('MISP.background_jobs', 0); - } - Configure::write('CurrentController', $controller); - Configure::write('CurrentAction', $action); - $versionArray = $this->User->checkMISPVersion(); - $this->mispVersion = implode('.', $versionArray); - $this->Security->blackHoleCallback = 'blackHole'; - - // send users away that are using ancient versions of IE - // Make sure to update this if IE 20 comes out :) - if (isset($_SERVER['HTTP_USER_AGENT'])) { - if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) { - throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact')); - } - } + $userLoggedIn = false; if (Configure::read('Plugin.CustomAuth_enable')) { $userLoggedIn = $this->__customAuthentication($_SERVER); @@ -528,12 +522,24 @@ class AppController extends Controller } $this->Flash->info($message); $this->Auth->logout(); - throw new MethodNotAllowedException($message);//todo this should pb be removed? + $this->_redirectToLogin(); + return false; } else { $this->Flash->error(__('Warning: MISP is currently disabled for all users. Enable it in Server Settings (Administration -> Server Settings -> MISP tab -> live). An update might also be in progress, you can see the progress in ') , array('params' => array('url' => $this->baseurl . '/servers/updateProgress/', 'urlName' => __('Update Progress')), 'clear' => 1)); } } + // kill existing sessions for a user if the admin/instance decides so + // exclude API authentication as it doesn't make sense + if (!$this->isApiAuthed && $this->User->checkForSessionDestruction($user['id'])) { + $this->Auth->logout(); + $this->Session->destroy(); + $message = __('User deauthenticated on administrator request. Please reauthenticate.'); + $this->Flash->warning($message); + $this->_redirectToLogin(); + return false; + } + // Force logout doesn't make sense for API key authentication if (!$this->isApiAuthed && $user['force_logout']) { $this->User->id = $user['id']; diff --git a/app/Controller/AuditLogsController.php b/app/Controller/AuditLogsController.php index 24d4f709d..4199c748f 100644 --- a/app/Controller/AuditLogsController.php +++ b/app/Controller/AuditLogsController.php @@ -192,10 +192,13 @@ class AuditLogsController extends AppController $list[$k]['AuditLog']['action_human'] = $this->actions[$item['AuditLog']['action']]; } - $this->set('list', $list); + $this->set('data', $list); $this->set('event', $event); $this->set('mayModify', $this->__canModifyEvent($event)); - $this->set('title_for_layout', __('Audit logs for event #%s', $event['Event']['id'])); + $this->set('menuData', [ + 'menuList' => 'event', + 'menuItem' => 'eventLog' + ]); } public function fullChange($id) diff --git a/app/Controller/Component/ACLComponent.php b/app/Controller/Component/ACLComponent.php index c78f98c15..99390e34d 100644 --- a/app/Controller/Component/ACLComponent.php +++ b/app/Controller/Component/ACLComponent.php @@ -125,7 +125,7 @@ class ACLComponent extends Component 'decayingModel' => array( "update" => array(), "export" => array('*'), - "import" => array('*'), + "import" => array('OR' => array('perm_admin', 'perm_decaying')), "view" => array('*'), "index" => array('*'), "add" => array( 'OR' => array('perm_admin', 'perm_decaying')), diff --git a/app/Controller/Component/CRUDComponent.php b/app/Controller/Component/CRUDComponent.php index fb276e34d..81ad2bfb1 100644 --- a/app/Controller/Component/CRUDComponent.php +++ b/app/Controller/Component/CRUDComponent.php @@ -114,7 +114,7 @@ class CRUDComponent extends Component $this->Controller->Flash->success($message); if (!empty($params['displayOnSuccess'])) { $this->Controller->set('entity', $data); - $this->Controller->set('referer', $this->Controller->referer()); + $this->Controller->set('referer', $this->Controller->referer(['action' => 'view', $model->id], true)); $this->Controller->render($params['displayOnSuccess']); return; } diff --git a/app/Controller/ServersController.php b/app/Controller/ServersController.php index 2123522ec..9035853d2 100644 --- a/app/Controller/ServersController.php +++ b/app/Controller/ServersController.php @@ -1726,6 +1726,7 @@ class ServersController extends AppController if (!$server) { throw new NotFoundException(__('Invalid server')); } + @session_write_close(); // close session to allow concurrent requests $result = $this->Server->runConnectionTest($server); if ($result['status'] == 1) { if (isset($result['info']['version']) && preg_match('/^[0-9]+\.+[0-9]+\.[0-9]+$/', $result['info']['version'])) { diff --git a/app/Controller/ShadowAttributesController.php b/app/Controller/ShadowAttributesController.php index 48b448091..6ba08cbd1 100644 --- a/app/Controller/ShadowAttributesController.php +++ b/app/Controller/ShadowAttributesController.php @@ -62,8 +62,10 @@ class ShadowAttributesController extends AppController // If the old_id is set to anything but 0 then we're dealing with a proposed edit to an existing attribute if ($shadow['old_id'] != 0) { // Find the live attribute by the shadow attribute's uuid, so we can begin editing it - $this->Attribute->contain = 'Event'; - $activeAttribute = $this->Attribute->findByUuid($shadow['uuid']); + $activeAttribute = $this->Attribute->find('first', [ + 'conditions' => ['Attribute.uuid' => $shadow['uuid']], + 'contain' => ['Event'], + ]); // Send those away that shouldn't be able to edit this if (!$this->__canModifyEvent($activeAttribute)) { diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php index 51ca9e6d2..08ab97cb0 100644 --- a/app/Controller/UsersController.php +++ b/app/Controller/UsersController.php @@ -1230,6 +1230,11 @@ class UsersController extends AppController $this->Bruteforce->insert($this->request->data['User']['email']); } } + + // + // Actions needed for the first access, when the database is not populated yet. + // + // populate the DB with the first role (site admin) if it's empty if (!$this->User->Role->hasAny()) { $siteAdmin = array('Role' => array( @@ -1279,7 +1284,6 @@ class UsersController extends AppController } $org_id = $this->User->Organisation->id; } - // populate the DB with the first user if it's empty if (!$this->User->hasAny()) { if (!isset($org_id)) { @@ -1291,7 +1295,6 @@ class UsersController extends AppController $org_id = $firstOrg['Organisation']['id']; } } - $this->User->runUpdates(); $this->User->createInitialUser($org_id); } @@ -1300,25 +1303,25 @@ class UsersController extends AppController private function _postlogin() { - $this->User->extralog($this->Auth->user(), "login"); - $this->User->Behaviors->disable('SysLogLogable.SysLogLogable'); - $this->User->id = $this->Auth->user('id'); - $user = $this->User->find('first', array( - 'conditions' => array( - 'User.id' => $this->Auth->user('id') - ), - 'recursive' => -1 - )); - unset($user['User']['password']); - $this->User->updateLoginTimes($user['User']); - $lastUserLogin = $user['User']['last_login']; - $this->User->Behaviors->enable('SysLogLogable.SysLogLogable'); - if ($lastUserLogin) { - $readableDatetime = (new DateTime())->setTimestamp($lastUserLogin)->format('D, d M y H:i:s O'); // RFC822 - $this->Flash->info(__('Welcome! Last login was on %s', $readableDatetime)); - } - // no state changes are ever done via GET requests, so it is safe to return to the original page: - $this->redirect($this->Auth->redirectUrl()); + $this->User->extralog($this->Auth->user(), "login"); + $this->User->Behaviors->disable('SysLogLogable.SysLogLogable'); + $this->User->id = $this->Auth->user('id'); + $user = $this->User->find('first', array( + 'conditions' => array( + 'User.id' => $this->Auth->user('id') + ), + 'recursive' => -1 + )); + unset($user['User']['password']); + $this->User->updateLoginTimes($user['User']); + $lastUserLogin = $user['User']['last_login']; + $this->User->Behaviors->enable('SysLogLogable.SysLogLogable'); + if ($lastUserLogin) { + $readableDatetime = (new DateTime())->setTimestamp($lastUserLogin)->format('D, d M y H:i:s O'); // RFC822 + $this->Flash->info(__('Welcome! Last login was on %s', $readableDatetime)); + } + // no state changes are ever done via GET requests, so it is safe to return to the original page: + $this->redirect($this->Auth->redirectUrl()); } public function routeafterlogin() diff --git a/app/View/AuditLogs/event_index.ctp b/app/View/AuditLogs/event_index.ctp index 9fd0aa7d4..b78afc18b 100644 --- a/app/View/AuditLogs/event_index.ctp +++ b/app/View/AuditLogs/event_index.ctp @@ -1,48 +1,59 @@ -
-

- - - - - - - - - - - - - - - - - - - - - - -
LightPaginator->sort('created') ?>LightPaginator->sort('user_id', __('User')) ?>LightPaginator->sort('org_id', __('Org')) ?>LightPaginator->sort('action') ?>
Time->time($item['AuditLog']['created']); ?>OrgImg->getOrgLogo($item, 24) : '' ?>element('AuditLog/change', ['item' => $item]) ?>
- -
-element('/genericElements/SideMenu/side_menu', ['menuList' => 'event', 'menuItem' => 'eventLog']); - +', empty($ajax) ? ' class="index"' : ''); +echo $this->element('genericElements/IndexTable/index_table', [ + 'data' => [ + 'light_paginator' => 1, + 'data' => $data, + 'fields' => [ + [ + 'name' => __('Created'), + 'data_path' => 'AuditLog.created', + 'sort' => 'AuditLog.created', + 'class' => 'short', + 'element' => 'time' + ], + [ + 'name' => __('User'), + 'data_path' => 'User.email', + 'sort' => 'User.email', + 'class' => 'short', + 'empty' => 'SYSTEM' + ], + [ + 'name' => __('Organisation'), + 'data_path' => 'Organisation', + 'sort' => 'Organisation.name', + 'element' => 'org', + 'class' => 'short' + ], + [ + 'name' => __('Action'), + 'data_path' => 'AuditLog.action_human', + 'sort' => 'AuditLog.action_human', + 'class' => 'short' + ], + [ + 'name' => __('Model'), + 'data_path' => 'AuditLog', + 'element' => 'model', + 'class' => 'short' + ], + [ + 'name' => __('Title'), + 'data_path' => 'AuditLog.title', + 'class' => 'limitedWidth' + ], + [ + 'name' => __('Change'), + 'data_path' => 'AuditLog', + 'element' => 'custom_element', + 'element_path' => 'AuditLog/change' + ] + ], + 'title' => __('Audit logs for event #%s', intval($event['Event']['id'])) + ] +]); +echo ''; +if (empty($ajax)) { + echo $this->element('/genericElements/SideMenu/side_menu', $menuData); +} diff --git a/app/View/AuthKeys/authkey_display.ctp b/app/View/AuthKeys/authkey_display.ctp index 5cd4161d3..f64321798 100644 --- a/app/View/AuthKeys/authkey_display.ctp +++ b/app/View/AuthKeys/authkey_display.ctp @@ -12,7 +12,7 @@

- + diff --git a/app/View/Elements/genericElements/IndexTable/Fields/custom_element.ctp b/app/View/Elements/genericElements/IndexTable/Fields/custom_element.ctp new file mode 100644 index 000000000..b661e6bda --- /dev/null +++ b/app/View/Elements/genericElements/IndexTable/Fields/custom_element.ctp @@ -0,0 +1 @@ +element($field['element_path'], ['item' => $row]) ?> \ No newline at end of file diff --git a/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp b/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp index 0d63cdc3f..2698be658 100644 --- a/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp +++ b/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp @@ -1,5 +1,8 @@ 1) { $implodeGlue = isset($field['array_implode_glue']) ? $field['array_implode_glue'] : ', '; diff --git a/app/View/Elements/genericElements/IndexTable/Fields/model.ctp b/app/View/Elements/genericElements/IndexTable/Fields/model.ctp new file mode 100644 index 000000000..52d0eaeda --- /dev/null +++ b/app/View/Elements/genericElements/IndexTable/Fields/model.ctp @@ -0,0 +1,3 @@ +Time->time($time); \ No newline at end of file diff --git a/app/View/Feeds/add.ctp b/app/View/Feeds/add.ctp index 47ccdefbd..dc49d38a2 100755 --- a/app/View/Feeds/add.ctp +++ b/app/View/Feeds/add.ctp @@ -73,7 +73,7 @@ echo $this->element('genericElements/Form/genericForm', [ 'field' => 'orgc_id', 'label' => __('Creator organisation'), 'options' => $dropdownData['orgs'], - 'value' => $this->request->params['action'] === 'add' ? $me['org_id'] : '', + 'value' => $this->request->params['action'] === 'add' ? $me['org_id'] : null, 'type' => 'dropdown', 'div' => ['id' => 'OrgcDiv', 'style' => 'display:none', 'class' => 'optionalField'], 'class' => 'form-control span6' diff --git a/app/View/Logs/event_index.ctp b/app/View/Logs/event_index.ctp index 7f38ecdeb..d53dec313 100644 --- a/app/View/Logs/event_index.ctp +++ b/app/View/Logs/event_index.ctp @@ -1,22 +1,24 @@

+

- - - - - - + + + + + + @@ -39,7 +41,7 @@
Paginator->sort('org');?>Paginator->sort('email');?>Paginator->sort('action');?>Paginator->sort('model');?>Paginator->sort('title');?>Paginator->sort('created');?>LightPaginator->sort('org');?>LightPaginator->sort('email');?>LightPaginator->sort('action');?>LightPaginator->sort('model');?>LightPaginator->sort('title');?>LightPaginator->sort('created');?>

Paginator->counter(array( + echo $this->LightPaginator->counter(array( 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}') )); ?> @@ -47,9 +49,9 @@

diff --git a/app/files/misp-galaxy b/app/files/misp-galaxy index ac1242a40..f605f041d 160000 --- a/app/files/misp-galaxy +++ b/app/files/misp-galaxy @@ -1 +1 @@ -Subproject commit ac1242a40e3a165ea664f3a8640dc346a5877c3a +Subproject commit f605f041d99057b767231831d7f5970be6c1fcb9 diff --git a/app/files/misp-objects b/app/files/misp-objects index 4e19aa30b..fd603be32 160000 --- a/app/files/misp-objects +++ b/app/files/misp-objects @@ -1 +1 @@ -Subproject commit 4e19aa30ba94940e38bf50164248a572139ca520 +Subproject commit fd603be3283953b68ed48ede7afd2e19f43577ac diff --git a/app/files/scripts/misp-stix b/app/files/scripts/misp-stix index c60a6e76c..93da9ae3a 160000 --- a/app/files/scripts/misp-stix +++ b/app/files/scripts/misp-stix @@ -1 +1 @@ -Subproject commit c60a6e76ccd735d460b382effee9af6aae7fa4ab +Subproject commit 93da9ae3a468f1beacc7edbfe241e6df89b94250 diff --git a/app/files/taxonomies b/app/files/taxonomies index e4d0c5807..14f1349fa 160000 --- a/app/files/taxonomies +++ b/app/files/taxonomies @@ -1 +1 @@ -Subproject commit e4d0c58076c2c1af20491b1d9be56967a16ac515 +Subproject commit 14f1349fad189091960311018a4cabcb1018adb9 diff --git a/app/files/warninglists b/app/files/warninglists index ab2938e00..a51a9adc6 160000 --- a/app/files/warninglists +++ b/app/files/warninglists @@ -1 +1 @@ -Subproject commit ab2938e008eb5ec085d9e9c8e7c5c4d6fd466a39 +Subproject commit a51a9adc6c693bd5d2bf83f49920df7247ced298 diff --git a/app/webroot/js/action_table.js b/app/webroot/js/action_table.js index 2bd54af97..103e36f4d 100644 --- a/app/webroot/js/action_table.js +++ b/app/webroot/js/action_table.js @@ -162,7 +162,7 @@ class ActionTable { tr.id = "tr_" + this.__uuidv4(); for (var col of row) { var td = document.createElement('td'); - td.innerHTML = col; + td.textContent = col; tr.appendChild(td); } this.__add_action_button(tr); diff --git a/app/webroot/js/event-graph.js b/app/webroot/js/event-graph.js index 97cf672e8..150e9b662 100644 --- a/app/webroot/js/event-graph.js +++ b/app/webroot/js/event-graph.js @@ -636,7 +636,7 @@ class EventGraph { btn_plot.data('network-preview', preview); btn_plot.popover({ container: 'body', - content: function() { return ''; }, + content: function() { return ''; }, placement: 'right', trigger: 'hover', template: '', @@ -2002,7 +2002,7 @@ function reset_graph_history() { btn_plot.data('network-preview', preview); btn_plot.popover({ container: 'body', - content: function() { return ''; }, + content: function() { return ''; }, placement: 'right', trigger: 'hover', template: '',