Merge remote-tracking branch 'origin/2.4' into decaying

pull/5032/head
mokaddem 2019-09-10 15:40:25 +02:00
commit f3860ade80
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
16 changed files with 478 additions and 120 deletions

11
.gitmodules vendored
View File

@ -37,9 +37,12 @@
path = Plugin/DebugKit
url = https://github.com/cakephp/debug_kit.git
branch = 2.2
[submodule "INSTALL/dependencies/Net_GeoIP"]
path = INSTALL/dependencies/Net_GeoIP
url = https://github.com/pear/Net_GeoIP
[submodule "INSTALL/Crypt_GPG"]
path = INSTALL/dependencies/Crypt_GPG
url = https://github.com/pear/Crypt_GPG
[submodule "INSTALL/Console_CommandLine"]
path = INSTALL/dependencies/Console_CommandLine
url = https://github.com/pear/Console_CommandLine
[submodule "app/files/misp-decaying-models"]
path = app/files/misp-decaying-models
url = https://github.com/MISP/misp-decaying-models.git
url = https://github.com/MISP/misp-decaying-models.git

@ -1 +0,0 @@
Subproject commit 5ccc654f03086febbec95e3358b7bae80ca9af6f

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":114}
{"major":2, "minor":4, "hotfix":115}

View File

@ -506,4 +506,30 @@ class AdminShell extends AppShell
$this->Server->cleanCacheFiles();
echo '...caches lost in time, like tears in rain.' . PHP_EOL;
}
public function resetSyncAuthkeys()
{
if (empty($this->args[0])) {
echo sprintf(
__("MISP mass sync authkey reset command line tool.\n\nUsage: %sConsole/cake resetSyncAuthkeys [user_id]") . "\n\n",
APP
);
die();
} else {
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
if (empty($user)) {
echo __('Invalid user.') . "\n\n";
}
if (!$user['Role']['perm_site_admin']) {
echo __('User has to be a site admin.') . "\n\n";
}
if (!empty($this->args[1])) {
$jobId = $this->args[1];
} else {
$jobId = false;
}
$this->User->resetAllSyncAuthKeys($user, $jobId);
}
}
}

View File

