MISP/app/Controller/UsersController.php

1078 lines
40 KiB
PHP

<?php
App::uses('AppController', 'Controller');
/**
* Users Controller
*
* @property User $User
*/
class UsersController extends AppController {
public $newkey;
public $components = array(
'Security',
'Email',
);
public $paginate = array(
'limit' => 60,
'recursive' => -1,
'order' => array(
'Organisation.name' => 'ASC'
),
'contain' => array(
'Organisation' => array('id', 'name'),
'Role' => array('id', 'name')
)
);
public function beforeFilter() {
parent::beforeFilter();
// what pages are allowed for non-logged-in users
$this->Auth->allow('login', 'logout');
}
/**
* view method
*
* @param string $id
* @return void
* @throws NotFoundException
*/
public function view($id = null) {
if ("me" == $id) $id = $this->Auth->user('id');
if (!$this->_isSiteAdmin() && $this->Auth->user('id') != $id) {
throw new NotFoundException(__('Invalid user or not authorised.'));
}
$this->User->id = $id;
$this->User->recursive = 0;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$this->set('user', $this->User->read(null, $id));
}
/**
* edit method
*
* @param string $id
* @return void
* @throws NotFoundException
*/
public function edit($id = null) {
$me = false;
if ("me" == $id) {
$id = $this->Auth->user('id');
$me = true;
}
$this->User->read(null, $id);
if (!$this->User->exists() && !$me && !$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $this->User->data['User']['org_id'])) {
throw new NotFoundException(__('Invalid user or not authorised.'));
}
if ($this->request->is('post') || $this->request->is('put')) {
// What fields should be saved (allowed to be saved)
$fieldList = array('email', 'autoalert', 'gpgkey', 'nids_sid', 'contactalert', 'disabled');
if ("" != $this->request->data['User']['password'])
$fieldList[] = 'password';
// Save the data
if ($this->User->save($this->request->data, true ,$fieldList)) {
$this->Session->setFlash(__('The profile has been updated'));
$this->_refreshAuth();
$this->redirect(array('action' => 'view', $id));
} else {
$this->Session->setFlash(__('The profile could not be updated. Please, try again.'));
}
} else {
$this->User->recursive = 0;
$this->User->read(null, $id);
if (!$this->User->exists() || (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != $this->User->data['User']['org_id'])) {
throw new NotFoundException(__('Invalid user or not authorised.'));
}
$this->User->set('password', '');
$this->request->data = $this->User->data;
}
$roles = $this->User->Role->find('list');
$this->set(compact('roles'));
$this->set('id', $id);
}
public function change_pw() {
$id = $this->Auth->user('id');
$this->User->id = $id;
if ($this->request->is('post') || $this->request->is('put')) {
// What fields should be saved (allowed to be saved)
$fieldList[] = 'password';
// Save the data
if ($this->User->save($this->request->data, true ,$fieldList)) {
$this->Session->setFlash(__('Password Changed.'));
$this->User->saveField('email', $this->Auth->user('email'));
$this->User->saveField('change_pw', 0);
$this->_refreshAuth();
$this->redirect(array('action' => 'view', $id));
} else {
$this->Session->setFlash(__('The password could not be updated. Please, try again.'));
}
} else {
$this->User->recursive = 0;
$this->User->read(null, $id);
$this->User->set('password', '');
$this->request->data = $this->User->data;
}
// XXX ACL roles
$this->__extralog("change_pw");
$roles = $this->User->Role->find('list');
$this->set(compact('roles'));
}
/**
* delete method
*
* @param string $id
* @return void
* @throws MethodNotAllowedException
* @throws NotFoundException
*/
public function delete($id = null) {
if ("me" == $id) $id = $this->Auth->user('id');
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
//if ($this->Auth->User('org') != 'ADMIN' && $this->Auth->User('org') != $this->User->data['User']['org']) $this->redirect(array('controller' => 'users', 'action' => 'index', 'admin' => true));
//// Only own profile
//if ($this->Auth->user('id') != $id) {
// throw new ForbiddenException('You are not authorized to delete this profile.');
//}
if ($this->User->delete()) {
$this->Session->setFlash(__('User deleted'));
$this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('User was not deleted'));
$this->redirect(array('action' => 'index'));
}
/**
* admin_index method
*
* @return void
*/
public function admin_index() {
$this->User->virtualFields['org_ci'] = 'UPPER(Organisation.name)';
$urlparams = "";
$passedArgsArray = array();
$booleanFields = array('autoalert', 'contactalert', 'termsaccepted');
$textFields = array('role', 'email', 'all');
// org admins can't see users of other orgs
if ($this->_isSiteAdmin()) $textFields[] = 'org';
$this->set('passedArgs', json_encode($this->passedArgs));
// check each of the passed arguments whether they're a filter (could also be a sort for example) and if yes, add it to the pagination conditions
foreach ($this->passedArgs as $k => $v) {
if (substr($k, 0, 6) === 'search') {
if ($v != "") {
if ($urlparams != "") $urlparams .= "/";
$urlparams .= $k . ":" . $v;
}
$searchTerm = substr($k, 6);
if (in_array($searchTerm, $booleanFields)) {
if ($v != "") $this->paginate['conditions'][] = array('User.' . $searchTerm => $v);
} else if (in_array($searchTerm, $textFields)) {
if ($v != "") {
if ($searchTerm == "role") $searchTerm = "role_id";
$pieces = explode('|', $v);
$test = array();
foreach ($pieces as $piece) {
if ($piece[0] == '!') {
if ($searchTerm == 'email') $this->paginate['conditions']['AND'][] = array('LOWER(User.' . $searchTerm . ') NOT LIKE' => '%' . strtolower(substr($piece, 1)) . '%');
else if ($searchTerm == 'org') $this->paginate['conditions']['AND'][] = array('User.org_id !=' => substr($piece, 1));
else $this->paginate['conditions']['AND'][] = array('User.' . $searchTerm => substr($piece, 1));
} else {
if ($searchTerm == 'email') $test['OR'][] = array('LOWER(User.' . $searchTerm . ') LIKE' => '%' . strtolower($piece) . '%');
else if ($searchTerm == 'org') $this->paginate['conditions']['OR'][] = array('User.org_id' => $piece);
else if ($searchTerm == 'all') {
$this->paginate['conditions']['AND'][] = array(
'OR' => array(
'UPPER(User.email) LIKE' => '%' . strtoupper($piece) . '%',
'UPPER(Organisation.name) LIKE' => '%' . strtoupper($piece) . '%',
'UPPER(Role.name) LIKE' => '%' . strtoupper($piece) . '%',
),
);
}
else $test['OR'][] = array('User.' . $searchTerm => $piece);
}
}
if (!empty($test)) $this->paginate['conditions']['AND'][] = $test;
}
}
$passedArgsArray[$searchTerm] = $v;
}
}
$this->set('urlparams', $urlparams);
$this->set('passedArgsArray', $passedArgsArray);
$conditions = array();
if ($this->_isSiteAdmin()) {
$this->set('users', $this->paginate());
} else {
if (!($this->_isAdmin())) throw new NotFoundException(__('Invalid user or not authorised.'));
$conditions['User.org_id'] = $this->Auth->User('org_id');
$this->paginate = array(
'conditions' => array($conditions),
);
$this->set('users', $this->paginate());
}
}
public function index($id) {
$this->autoRender = false;
$this->layout = false;
$overrideAbleParams = array('all');
$passedArgs = $this->passedArgs;
$overrideAbleParams = array('all');
$org = $this->User->Organisation->read(null, $id);
if (!$this->User->Organisation->exists() || !($this->_isSiteAdmin() || $this->Auth->user('org_id') == $id)) {
throw new MethodNotAllowedException('Organisation not found or no authorisation to view it.');
}
$user_fields = array('id', 'email', 'gpgkey', 'nids_sid');
$conditions = array('org_id' => $id);
if ($this->_isSiteAdmin() || ($this->_isAdmin() && $this->Auth->user('org_id') == $id)) {
$user_fields = array_merge($user_fields, array('newsread', 'termsaccepted', 'change_pw', 'authkey'));
}
if (isset($this->request->data)) {
if (isset($this->request->data['searchall'])) $this->request->data['all'] = $this->request->data['searchall'];
if (isset($this->request->data['all']) && !empty($this->request->data['all'])) {
$passedArgs['searchall'] = $this->request->data['all'];
$conditions['OR'][] = array('User.email LIKE' => '%' . $passedArgs['searchall'] . '%');
}
}
$this->set('passedArgs', json_encode($passedArgs));
$this->paginate = array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => $user_fields,
'contain' => array(
'Role' => array(
'fields' => array('id', 'name', 'perm_auth', 'perm_site_admin'),
),
),
);
// add roles to the list even though it is not used for the query itself, we can reuse the user_fields array in the view to build the table
$user_fields = array_merge(array_slice($user_fields, 0, 2), array('role'), array_slice($user_fields, 2));
$this->set('user_fields', $user_fields);
$this->set('users', $this->paginate());
$this->set('org', $org['Organisation']['name']);
$this->render('ajax/index');
//return new CakeResponse(array('body'=> json_encode(array('users' => $users, 'status' => 200))));
}
public function admin_filterUserIndex() {
if (!$this->_isAdmin() && !$this->_isSiteAdmin()) throw new MethodNotAllowedException();
$passedArgsArray = array();
$booleanFields = array('autoalert', 'contactalert', 'termsaccepted');
$textFields = array('role', 'email');
$showorg = 0;
// org admins can't see users of other orgs
if ($this->_isSiteAdmin()) {
$textFields[] = 'org';
$showorg = 1;
}
$this->set('differentFilters', $booleanFields);
$this->set('simpleFilters', $textFields);
$rules = array_merge($booleanFields, $textFields);
$this->set('showorg', $showorg);
$filtering = array();
foreach ($booleanFields as $b) {
$filtering[$b] = '';
}
foreach ($textFields as $t) {
$filtering[$t] = array('OR' => array(), 'NOT' => array());
}
foreach ($this->passedArgs as $k => $v) {
if (substr($k, 0, 6) === 'search') {
$searchTerm = substr($k, 6);
if (in_array($searchTerm, $booleanFields)) $filtering[$searchTerm] = $v;
else if (in_array($searchTerm, $textFields)) {
$pieces = explode('|', $v);
foreach ($pieces as $piece) {
if ($piece[0] == '!') $filtering[$searchTerm]['NOT'][] = substr($piece,1);
else $filtering[$searchTerm]['OR'][] = $piece;
}
}
$passedArgsArray[$searchTerm] = $v;
}
}
$this->set('filtering', json_encode($filtering));
$roles = $this->User->Role->find('all', array('recursive' => -1));
$roleNames = array();
$roleJSON = array();
foreach ($roles as $k => $v) {
$roleNames[$v['Role']['id']] = $v['Role']['name'];
$roleJSON[] = array('id' => $v['Role']['id'], 'value' => $v['Role']['name']);
}
$temp = $this->User->Organisation->find('all', array(
'conditions' => array('local' => 1),
'recursive' => -1,
'fields' => array('id', 'name'),
'order' => array('LOWER(name) ASC')
));
$orgs = array();
foreach ($temp as $org) {
$orgs[$org['Organisation']['id']] = $org['Organisation']['name'];
}
$this->set('orgs', $orgs);
$this->set('roles', $roleNames);
$this->set('roleJSON', json_encode($roleJSON));
$rules = $this->_arrayToValuesIndexArray($rules);
$this->set('rules', $rules);
$this->set('baseurl', Configure::read('MISP.baseurl'));
$this->layout = 'ajax';
}
/**
* admin_view method
*
* @param string $id
* @return void
* @throws NotFoundException
*/
public function admin_view($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$this->set('user', $this->User->read(null, $id));
if (!$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $this->User->data['User']['org_id'])) throw new MethodNotAllowedException();
$temp = $this->User->field('invited_by');
$this->set('id', $id);
$this->set('user2', $this->User->read(null, $temp));
}
/**
* admin_add method
*
* @return void
*/
public function admin_add() {
if (!$this->_isAdmin()) throw new Exception('Administrators only.');
$this->set('currentOrg', $this->Auth->User('org_id'));
$this->set('isSiteAdmin', $this->_isSiteAdmin());
$params = null;
if (!$this->_isSiteAdmin()) {
$params = array('conditions' => array('perm_site_admin !=' => 1, 'perm_sync !=' => 1, 'perm_regexp_access !=' => 1));
}
$roles = $this->User->Role->find('list', $params);
$syncRoles = $this->User->Role->find('list', array('conditions' => array('perm_sync' => 1), 'recursive' => -1));
if ($this->request->is('post')) {
if (!array_key_exists($this->request->data['User']['role_id'], $syncRoles)) $this->request->data['User']['server_id'] = 0;
$this->User->create();
// set invited by
$this->loadModel('Role');
$this->Role->recursive = -1;
$chosenRole = $this->Role->findById($this->request->data['User']['role_id']);
$this->request->data['User']['invited_by'] = $this->Auth->user('id');
if ($chosenRole['Role']['perm_sync']) {
$this->request->data['User']['change_pw'] = 0;
$this->request->data['User']['termsaccepted'] = 1;
} else {
$this->request->data['User']['change_pw'] = 1;
$this->request->data['User']['termsaccepted'] = 0;
}
if (!isset($this->request->data['User']['disabled'])) $this->request->data['User']['disabled'] = false;
$this->request->data['User']['newsread'] = '2000-01-01';
if (!$this->_isSiteAdmin()) {
$this->request->data['User']['org_id'] = $this->Auth->User('org_id');
$this->loadModel('Role');
$this->Role->recursive = -1;
$chosenRole = $this->Role->findById($this->request->data['User']['role_id']);
if ($chosenRole['Role']['perm_site_admin'] == 1 || $chosenRole['Role']['perm_regexp_access'] == 1 || $chosenRole['Role']['perm_sync'] == 1) {
throw new Exception('You are not authorised to assign that role to a user.');
}
}
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
// reset auth key for a new user
$this->set('authkey', $this->newkey);
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
} else {
$this->newkey = $this->User->generateAuthKey();
$this->set('authkey', $this->newkey);
}
$orgs = $this->User->Organisation->find('list', array(
'conditions' => array('local' => 1),
));
$this->set('orgs', $orgs);
// generate auth key for a new user
$this->loadModel('Server');
$conditions = array();
if (!$this->_isSiteAdmin()) $conditions['Server.org_id LIKE'] = $this->Auth->user('org_id');
$temp = $this->Server->find('all', array('conditions' => $conditions, 'recursive' => -1, 'fields' => array('id', 'name', 'url')));
$servers = array(0 => 'Not bound to a server');
if (!empty($temp)) foreach ($temp as $t) {
if (!empty($t['Server']['name'])) $servers[$t['Server']['id']] = $t['Server']['name'];
else $servers[$t['Server']['id']] = $t['Server']['url'];
}
$this->set('servers', $servers);
$this->set(compact('roles'));
$this->set(compact('syncRoles'));
}
/**
* admin_edit method
*
* @param string $id
* @return void
* @throws NotFoundException
*/
public function admin_edit($id = null) {
$this->set('currentOrg', $this->Auth->User('org_id'));
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$params = null;
$paramsOrgs = null;
if (!$this->_isSiteAdmin()) {
// Org admins should be able to select the role that is already assigned to an org user when editing them.
// What happened previously:
// Org admin edits another org admin of the same org
// Org admin is not allowed to set privileged access roles (site_admin/sync/regex)
// MISP automatically chooses the first available option for the user as the selected setting (usually user)
// Org admin is downgraded to a user
// Now we make an exception for the already assigned role, both in the form and the actual edit.
$userToEdit = $this->User->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1,
'fields' => array('id', 'role_id', 'email'),
));
$allowedRole = $userToEdit['User']['role_id'];
$params = array('conditions' => array(
'OR' => array(
'AND' => array(
'perm_site_admin' => 0, 'perm_sync' => 0, 'perm_regexp_access' => 0
),
'id' => $allowedRole,
)
));
}
$roles = $this->User->Role->find('list', $params);
$syncRoles = $this->User->Role->find('list', array('conditions' => array('perm_sync' => 1), 'recursive' => -1));
$this->set('currentId', $id);
if ($this->request->is('post') || $this->request->is('put')) {
if (!array_key_exists($this->request->data['User']['role_id'], $syncRoles)) $this->request->data['User']['server_id'] = 0;
$fields = array();
foreach (array_keys($this->request->data['User']) as $field) {
if($field != 'password') array_push($fields, $field);
}
// TODO Audit, __extralog, fields get orig
$fieldsOldValues = array();
foreach ($fields as $field) {
if($field != 'confirm_password') array_push($fieldsOldValues, $this->User->field($field));
else array_push($fieldsOldValues, $this->User->field('password'));
}
// TODO Audit, __extralog, fields get orig END
if ("" != $this->request->data['User']['password'])
$fields[] = 'password';
$fields[] = 'role_id';
if (!$this->_isSiteAdmin()) {
$this->loadModel('Role');
$this->Role->recursive = -1;
$chosenRole = $this->Role->findById($this->request->data['User']['role_id']);
if (($chosenRole['Role']['id'] != $allowedRole) && ($chosenRole['Role']['perm_site_admin'] == 1 || $chosenRole['Role']['perm_regexp_access'] == 1 || $chosenRole['Role']['perm_sync'] == 1)) {
throw new Exception('You are not authorised to assign that role to a user.');
}
}
if ($this->User->save($this->request->data, true, $fields)) {
// TODO Audit, __extralog, fields compare
// newValues to array
$fieldsNewValues = array();
foreach ($fields as $field) {
if ($field != 'confirm_password') {
$newValue = $this->data['User'][$field];
if (gettype($newValue) == 'array') {
$newValueStr = '';
$cP = 0;
foreach ($newValue as $newValuePart) {
if ($cP < 2) $newValueStr .= '-' . $newValuePart;
else $newValueStr = $newValuePart . $newValueStr;
$cP++;
}
array_push($fieldsNewValues, $newValueStr);
}
else array_push($fieldsNewValues, $newValue);
}
else array_push($fieldsNewValues, $this->data['User']['password']);
}
// compare
$fieldsResultStr = '';
$c = 0;
foreach ($fields as $field) {
if (isset($fieldsOldValues[$c]) && $fieldsOldValues[$c] != $fieldsNewValues[$c]) {
if($field != 'confirm_password') $fieldsResultStr = $fieldsResultStr . ', ' . $field . ' (' . $fieldsOldValues[$c] . ') => (' . $fieldsNewValues[$c] . ')';
}
$c++;
}
$fieldsResultStr = substr($fieldsResultStr, 2);
$this->__extralog("edit", "user", $fieldsResultStr); // TODO Audit, check: modify User
// TODO Audit, __extralog, fields compare END
$this->Session->setFlash(__('The user has been saved'));
$this->_refreshAuth(); // in case we modify ourselves
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
} else {
$this->User->read(null, $id);
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != $this->User->data['User']['org_id']) $this->redirect(array('controller' => 'users', 'action' => 'index', 'admin' => true));
$this->User->set('password', '');
$this->request->data = $this->User->data; // TODO CHECK
}
if ($this->_isSiteAdmin()) {
$orgs = $this->User->Organisation->find('list', array(
'conditions' => array('local' => 1),
));
}
$this->loadModel('Server');
$conditions = array();
if (!$this->_isSiteAdmin()) $conditions['Server.org_id LIKE'] = $this->Auth->user('org_id');
$temp = $this->Server->find('all', array('conditions' => $conditions, 'recursive' => -1, 'fields' => array('id', 'name', 'url')));
$servers = array(0 => 'Not bound to a server');
foreach ($temp as $t) {
if (!empty($t['Server']['name'])) $servers[$t['Server']['id']] = $t['Server']['name'];
else $servers[$t['Server']['id']] = $t['Server']['url'];
}
$this->set('servers', $servers);
$this->set('orgs', $orgs);
$this->set('id', $id);
$this->set(compact('roles'));
$this->set(compact('syncRoles'));
}
/**
* admin_delete method
*
* @param string $id
* @return void
* @throws MethodNotAllowedException
* @throws NotFoundException
*/
public function admin_delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
if (!$this->_isAdmin()) throw new Exception('Administrators only.');
$this->User->id = $id;
$user = $this->User->read('email', $id);
$fieldsDescrStr = 'User (' . $id . '): ' . $user['User']['email'];
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->User->delete()) {
$this->__extralog("delete", $fieldsDescrStr, ''); // TODO Audit, check: modify User
$this->Session->setFlash(__('User deleted'));
$this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('User was not deleted'));
$this->redirect(array('action' => 'index'));
}
public function login() {
if ($this->Auth->login()) {
$this->__extralog("login"); // TODO Audit, __extralog, check: customLog i.s.o. __extralog, no auth user?: $this->User->customLog('login', $this->Auth->user('id'), array('title' => '','user_id' => $this->Auth->user('id'),'email' => $this->Auth->user('email'),'org' => 'IN2'));
// TODO removed the auto redirect for now, due to security concerns - will look more into this
// $this->redirect($this->Auth->redirectUrl());
$this->redirect(array('controller' => 'events', 'action' => 'index'));
} else {
// don't display authError before first login attempt
if (str_replace("//","/",$this->webroot . $this->Session->read('Auth.redirect')) == $this->webroot && $this->Session->read('Message.auth.message') == $this->Auth->authError) {
$this->Session->delete('Message.auth');
}
// don't display "invalid user" before first login attempt
if($this->request->is('post')) {
$this->Session->setFlash(__('Invalid username or password, try again'));
}
// populate the DB with the first role (site admin) if it's empty
$this->loadModel('Role');
if ($this->Role->find('count') == 0 ) {
$siteAdmin = array('Role' => array(
'id' => 1,
'name' => 'Site Admin',
'permission' => 3,
'perm_add' => 1,
'perm_modify' => 1,
'perm_modify_org' => 1,
'perm_publish' => 1,
'perm_sync' => 1,
'perm_admin' => 1,
'perm_audit' => 1,
'perm_auth' => 1,
'perm_site_admin' => 1,
'perm_regexp_access' => 1,
'perm_sharing_group' => 1,
'perm_template' => 1,
'perm_tagger' => 1,
'perm_site_admin' => 1
));
$this->Role->save($siteAdmin);
}
if ($this->User->Organisation->find('count', array('conditions' => array('Organisation.local' => true))) == 0) {
$org = array('Organisation' => array(
'id' => 1,
'name' => !empty(Configure::read('MISP.org')) ? Configure::read('MISP.org') : 'ADMIN',
'description' => 'Automatically generated admin organisation',
'type' => 'ADMIN',
'uuid' => $this->User->Organisation->generateUuid(),
'local' => 1
));
$this->User->Organisation->save($org);
$org_id = $this->User->Organisation->id;
} else {
$hostOrg = $this->User->Organisation->find('first', array('conditions' => array('Organisation.name' => Configure::read('MISP.org'), 'Organisation.local' => true), 'recursive' => -1));
if (!empty($hostOrg)) $org_id = $hostOrg['Organisation']['id'];
else {
$firstOrg = $this->User->Organisation->find('first', array('conditions' => array('Organisation.local' => true), 'order' => 'Organisation.id ASC'));
$org_id = $firstOrg['Organisation']['id'];
}
}
// populate the DB with the first user if it's empty
if ($this->User->find('count') == 0 ) {
$admin = array('User' => array(
'id' => 1,
'email' => 'admin@admin.test',
'org_id' => $org_id,
'password' => 'admin',
'confirm_password' => 'admin',
'authkey' => $this->User->generateAuthKey(),
'nids_sid' => 4000000,
'newsread' => date('Y-m-d'),
'role_id' => 1,
'change_pw' => 1
));
$this->User->validator()->remove('password'); // password is to simple, remove validation
$this->User->save($admin);
}
}
}
public function routeafterlogin() {
// Terms and Conditions Page
if (!$this->Auth->user('termsaccepted')) {
$this->redirect(array('action' => 'terms'));
}
// Events list
$this->redirect(array('controller' => 'events', 'action' => 'index'));
}
public function logout() {
if ($this->Session->check('Auth.User')) { // TODO session, user is logged in, so ..
$this->__extralog("logout"); // TODO Audit, __extralog, check: customLog i.s.o. __extralog, $this->User->customLog('logout', $this->Auth->user('id'), array());
}
$this->Session->setFlash(__('Good-Bye'));
$this->redirect($this->Auth->logout());
}
public function resetauthkey($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid id for user', true), 'default', array(), 'error');
$this->redirect(array('action' => 'view', $this->Auth->user('id')));
}
// reset the key
$this->User->id = $id;
if (!$this->User->exists($id)) {
$this->Session->setFlash(__('Invalid id for user', true), 'default', array(), 'error');
$this->redirect(array('action' => 'view', $this->Auth->user('id')));
}
$user = $this->User->read();
$oldKey = $this->User->data['User']['authkey'];
if ('me' == $id ) $id = $this->Auth->user('id');
else if (!$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $this->User->data('org_id')) && ($this->Auth->user('id') != $id)) throw new MethodNotAllowedException();
$newkey = $this->User->generateAuthKey();
$this->User->saveField('authkey', $newkey);
$this->__extralog(
'reset_auth_key',
'Authentication key for user ' . $user['User']['id'] . ' (' . $user['User']['email'] . ')',
$fieldsResult = 'authkey(' . $oldKey . ') => (' . $newkey . ')'
);
$this->Session->setFlash(__('New authkey generated.', true));
$this->_refreshAuth();
$this->redirect($this->referer());
}
public function memberslist() {
// Orglist
$fields = array('Organisation.name', 'count(User.id) as `num_members`');
$params = array('recursive' => 0,
'fields' => $fields,
'recursive' => -1,
'contain' => array('Organisation'),
'group' => array('Organisation.name'),
'order' => array('UPPER(Organisation.name)'),
);
$orgs = $this->User->find('all', $params);
$this->set('orgs', $orgs);
}
public function histogram($selected = null) {
if (!$this->request->is('ajax')) throw new MethodNotAllowedException('This function can only be accessed via AJAX.');
if ($selected == '[]') $selected = null;
$selectedTypes = array();
if ($selected) $selectedTypes = json_decode($selected);
$temp = $this->User->Event->find('all', array(
'recursive' => -1,
'fields' => array('distinct(orgc_id)'),
'contain' => array('Orgc' => array('fields' => array('Orgc.name'))),
));
$orgs = array();
foreach ($temp as $t) {
$orgs[$t['Event']['orgc_id']] = $t['Orgc']['name'];
}
// What org posted what type of attribute
$this->loadModel('Attribute');
$conditions = array();
if ($selected) $conditions[] = array('Attribute.type' => $selectedTypes);
$fields = array('Event.orgc_id', 'Attribute.type', 'count(Attribute.type) as `num_types`');
$params = array('recursive' => 0,
'fields' => $fields,
'group' => array('Attribute.type', 'Event.orgc_id'),
'order' => array('Event.orgc_id', 'num_types DESC'),
'conditions' => $conditions,
);
$temp = $this->Attribute->find('all', $params);
$data = array();
foreach ($orgs as $k => $org) {
$data[$org]['total'] = 0;
$data[$org]['data'] = array();
foreach ($temp as $t) {
if ($t['Event']['orgc_id'] == $k) {
$data[$org]['data'][$t['Attribute']['type']] = $t[0]['num_types'];
}
}
}
$max = 1;
foreach ($data as &$d) {
foreach ($d['data'] as $t) {
$d['total'] += $t;
}
if ($d['total'] > $max) $max = $d['total'];
}
$this->set('data', $data);
$this->set('max', $max);
$this->set('selectedTypes', $selectedTypes);
// Nice graphical histogram
$sigTypes = array_keys($this->Attribute->typeDefinitions);
App::uses('ColourPaletteTool', 'Tools');
$paletteTool = new ColourPaletteTool();
$colours = $paletteTool->createColourPalette(count($sigTypes));
$typeDb = array();
foreach($sigTypes as $k => $type) {
$typeDb[$type] = $colours[$k];
}
$this->set('typeDb', $typeDb);
$this->set('sigTypes', $sigTypes);
$graphInterval = $this->_getIntervals($max);
$this->layout = 'ajax';
}
private function _getIntervals($max) {
$intervals = array();
if ($max > 5) {
$maxDecimals = strlen((string) $max);
//$graphInterval = $max / 10;
$graphInterval = round($max, -($maxDecimals-2), PHP_ROUND_HALF_DOWN);
$graphInterval = round($graphInterval / 5);
for ($i=0; $i<$max; $i+=$graphInterval) {
$intervals[] = $i;
}
} else {
for ($i=0; $i<$max; $i++) $intervals[] = $i;
}
return $intervals;
}
private function _generateColours($count){
$pallette = 16777216;
$array = array();
$interval = ceil($pallette / $count);
$colours = array();
for ($i = 0; $i < $count; $i++) {
$temp = $i * $interval;
$array[$i] = $temp;
$colours[$i] = $this->_convertToHex($temp);
}
return $colours;
}
private function _convertToHex($int) {
$hex = strval(dechex($int));
$filler = '';
for ($i = 0; $i < 6 - (strlen($hex)); $i++) $filler .= '0';
$filler = '#' . $filler . $hex;
return $filler;
}
public function terms() {
if ($this->request->is('post') || $this->request->is('put')) {
$this->User->id = $this->Auth->user('id');
$this->User->saveField('termsaccepted', true);
$this->_refreshAuth(); // refresh auth info
$this->Session->setFlash(__('You accepted the Terms and Conditions.'));
$this->redirect(array('action' => 'routeafterlogin'));
}
$this->set('termsaccepted', $this->Auth->user('termsaccepted'));
}
public function downloadTerms() {
if (!Configure::read('MISP.terms_file')) {
$termsFile = APP ."View/Users/terms";
} else {
$termsFile = APP . 'files' . DS . 'terms' . DS . Configure::read('MISP.terms_file');
}
$this->response->file($termsFile, array('download' => true, 'name' => Configure::read('MISP.terms_file')));
return $this->response;
}
private function __extralog($action = null, $description = null, $fieldsResult = null) { // TODO move audit to AuditsController?
// new data
$userId = $this->Auth->user('id');
$model = 'User';
$modelId = $this->Auth->user('id');
if ($action == 'login') {
$description = "User (" . $this->Auth->user('id') . "): " . $this->data['User']['email'];
} elseif ($action == 'logout') {
$description = "User (" . $this->Auth->user('id') . "): " . $this->Auth->user('email');
} elseif ($action == 'edit') {
$description = "User (" . $this->User->id . "): " . $this->data['User']['email'];
} elseif ($action == 'change_pw') {
$description = "User (" . $this->User->id . "): " . $this->data['User']['email'];
$fieldsResult = "Password changed.";
}
// query
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => $model,
'model_id' => $modelId,
'email' => $this->Auth->user('email'),
'action' => $action,
'title' => $description,
'change' => isset($fieldsResult) ? $fieldsResult : ''));
// write to syslogd as well
App::import('Lib', 'SysLog.SysLog');
$syslog = new SysLog();
if (isset($fieldsResult) && $fieldsResult) $syslog->write('notice', $description . ' -- ' . $action . ' -- ' . $fieldsResult);
else $syslog->write('notice', $description . ' -- ' . $action);
}
/**
* Used for fields_before and fields for audit
*
* @param $array
*/
public function arrayCopy(array $array) {
$result = array();
foreach ($array as $key => $val) {
if (is_array( $val)) {
$result[$key] = arrayCopy($val);
} elseif (is_object($val)) {
$result[$key] = clone $val;
} else {
$result[$key] = $val;
}
}
return $result;
}
/**
* @throws NotFoundException
**/
public function checkAndCorrectPgps() {
if (!self::_isAdmin()) throw new NotFoundException();
$this->set('fails', $this->User->checkAndCorrectPgps());
}
public function admin_email() {
if (!$this->_isAdmin()) throw new MethodNotAllowedException();
// User has filled in his contact form, send out the email.
if ($this->request->is('post') || $this->request->is('put')) {
$conditions = array();
if (!$this->_isSiteAdmin()) $conditions = array('org_id' => $this->Auth->user('org_id'));
if ($this->request->data['User']['recipient'] != 1) $conditions['id'] = $this->request->data['User']['recipientEmailList'];
$users = $this->User->find('all', array('recursive' => -1, 'order' => array('email ASC'), 'conditions' => $conditions));
$this->request->data['User']['message'] = $this->User->adminMessageResolve($this->request->data['User']['message']);
$failures = '';
foreach ($users as $user) {
$password = $this->User->generateRandomPassword();
$body = str_replace('$password', $password, $this->request->data['User']['message']);
$body = str_replace('$username', $user['User']['email'], $body);
$result = $this->User->sendEmail($user, $body, false, $this->request->data['User']['subject']);
// if sending successful and action was a password change, update the user's password.
if ($result && $this->request->data['User']['action'] != '0') {
$this->User->id = $user['User']['id'];
$this->User->saveField('password', $password);
$this->User->saveField('change_pw', '1');
}
if (!$result) {
if ($failures != '') $failures .= ', ';
$failures .= $user['User']['email'];
}
}
if ($failures != '') $this->Session->setFlash(__('E-mails sent, but failed to deliver the messages to the following recipients: ' . $failures));
else $this->Session->setFlash(__('E-mails sent.'));
}
$conditions = array();
if (!$this->_isSiteAdmin()) $conditions = array('org_id' => $this->Auth->user('org_id'));
$temp = $this->User->find('all', array('recursive' => -1, 'fields' => array('id', 'email'), 'order' => array('email ASC'), 'conditions' => $conditions));
$emails = array();
$gpgKeys = array();
// save all the emails of the users and set it for the dropdown list in the form
foreach ($temp as $user) {
$emails[$user['User']['id']] = $user['User']['email'];
}
$this->set('users', $temp);
$this->set('recipientEmail', $emails);
$this->set('org', Configure::read('MISP.org'));
$textsToFetch = array('newUserText', 'passwordResetText');
$this->loadModel('Server');
foreach ($textsToFetch as $text) {
${$text} = Configure::read('MISP.' . $text);
if (!${$text}) ${$text} = $this->Server->serverSettings['MISP'][$text]['value'];
$this->set($text, ${$text});
}
}
public function initiatePasswordReset($id, $firstTime = false) {
if (!$this->_isAdmin()) throw new MethodNotAllowedException('You are not authorised to do that.');
$user = $this->User->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1
));
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != $user['User']['org_id']) throw new MethodNotAllowedException('You are not authorised to do that.');
if ($this->request->is('post')) {
if (isset($this->request->data['User']['firstTime'])) $firstTime = $this->request->data['User']['firstTime'];
$org = Configure::read('MISP.org');
$options = array('passwordResetText', 'newUserText');
$subjects = array('[' . $org . ' MISP] New user registration', '[' . $org . ' MISP] Password reset');
$textToFetch = $options[($firstTime ? 0 : 1)];
$subject = $subjects[($firstTime ? 0 : 1)];
$this->loadModel('Server');
$body = Configure::read('MISP.' . $textToFetch);
if (!$body) $body = $this->Server->serverSettings['MISP'][$textToFetch]['value'];
$body = $this->User->adminMessageResolve($body);
$password = $this->User->generateRandomPassword();
$body = str_replace('$password', $password, $body);
$body = str_replace('$username', $user['User']['email'], $body);
$result = $this->User->sendEmail($user, $body, false, $subject);
if ($result) {
$this->User->id = $user['User']['id'];
$this->User->saveField('password', $password);
$this->User->saveField('change_pw', '1');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'New credentials sent.')),'status'=>200));
}
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'There was an error notifying the user. His/her credentials were not altered.')),'status'=>200));
} else {
$this->layout = 'ajax';
$this->set('user', $user);
$this->set('firstTime', $firstTime);
$this->render('ajax/passwordResetConfirmationForm');
}
}
// shows some statistics about the instance
public function statistics() {
// set all of the data up for the heatmaps
$orgs = $this->User->Organisation->find('all', array('fields' => array('DISTINCT (name) AS name'), 'recursive' => -1));
$this->loadModel('Log');
$year = date('Y');
$month = date('n');
$day = date('j');
$month = $month - 5;
if ($month < 1) {
$year--;
$month = 12 + $month;
}
// Some additional satistics
$this_month = strtotime('first day of this month');
$stats[0] = $this->User->Event->find('count', null);
$stats[1] = $this->User->Event->find('count', array('conditions' => array('Event.timestamp >' => $this_month)));
$stats[2] = $this->User->Event->Attribute->find('count', null);
$stats[3] = $this->User->Event->Attribute->find('count', array('conditions' => array('Attribute.timestamp >' => $this_month)));
$this->loadModel('Correlation');
$this->Correlation->recursive = -1;
$stats[4] = $this->Correlation->find('count', null);
$stats[4] = $stats[4] / 2;
$stats[5] = $this->User->Event->ShadowAttribute->find('count', null);
$stats[6] = $this->User->find('count', null);
$stats[7] = count($orgs);
$this->loadModel('Thread');
$stats[8] = $this->Thread->find('count', array('conditions' => array('Thread.post_count >' => 0)));
$stats[9] = $this->Thread->find('count', array('conditions' => array('Thread.date_created >' => date("Y-m-d H:i:s",$this_month), 'Thread.post_count >' => 0)));
$stats[10] = $this->Thread->Post->find('count', null);
$stats[11] = $this->Thread->Post->find('count', array('conditions' => array('Post.date_created >' => date("Y-m-d H:i:s",$this_month))));
$this->set('stats', $stats);
$this->set('orgs', $orgs);
$this->set('start', strtotime(date('Y-m-d H:i:s') . ' -5 months'));
$this->set('end', strtotime(date('Y-m-d H:i:s')));
$this->set('startDateCal', $year . ', ' . $month . ', 01');
$range = '[5, 10, 50, 100]';
$this->set('range', $range);
}
public function verifyGPG() {
if (!self::_isSiteAdmin()) throw new NotFoundException();
$user_results = $this->User->verifyGPG();
$this->set('users', $user_results);
}
/**
* Refreshes the Auth session with new/updated data
* @return void
*/
protected function _refreshAuth() {
$oldUser = $this->Auth->user();
$newUser = $this->User->find('first', array('conditions' => array('User.id' => $oldUser['id']), 'recursive' => -1,'contain' => array('Organisation', 'Role')));
// Rearrange it a bit to match the Auth object created during the login
$newUser['User']['Role'] = $newUser['Role'];
$newUser['User']['Organisation'] = $newUser['Organisation'];
unset($newUser['Organisation'], $newUser['Role']);
$this->Auth->login($newUser['User']);
}
public function fetchPGPKey($email) {
if (!$this->_isAdmin()) throw new Exception('Administrators only.');
$keys = $this->User->fetchPGPKey($email);
if (is_numeric($keys)) {
throw new NotFoundException('Could not retrieved any keys from the key server.');
}
$this->set('keys', $keys);
$this->autorender = false;
$this->layout = false;
$this->render('ajax/fetchpgpkey');
}
}