Merge branch '2.4' of github.com:MISP/MISP into 2.4

pull/5615/head
mokaddem 2020-02-10 14:35:54 +01:00
commit f7a0b1916e
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
6 changed files with 131 additions and 79 deletions

View File

@ -238,6 +238,7 @@ class ObjectsController extends AppController
$this->request->data['Attribute'] = $this->request->data['Object']['Attribute'];
unset($this->request->data['Object']['Attribute']);
}
$breakOnDuplicate = !empty($this->request->data['Object']['breakOnDuplicate']) || !empty($this->params['named']['breakOnDuplicate']);
$object = $this->MispObject->attributeCleanup($this->request->data);
// we pre-validate the attributes before we create an object at this point
// This allows us to stop the process and return an error (API) or return
@ -283,7 +284,7 @@ class ObjectsController extends AppController
}
if (empty($error)) {
unset($object['Object']['id']);
$result = $this->MispObject->saveObject($object, $eventId, $template, $this->Auth->user(), $errorBehaviour = 'halt');
$result = $this->MispObject->saveObject($object, $eventId, $template, $this->Auth->user(), 'halt', $breakOnDuplicate);
if (is_numeric($result)) {
$this->MispObject->Event->unpublishEvent($eventId);
} else {

View File

@ -63,67 +63,32 @@ class ThreadsController extends AppController
private function __view($thread_id, $eventView, $post_id)
{
$conditions = array('id' => $thread_id);
if ($eventView) {
$id = $thread_id;
// Show the discussion
$this->Thread->Behaviors->unload('SysLogLogable.SysLogLogable');
$params = array('conditions' => array('event_id' => $id),
'recursive' => -1,
'fields' => array('id', 'event_id', 'distribution', 'title', 'sharing_group_id', 'org_id')
);
$thread = $this->Thread->find('first', $params);
if (!empty($thread)) {
if (!$this->_isSiteAdmin()) {
if ($thread['Thread']['distribution'] == 0 && $thread['Thread']['org_id'] != $this->Auth->user('org_id')) {
throw new MethodNotAllowedException('Invalid Thread.');
}
if ($thread['Thread']['distribution'] == 4) {
if (!$this->Thread->SharingGroup->checkIfAuthorised($this->Auth->user(), $thread['Thread']['sharing_group_id'])) {
new NotFoundException('Invalid thread.');
}
}
}
$thread_id = $thread['Thread']['id'];
} else {
$thread_id = 0;
$event_id = $thread_id;
if (!$this->request->is('ajax')) {
$this->redirect(array('controller' => 'events', 'action' => 'view', $event_id));
}
$this->set('currentEvent', $id);
$conditions = array('event_id' => $event_id);
$this->set('currentEvent', $event_id);
$this->set('event_id', $event_id);
$this->set('context', 'event');
} else {
$this->Thread->recursive = -1;
$this->Thread->id = $thread_id;
//If the thread doesn't exist, throw exception
if (!$this->Thread->exists()) {
$this->set('context', 'thread');
}
$this->set('myuserid', $this->Auth->user('id'));
$thread = $this->Thread->find('first', array(
'conditions' => $conditions,
'recursive' => -1
));
if (empty($thread)) {
if (!$eventView) {
throw new NotFoundException('Invalid thread.');
}
$thread = $this->Thread->read();
// If the thread belongs to an event, we have to make sure that the event's distribution level hasn't changed.
// This is also a good time to update the thread's distribution level if that did happen.
if (!empty($thread['Thread']['event_id'])) {
$this->loadModel('Event');
$this->Event->id = $thread['Thread']['event_id'];
$this->Event->recursive = -1;
$this->Event->read(array('id', 'distribution', 'org_id', 'sharing_group_id'));
if ($this->Event->data['Event']['distribution'] != $thread['Thread']['distribution']) {
$this->Thread->saveField('distribution', $this->Event->data['Event']['distribution']);
}
if ($this->Event->data['Event']['sharing_group_id'] != $thread['Thread']['sharing_group_id']) {
$this->Thread->saveField('sharing_group_id', $this->Event->data['Event']['sharing_group_id']);
}
$this->set('event_id', $thread['Thread']['event_id']);
}
// If the user shouldn't be allowed to see the event send him away.
if (!$this->_isSiteAdmin()) {
if ($thread['Thread']['distribution'] == 0 && $thread['Thread']['org_id'] != $this->Auth->user('org_id')) {
throw new MethodNotAllowedException('Invalid Thread.');
}
if ($thread['Thread']['distribution'] == 4) {
if (!$this->Thread->SharingGroup->checkIfAuthorised($this->Auth->user(), $thread['Thread']['sharing_group_id'])) {
new NotFoundException('Invalid thread.');
}
}
} else {
$thread_id = $thread['Thread']['id'];
if (!$this->Thread->checkIfAuthorised($this->Auth->user(), $thread_id)) {
throw new NotFoundException('Invalid thread.');
}
}
if ($thread_id) {
@ -166,15 +131,6 @@ class ThreadsController extends AppController
$this->set('thread', $thread);
}
}
if ($eventView) {
$this->set('context', 'event');
if (!$this->request->is('ajax')) {
$this->redirect(array('controller' => 'events', 'action' => 'view', $id));
}
} else {
$this->set('context', 'thread');
}
$this->set('myuserid', $this->Auth->user('id'));
if ($this->request->is('ajax')) {
$this->layout = 'ajax';
$this->render('/Elements/eventdiscussion');
@ -185,7 +141,7 @@ class ThreadsController extends AppController
{
$this->loadModel('Posts');
$this->loadModel('SharingGroup');
$sgids = $this->SharingGroup->fetchAllAuthorised($this->Auth->user);
$sgids = $this->SharingGroup->fetchAllAuthorised($this->Auth->user());
$conditions = null;
if (!$this->_isSiteAdmin()) {
$conditions['AND']['OR'] = array(
@ -206,7 +162,7 @@ class ThreadsController extends AppController
}
$conditions['AND'][] = array('Thread.post_count >' => 0);
$this->paginate = array(
'conditions' => array($conditions),
'conditions' => $conditions,
'fields' => array('date_modified', 'date_created', 'org_id', 'distribution', 'title', 'post_count', 'sharing_group_id'),
'contain' => array(
'Post' =>array(

View File

@ -1066,6 +1066,7 @@ class UsersController extends AppController
$this->Bruteforce = ClassRegistry::init('Bruteforce');
if (!empty($this->request->data['User']['email'])) {
if ($this->Bruteforce->isBlacklisted($_SERVER['REMOTE_ADDR'], $this->request->data['User']['email'])) {
$expire = Configure::check('SecureAuth.expire') ? Configure::read('SecureAuth.expire') : 300;
throw new ForbiddenException('You have reached the maximum number of login attempts. Please wait ' . Configure::read('SecureAuth.expire') . ' seconds and try again.');
}
}
@ -1116,7 +1117,7 @@ class UsersController extends AppController
$this->Session->delete('Message.auth');
}
// don't display "invalid user" before first login attempt
if ($this->request->is('post')) {
if ($this->request->is('post') || $this->request->is('put')) {
$this->Flash->error(__('Invalid username or password, try again'));
if (isset($this->request->data['User']['email'])) {
$this->Bruteforce->insert($_SERVER['REMOTE_ADDR'], $this->request->data['User']['email']);

View File

@ -9,17 +9,19 @@ class Bruteforce extends AppModel
{
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$expire = time() + Configure::read('SecureAuth.expire');
$expire = Configure::check('SecureAuth.expire') ? Configure::read('SecureAuth.expire') : 300;
$amount = Configure::check('SecureAuth.amount') ? Configure::read('SecureAuth.amount') : 5;
$expire = time() + $expire;
$expire = date('Y-m-d H:i:s', $expire);
$bruteforceEntry = array(
'ip' => $ip,
'username' => $username,
'username' => trim(strtolower($username)),
'expire' => $expire
);
$this->save($bruteforceEntry);
$title = 'Failed login attempt using username ' . $username . ' from IP: ' . $_SERVER['REMOTE_ADDR'] . '.';
if ($this->isBlacklisted($ip, $username)) {
$title .= 'This has tripped the bruteforce protection after ' . Configure::read('SecureAuth.amount') . ' failed attempts. The user is now blacklisted for ' . Configure::read('SecureAuth.expire') . ' seconds.';
$title .= 'This has tripped the bruteforce protection after ' . $amount . ' failed attempts. The user is now blacklisted for ' . $expire . ' seconds.';
}
$log = array(
'org' => 'SYSTEM',
@ -36,10 +38,11 @@ class Bruteforce extends AppModel
{
$dataSourceConfig = ConnectionManager::getDataSource('default')->config;
$dataSource = $dataSourceConfig['datasource'];
$expire = date('Y-m-d H:i:s', time());
if ($dataSource == 'Database/Mysql') {
$sql = 'DELETE FROM bruteforces WHERE `expire` <= NOW();';
$sql = 'DELETE FROM bruteforces WHERE `expire` <= "' . $expire . '";';
} elseif ($dataSource == 'Database/Postgres') {
$sql = 'DELETE FROM bruteforces WHERE expire <= NOW();';
$sql = 'DELETE FROM bruteforces WHERE expire <= "' . $expire . '";';
}
$this->query($sql);
}
@ -49,11 +52,14 @@ class Bruteforce extends AppModel
// first remove old expired rows
$this->clean();
// count
$params = array('conditions' => array(
'Bruteforce.ip' => $ip,
'Bruteforce.username' => $username),);
$params = array(
'conditions' => array(
'Bruteforce.ip' => $ip,
'LOWER(Bruteforce.username)' => trim(strtolower($username)))
);
$count = $this->find('count', $params);
if ($count >= Configure::read('SecureAuth.amount')) {
$amount = Configure::check('SecureAuth.amount') ? Configure::read('SecureAuth.amount') : 5;
if ($count >= $amount) {
return true;
} else {
return false;

View File

@ -203,8 +203,49 @@ class MispObject extends AppModel
}
}
public function saveObject($object, $eventId, $template = false, $user, $errorBehaviour = 'drop')
public function checkForDuplicateObjects($object, $eventId)
{
$newObjectAttributes = array();
$existingObjectAttributes = array();
foreach ($object['Attribute'] as $attribute) {
$newObjectAttributes[] = hash('sha256', $attribute['object_relation'] . $attribute['category'] . $attribute['type'] . $attribute['value']);
}
$newObjectAttributeCount = count($newObjectAttributes);
$existingObjects = $this->find('all', array(
'recursive' => -1,
'contain' => array(
'Attribute' => array(
'fields' => array('value', 'type', 'category', 'object_relation'),
'conditions' => array('Attribute.deleted' => 0)
)
),
'fields' => array('template_uuid'),
'conditions' => array('template_uuid' => $object['Object']['template_uuid'], 'Object.deleted' => 0)
));
$oldObjects = array();
foreach ($existingObjects as $k => $existingObject) {
if (!empty($existingObject['Attribute']) && $newObjectAttributeCount == count($existingObject['Attribute'])) {
foreach ($existingObject['Attribute'] as $existingAttribute) {
$oldObjects[$k][] = hash('sha256',
$attribute['object_relation'] . $existingAttribute['category'] . $existingAttribute['type'] . $existingAttribute['value']
);
}
}
}
foreach ($oldObjects as $k => $object) {
if (empty(array_diff($object, $newObjectAttributes))) {
return true;
}
}
return false;
}
public function saveObject($object, $eventId, $template = false, $user, $errorBehaviour = 'drop', $breakOnDuplicate = false)
{
if ($breakOnDuplicate) {
$duplicate = $this->checkForDuplicateObjects($object, $eventId);
return array('value' => array('Duplicate object found. Since breakOnDuplicate is set the object will not be added.'));
}
$this->create();
$templateFields = array(
'name' => 'name',

View File

@ -38,4 +38,51 @@ class Thread extends AppModel
return true;
}
}
// convenience method to check whether a user can see an event
public function checkIfAuthorised($user, $id)
{
if (!isset($user['id'])) {
throw new MethodNotAllowedException('Invalid user.');
}
$this->id = $id;
if (!$this->exists()) {
return false;
}
$thread = $this->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1
));
if (!empty($thread['Thread']['event_id'])) {
$event = $this->Event->fetchEvent($user, array(
'eventid' => $thread['Thread']['event_id'],
'metadata' => true
));
if (empty($event)) {
return false;
}
$event = $event[0];
// update the distribution if it diverged from the event
if (
$event['Event']['distribution'] != $thread['Thread']['distribution'] ||
$event['Event']['sharing_group_id'] != $thread['Thread']['sharing_group_id']
) {
$this->Behaviors->unload('SysLogLogable.SysLogLogable');
$thread['Thread']['distribution'] = $event['Event']['distribution'];
$thread['Thread']['sharing_group_id'] = $event['Event']['sharing_group_id'];
$this->save($thread);
}
return !empty($event);
}
if ($user['Role']['perm_site_admin']) {
return true;
}
if ($thread['Thread']['org_id'] == $user['org_id'] || ($thread['Thread']['distribution'] > 0 && $thread['Thread']['distribution'] < 4)) {
return true;
}
if ($thread['Thread']['distribution'] == 4 && $this->SharingGroup->checkIfAuthorised($user, $thread['Thread']['sharing_group_id'])) {
return true;
}
return false;
}
}