@ -260,19 +260,24 @@ class AppController extends Controller
} else {
// User not authenticated correctly
// reset the session information
$this->Session->destroy();
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$log = array(
'org' => 'SYSTEM',
'model' => 'User',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'auth_fail',
'title' => 'Failed authentication using API key (' . trim($auth_key) . ')',
'change' => null,
);
$this->Log->save($log);
$redis = $this->{$this->modelClass}->setupRedis();
if ($redis && !$redis->exists('misp:auth_fail_throttling:' . trim($auth_key))) {
$redis->set('misp:auth_fail_throttling:' . trim($auth_key), 1);
$redis->expire('misp:auth_fail_throttling:' . trim($auth_key), 3600);
$this->Session->destroy();
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$log = array(
'org' => 'SYSTEM',
'model' => 'User',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'auth_fail',
'title' => 'Failed authentication using API key (' . trim($auth_key) . ')',
'change' => null,
);
$this->Log->save($log);
}
throw new ForbiddenException('Authentication failed. Please make sure you pass the API key of an API enabled user along in the Authorization header.');
}
unset($user);
@ -538,7 +543,7 @@ class AppController extends Controller
return $name;
}
public function blackhole($type)
public function blackhole($type=false)
{
if ($type === 'csrf') {
throw new BadRequestException($type);

View File

@ -357,7 +357,7 @@ class ACLComponent extends Component
),
'servers' => array(
'add' => array(),
'cache' => array('perm_site_admin'),
'cache' => array(),
'checkout' => array(),
'createSync' => array('perm_sync'),
'delete' => array(),
@ -370,12 +370,12 @@ class ACLComponent extends Component
'getInstanceUUID' => array('perm_sync'),
'getPyMISPVersion' => array('*'),
'getSetting' => array(),
'getSubmodulesStatus' => array('perm_site_admin'),
'getSubmoduleQuickUpdateForm' => array('perm_site_admin'),
'getSubmodulesStatus' => array(),
'getSubmoduleQuickUpdateForm' => array(),
'getWorkers' => array(),
'getVersion' => array('*'),
'import' => ('perm_site_admin'),
'index' => array('OR' => array('perm_sync', 'perm_admin')),
'import' => array(),
'index' => array(),
'ondemandAction' => array(),
'postTest' => array('perm_sync'),
'previewEvent' => array(),
@ -383,6 +383,7 @@ class ACLComponent extends Component
'pull' => array(),
'purgeSessions' => array(),
'push' => array(),
'resetRemoteAuthKey' => array(),
'rest' => array('perm_auth'),
'restartWorkers' => array(),
'serverSettings' => array(),
@ -393,7 +394,7 @@ class ACLComponent extends Component
'statusZeroMQServer' => array(),
'stopWorker' => array(),
'stopZeroMQServer' => array(),
'testConnection' => array('perm_sync'),
'testConnection' => array(),
'update' => array(),
'updateJSON' => array(),
'updateProgress' => array(),
@ -525,7 +526,6 @@ class ACLComponent extends Component
'admin_index' => array('perm_admin'),
'admin_quickEmail' => array('perm_admin'),
'admin_view' => array('perm_admin'),
'arrayCopy' => array(),
'attributehistogram' => array('*'),
'change_pw' => array('*'),
'checkAndCorrectPgps' => array(),
@ -540,6 +540,7 @@ class ACLComponent extends Component
'initiatePasswordReset' => array('perm_admin'),
'login' => array('*'),
'logout' => array('*'),
'resetAllSyncAuthKeys' => array(),
'resetauthkey' => array('*'),
'request_API' => array('*'),
'routeafterlogin' => array('*'),
@ -575,6 +576,78 @@ class ACLComponent extends Component
)
);
private function __checkLoggedActions($user, $controller, $action)
{
$loggedActions = array(
'servers' => array(
'index' => array(
'role' => array(
'NOT' => array(
'perm_site_admin'
)
),
'message' => __('This could be an indication of an attempted privilege escalation on older vulnerable versions of MISP (<2.4.115)')
)
)
);
foreach ($loggedActions as $k => $v) {
$loggedActions[$k] = array_change_key_case($v);
}
$message = '';
if (!empty($loggedActions[$controller])) {
if (!empty($loggedActions[$controller][$action])) {
$message = $loggedActions[$controller][$action]['message'];
$hit = false;
if (empty($loggedActions[$controller][$action]['role'])) {
$hit = true;
} else {
$role_req = $loggedActions[$controller][$action]['role'];
if (empty($role_req['OR']) && empty($role_req['AND']) && empty($role_req['NOT'])) {
$role_req = array('OR' => $role_req);
}
if (!empty($role_req['NOT'])) {
foreach ($role_req['NOT'] as $k => $v) {
if (!$user['Role'][$v]) {
$hit = true;
continue;
}
}
}
if (!$hit && !empty($role_req['AND'])) {
$subhit = true;
foreach ($role_req['AND'] as $k => $v) {
$subhit = $subhit && $user['Role'][$v];
}
if ($subhit) {
$hit = true;
}
}
if (!$hit && !empty($role_req['OR'])) {
foreach ($role_req['OR'] as $k => $v) {
if ($user['Role'][$v]) {
$hit = true;
continue;
}
}
}
if ($hit) {
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'User',
'model_id' => $user['id'],
'email' => $user['email'],
'action' => 'security',
'user_id' => $user['id'],
'title' => __('User triggered security alert by attempting to access /%s/%s. Reason why this endpoint is of interest: %s', $controller, $action, $message),
));
}
}
}
}
}
// The check works like this:
// If the user is a site admin, return true
// If the requested action has an OR-d list, iterate through the list. If any of the permissions are set for the user, return true
@ -589,6 +662,7 @@ class ACLComponent extends Component
foreach ($aclList as $k => $v) {
$aclList[$k] = array_change_key_case($v);
}
$this->__checkLoggedActions($user, $controller, $action);
if ($user['Role']['perm_site_admin']) {
return true;
}

View File

@ -44,12 +44,6 @@ class ServersController extends AppController
public function index()
{
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_sync'] && !$this->userRole['perm_admin']) {
$this->redirect(array('controller' => 'events', 'action' => 'index'));
}
$this->paginate['conditions'] = array('Server.org_id LIKE' => $this->Auth->user('org_id'));
}
if ($this->_isRest()) {
$params = array(
'recursive' => -1,
@ -2089,4 +2083,28 @@ misp.direct_call(relative_path, body)
}
}
}
public function resetRemoteAuthKey($id)
{
if (!$this->request->is('post')) {
throw new MethodNotAllowedException(__('This endpoint expects POST requests.'));
}
$result = $this->Server->resetRemoteAuthkey($id);
if ($result !== true) {
if (!$this->_isRest()) {
$this->Flash->error($result);
$this->redirect(array('action' => 'index'));
} else {
return $this->RestResponse->saveFailResponse('Servers', 'resetRemoteAuthKey', $id, $message, $this->response->type());
}
} else {
$message = __('API key updated.');
if (!$this->_isRest()) {
$this->Flash->success($message);
$this->redirect(array('action' => 'index'));
} else {
return $this->RestResponse->saveSuccessResponse('Servers', 'resetRemoteAuthKey', $message, $this->response->type());
}
}
}
}

View File

@ -211,7 +211,7 @@ class UsersController extends AppController
// Save the data
if ($this->User->save($user)) {
$message = __('Password Changed.');
$this->__extralog("change_pw");
$this->User->extralog($this->Auth->user(), "change_pw", null, null, $user);
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('User', 'change_pw', false, $this->response->type(), $message);
}
@ -869,12 +869,12 @@ class UsersController extends AppController
$c++;
}
$fieldsResultStr = substr($fieldsResultStr, 2);
$this->__extralog("edit", "user", $fieldsResultStr);
$user = $this->User->find('first', array(
'recursive' => -1,
'conditions' => array('User.id' => $this->User->id)
));
$this->User->extralog($this->Auth->user(), "edit", "user", $fieldsResultStr, $user);
if ($this->_isRest()) {
$user = $this->User->find('first', array(
'conditions' => array('User.id' => $this->User->id),
'recursive' => -1
));
$user['User']['password'] = '******';
return $this->RestResponse->viewData($user, $this->response->type());
} else {
@ -954,7 +954,7 @@ class UsersController extends AppController
}
$fieldsDescrStr = 'User (' . $id . '): ' . $user['User']['email'];
if ($this->User->delete($id)) {
$this->__extralog("delete", $fieldsDescrStr, '');
$this->User->extralog($this->Auth->user(), "delete", $fieldsDescrStr, '');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('User', 'admin_delete', $id, $this->response->type(), 'User deleted.');
} else {
@ -1010,7 +1010,7 @@ class UsersController extends AppController
}
}
if ($this->Auth->login()) {
$this->__extralog("login");
$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(
@ -1125,7 +1125,7 @@ class UsersController extends AppController
public function logout()
{
if ($this->Session->check('Auth.User')) {
$this->__extralog("logout");
$this->User->extralog($this->Auth->user(), "logout");
}
$this->Flash->info(__('Good-Bye'));
$user = $this->User->find('first', array(
@ -1140,7 +1140,7 @@ class UsersController extends AppController
$this->redirect($this->Auth->logout());
}
public function resetauthkey($id = null)
public function resetauthkey($id = null, $alert = false)
{
if (!$this->_isAdmin() && Configure::read('MISP.disableUserSelfManagement')) {
throw new MethodNotAllowedException('User self-management has been disabled on this instance.');
@ -1149,24 +1149,12 @@ class UsersController extends AppController
$id = $this->Auth->user('id');
}
if (!$this->userRole['perm_auth']) {
throw new MethodNotAllowedException('Invalid action.');
throw new MethodNotAllowedException(__('Invalid action.'));
}
$this->User->id = $id;
if (!$id || !$this->User->exists($id)) {
throw new MethodNotAllowedException('Invalid user.');
$newkey = $this->User->resetauthkey($this->Auth->user(), $id, $alert);
if ($newkey === false) {
throw new MethodNotAllowedException(__('Invalid user.'));
}
$user = $this->User->read();
$oldKey = $this->User->data['User']['authkey'];
if (!$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $this->User->data['User']['org_id']) && ($this->Auth->user('id') != $id)) {
throw new MethodNotAllowedException('Invalid user.');
}
$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 . ')'
);
if (!$this->_isRest()) {
$this->Flash->success(__('New authkey generated.', true));
$this->_refreshAuth();
@ -1176,6 +1164,25 @@ class UsersController extends AppController
}
}
public function resetAllSyncAuthKeys()
{
if (!$this->request->is('post')) {
throw new MethodNotAllowedException(__('This functionality is only accessible via POST requests.'));
}
$results = $this->User->resetAllSyncAuthKeysRouter($this->Auth->user());
if ($results === true) {
$message = __('Job initiated.');
} else {
$message = __('%s authkeys reset, %s could not be reset.', $results['success'], $results['fails']);
}
if (!$this->_isRest()) {
$this->Flash->info($message);
$this->redirect($this->referer());
} else {
return $this->RestResponse->saveSuccessResponse('User', 'resetAllSyncAuthKeys', false, $this->response->type(), $message);
}
}
public function histogram($selected = null)
{
//if (!$this->request->is('ajax') && !$this->_isRest()) throw new MethodNotAllowedException('This function can only be accessed via AJAX or the API.');
@ -1297,60 +1304,6 @@ class UsersController extends AppController
return $this->response;
}
private function __extralog($action = null, $description = null, $fieldsResult = null)
{
// new data
$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->Auth->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
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;
}
public function checkAndCorrectPgps()
{
if (!self::_isAdmin()) {

View File

@ -461,7 +461,7 @@ class Feed extends AppModel
$result = array(
'header' => array(
'Accept' => 'application/json',
'Accept' => array('application/json', 'text/plain'),
'Content-Type' => 'application/json',
'MISP-version' => $version,
'MISP-uuid' => Configure::read('MISP.uuid')

View File

@ -48,6 +48,7 @@ class Log extends AppModel
'request',
'request_delegation',
'reset_auth_key',
'security',
'serverSettingsEdit',
'tag',
'undelete',

View File

@ -2289,10 +2289,10 @@ class Server extends AppModel
if (!$existingEvent) {
// add data for newly imported events
$result = $eventModel->_add($event, true, $user, $server['Server']['org_id'], $passAlong, true, $jobId);
if ($result === true) {
if ($result) {
$successes[] = $eventId;
} else {
$fails[$eventId] = __('Failed (partially?) because of errors: ') . $result;
$fails[$eventId] = __('Failed (partially?) because of validation errors: ') . json_encode($eventModel->validationErrors, true);
}
} else {
if (!$existingEvent['Event']['locked'] && !$server['Server']['internal']) {
@ -2316,6 +2316,7 @@ class Server extends AppModel
$eventId,
$server
);
;
if (!empty($event)) {
if ($this->__checkIfEventIsBlockedBeforePull($event)) {
return false;
@ -2328,7 +2329,7 @@ class Server extends AppModel
}
} else {
// error
$fails[$eventId] = __('failed downloading the event') . ': ' . json_encode($event);
$fails[$eventId] = __('failed downloading the event');
}
return true;
}
@ -3984,6 +3985,9 @@ class Server extends AppModel
public function runPOSTtest($id)
{
$server = $this->find('first', array('conditions' => array('Server.id' => $id)));
if (empty($server)) {
throw new InvalidArgumentException(__('Invalid server.'));
}
$HttpSocket = $this->setupHttpSocket($server);
$request = $this->setupSyncRequest($server);
$testFile = file_get_contents(APP . 'files/scripts/test_payload.txt');
@ -3991,6 +3995,7 @@ class Server extends AppModel
$this->Log = ClassRegistry::init('Log');
try {
$response = $HttpSocket->post($uri, json_encode(array('testString' => $testFile)), $request);
$rawBody = $response->body;
$response = json_decode($response, true);
} catch (Exception $e) {
$this->Log->create();
@ -4006,7 +4011,14 @@ class Server extends AppModel
return 8;
}
if (!isset($response['body']['testString']) || $response['body']['testString'] !== $testFile) {
$responseString = isset($response['body']['testString']) ? $response['body']['testString'] : 'Response was empty.';
$responseString = '';
if (!empty($repsonse['body']['testString'])) {
$responseString = $response['body']['testString'];
} else if (!empty($rawBody)){
$responseString = $rawBody;
} else {
$responseString = __('Response was empty.');
}
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
@ -5197,4 +5209,65 @@ class Server extends AppModel
}
return $results;
}
public function resetRemoteAuthKey($id)
{
$server = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Server.id' => $id)
));
if (empty($server)) {
return __('Invalid server');
}
$HttpSocket = $this->setupHttpSocket($server);
$request = $this->setupSyncRequest($server);
$uri = $server['Server']['url'] . '/users/resetauthkey/me';
try {
$response = $HttpSocket->post($uri, '{}', $request);
} catch (Exception $e) {
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$message = 'Could not reset the remote authentication key.';
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => $id,
'email' => 'SYSTEM',
'action' => 'error',
'user_id' => 0,
'title' => 'Error: ' . $message,
));
return $message;
}
if ($response->isOk()) {
try {
$response = json_decode($response->body, true);
} catch (Exception $e) {
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$message = 'Invalid response received from the remote instance.';
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => $id,
'email' => 'SYSTEM',
'action' => 'error',
'user_id' => 0,
'title' => 'Error: ' . $message,
));
return $message;
}
if (!empty($response['message'])) {
$authkey = $response['message'];
}
if (substr($authkey, 0, 17) === 'Authkey updated: ') {
$authkey = substr($authkey, 17, 57);
}
$server['Server']['authkey'] = $authkey;
$this->save($server);
return true;
} else {
return __('Could not reset the remote authentication key.');
}
}
}

View File

@ -1251,6 +1251,176 @@ class User extends AppModel
return $authKey;
}
public function resetAllSyncAuthKeysRouter($user, $jobId = false)
{
if (Configure::read('MISP.background_jobs')) {
$job = ClassRegistry::init('Job');
$job->create();
$eventModel = ClassRegistry::init('Event');
$data = array(
'worker' => $eventModel->__getPrioWorkerIfPossible(),
'job_type' => __('reset_all_sync_api_keys'),
'job_input' => __('Reseting all API keys'),
'status' => 0,
'retries' => 0,
'org_id' => $user['org_id'],
'org' => $user['Organisation']['name'],
'message' => 'Issuing new API keys to all sync users.',
);
$job->save($data);
$jobId = $job->id;
$process_id = CakeResque::enqueue(
'prio',
'AdminShell',
array('resetSyncAuthkeys', $user['id'], $jobId),
true
);
$job->saveField('process_id', $process_id);
return true;
} else {
return $this->resetAllSyncAuthKeys($user);
}
}
public function resetAllSyncAuthKeys($user, $jobId = false)
{
$affected_users = $this->find('all', array(
'recursive' => -1,
'contain' => array('Role'),
'conditions' => array(
'OR' => array(
'Role.perm_sync' => 1,
'Role.perm_admin' => 1
),
'Role.perm_site_admin' => 0
)
));
$results = array('success' => 0, 'fails' => 0);
$user_count = count($affected_users);
if ($jobId) {
$job = ClassRegistry::init('Job');
$existingJob = $job->find('first', array(
'conditions' => array('Job.id' => $jobId),
'recursive' => -1
));
if (empty($existingJob)) {
$jobId = false;
}
}
foreach ($affected_users as $k => $affected_user) {
try {
$reset_result = $this->resetauthkey($user, $affected_user['User']['id'], true);
if ($reset_result) {
$results['success'] += 1;
} else {
$results['fails'] += 1;
}
} catch (Exception $e) {
$results['fails'] += 1;
}
if ($jobId) {
if ($k % 100 == 0) {
$job->id = $jobId;
$job->saveField('progress', 100 * (($k + 1) / count($user_count)));
$job->saveField('message', __('Reset in progress - %s/%s.', $k, $user_count));
}
}
}
if ($jobId) {
$message = __('%s authkeys reset, %s could not be reset', $results['success'], $results['fails']);
$job->saveField('progress', 100);
$job->saveField('message', $message);
$job->saveField('status', 4);
}
return $results;
}
public function resetauthkey($user, $id, $alert = false)
{
$this->id = $id;
if (!$id || !$this->exists($id)) {
return false;
}
$updatedUser = $this->read();
$oldKey = $this->data['User']['authkey'];
if (empty($user['Role']['perm_site_admin']) && !($user['Role']['perm_admin'] && $user['org_id'] == $updatedUser['User']['org_id']) && ($user['id'] != $id)) {
return false;
}
$newkey = $this->generateAuthKey();
$this->saveField('authkey', $newkey);
$this->extralog(
$user,
'reset_auth_key',
sprintf(
__('Authentication key for user %s (%s) updated.'),
$updatedUser['User']['id'],
$updatedUser['User']['email']
),
$fieldsResult = 'authkey(' . $oldKey . ') => (' . $newkey . ')',
$updatedUser
);
if ($alert) {
$baseurl = Configure::read('MISP.external_baseurl');
if (empty($baseurl)) {
$baseurl = Configure::read('MISP.baseurl');
}
$body = __(
"Dear user,\n\nan API key reset has been triggered by an administrator for your user account on %s.\n\nYour new API key is: %s\n\nPlease update your server's sync setup to reflect this change.\n\nWe apologise for the inconvenience.",
$baseurl,
$newkey
);
$bodyNoEnc = __(
"Dear user,\n\nan API key reset has been triggered by an administrator for your user account on %s.\n\nYour new API key can be retrieved by logging in using this sync user's account.\n\nPlease update your server's sync setup to reflect this change.\n\nWe apologise for the inconvenience.",
$baseurl,
$newkey
);
$this->sendEmail(
$updatedUser,
$body,
$bodyNoEnc,
__('API key reset by administrator')
);
}
return $newkey;
}
public function extralog($user, $action = null, $description = null, $fieldsResult = null, $modifiedUser = null)
{
// new data
$model = 'User';
$modelId = $user['id'];
if (!empty($modifiedUser)) {
$modelId = $modifiedUser['User']['id'];
}
if ($action == 'login') {
$description = "User (" . $user['id'] . "): " . $user['email'];
} elseif ($action == 'logout') {
$description = "User (" . $user['id'] . "): " . $user['email'];
} elseif ($action == 'edit') {
$description = "User (" . $modifiedUser['User']['id'] . "): " . $modifiedUser['User']['email'];
} elseif ($action == 'change_pw') {
$description = "User (" . $modifiedUser['User']['id'] . "): " . $modifiedUser['User']['email'];
$fieldsResult = "Password changed.";
}
// query
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => $user['Organisation']['name'],
'model' => $model,
'model_id' => $modelId,
'email' => $user['email'],
'action' => $action,
'title' => $description,
'change' => isset($fieldsResult) ? $fieldsResult : ''));
// write to syslogd as well
App::import('Lib', 'SysLog.SysLog');
$syslog = new SysLog();
$syslog->write('notice', $description . ' -- ' . $action . (empty($fieldResult) ? '' : '-- ' . $fieldResult));
}
/**
* @return Crypt_GPG
* @throws Exception

View File

@ -21,6 +21,7 @@
<th><?php echo $this->Paginator->sort('id');?></th>
<th><?php echo $this->Paginator->sort('name');?></th>
<th><?php echo __('Connection test');?></th>
<th><?php echo __('Reset API key');?></th>
<th><?php echo $this->Paginator->sort('internal');?></th>
<th><?php echo $this->Paginator->sort('push');?></th>
<th><?php echo $this->Paginator->sort('pull');?></th>
@ -70,6 +71,20 @@ foreach ($servers as $server):
?>
</td>
<td id="connection_test_<?php echo $server['Server']['id'];?>"><span role="button" tabindex="0" aria-label="<?php echo __('Test the connection to the remote instance');?>" title="<?php echo __('Test the connection to the remote instance');?>" class="btn btn-primary" style="line-height:10px; padding: 4px 4px;" onClick="testConnection('<?php echo $server['Server']['id'];?>');"><?php echo __('Run');?></span></td>
<td id="reset_api_key_<?php echo $server['Server']['id'];?>">
<?php
echo $this->Form->postLink(
__('Reset'),
$baseurl . '/servers/resetRemoteAuthKey/' . $server['Server']['id'],
array(
'style' => 'line-height:10px; padding: 4px 4px;',
'title' => __('Remotely reset API key'),
'aria-label' => __('Remotely reset API key'),
'class' => 'btn btn-primary'
)
);
?>
</td>
<td><span class="<?php echo ($server['Server']['internal']? 'icon-ok' : 'icon-remove'); ?>" role="img" aria-label="<?php echo ($server['Server']['internal']? __('Yes') : __('No')); ?>" title="<?php echo ($server['Server']['internal']? __('Internal instance that ignores distribution level degradation *WARNING: Only use this setting if you have several internal instances and the sync link is to an internal extension of the current MISP community*') : __('Normal sync link to an external MISP instance. Distribution degradation will follow the normal rules.')); ?>"></span></td>
<td><span class="<?php echo ($server['Server']['push']? 'icon-ok' : 'icon-remove'); ?>" role="img" aria-label="<?php echo ($server['Server']['push']? __('Yes') : __('No')); ?>"></span><span class="short <?php if (!$server['Server']['push'] || empty($ruleDescription['push'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['push']; ?>"> (<?php echo __('Rules');?>)</span></td>

View File

@ -1,5 +1,25 @@
<div class="users index">
<h2><?php echo __('Users');?></h2>
<?php
if ($isSiteAdmin) {
echo sprintf(
'<span>%s</span>',
__(
'Click %s to reset the API keys of all sync and org admin users in one shot. This will also automatically inform them of their new API keys.',
$this->Form->postLink(
__('here'),
$baseurl . '/users/resetAllSyncAuthKeys',
array(
'title' => __('Reset all sync user API keys'),
'aria-label' => __('Reset all sync user API keys'),
'class' => 'bold'
),
__('Are you sure you wish to reset the API keys of all users with sync privileges?')
)
)
);
}
?>
<div class="pagination">
<ul>
<?php

View File

@ -3,7 +3,8 @@
"minimum-stability": "dev",
"require": {
"kamisama/cake-resque": "4.1.2",
"pear/crypt_gpg": "1.6.3"
"pear/crypt_gpg": "1.6.3",
"monolog/monolog": "1.24.0"
},
"suggest": {
"elasticsearch/elasticsearch": "For logging to elasticsearch",

@ -1 +1 @@
Subproject commit b986f06cb415262c18c25e0e9c37107eb463cc54
Subproject commit c4947875842fcac7d135e1ae9bc99973e18b8b64