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

pull/6589/head
iglocska 2020-11-15 10:21:50 +01:00
commit a306784844
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
15 changed files with 365 additions and 281 deletions

View File

@ -608,7 +608,7 @@ class ACLComponent extends Component
),
'users' => array(
'acceptRegistrations' => array('perm_site_admin'),
'admin_add' => array('perm_admin'),
'admin_add' => ['AND' => ['perm_admin', 'add_user_enabled']],
'admin_delete' => array('perm_admin'),
'admin_edit' => array('perm_admin'),
'admin_email' => array('perm_admin'),
@ -618,19 +618,19 @@ class ACLComponent extends Component
'admin_quickEmail' => array('perm_admin'),
'admin_view' => array('perm_admin'),
'attributehistogram' => array('*'),
'change_pw' => array('*'),
'change_pw' => ['AND' => ['self_management_enabled', 'password_change_enabled']],
'checkAndCorrectPgps' => array(),
'checkIfLoggedIn' => array('*'),
'dashboard' => array('*'),
'delete' => array('perm_admin'),
'discardRegistrations' => array('perm_site_admin'),
'downloadTerms' => array('*'),
'edit' => array('*'),
'edit' => array('self_management_enabled'),
'email_otp' => array('*'),
'searchGpgKey' => array('*'),
'fetchGpgKey' => array('*'),
'histogram' => array('*'),
'initiatePasswordReset' => array('perm_admin'),
'initiatePasswordReset' => ['AND' => ['perm_admin', 'password_change_enabled']],
'login' => array('*'),
'logout' => array('*'),
'register' => array('*'),
@ -680,6 +680,36 @@ class ACLComponent extends Component
)
);
private $dynamicChecks = [];
public function __construct(ComponentCollection $collection, $settings = array())
{
parent::__construct($collection, $settings);
$this->dynamicChecks['host_org_user'] = function (array $user) {
$hostOrgId = Configure::read('MISP.host_org_id');
return (int)$user['org_id'] === (int)$hostOrgId;
};
$this->dynamicChecks['self_management_enabled'] = function (array $user) {
if (Configure::read('MISP.disableUserSelfManagement') && !$user['Role']['perm_admin']) {
throw new MethodNotAllowedException('User self-management has been disabled on this instance.');
}
return true;
};
$this->dynamicChecks['password_change_enabled'] = function (array $user) {
if (Configure::read('MISP.disable_user_password_change')) {
throw new MethodNotAllowedException('User password change has been disabled on this instance.');
}
return true;
};
$this->dynamicChecks['add_user_enabled'] = function (array $user) {
if (Configure::read('MISP.disable_user_add')) {
throw new MethodNotAllowedException('Adding users has been disabled on this instance.');
}
return true;
};
}
private function __checkLoggedActions($user, $controller, $action)
{
$loggedActions = array(
@ -697,7 +727,6 @@ class ACLComponent extends Component
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'];
@ -752,6 +781,24 @@ class ACLComponent extends Component
}
}
/**
* @param array $user
* @param string $controller
* @param string $action
* @return bool
*/
public function canUserAccess($user, $controller, $action)
{
try {
$this->checkAccess($user, $controller, $action, false);
} catch (NotFoundException $e) {
throw new RuntimeException("Invalid controller '$controller' specified.", 0, $e);
} catch (MethodNotAllowedException $e) {
return false;
}
return true;
}
/**
* The check works like this:
* - If the user is a site admin, return true
@ -763,38 +810,38 @@ class ACLComponent extends Component
* @param array|null $user
* @param string $controller
* @param string $action
* @param bool $soft If true, instead of exception, HTTP error code is retuned as int.
* @return bool|int
* @param bool $checkLoggedActions
* @return true
* @throws NotFoundException
* @throws MethodNotAllowedException
* @throws InternalErrorException
*/
public function checkAccess($user, $controller, $action, $soft = false)
public function checkAccess($user, $controller, $action, $checkLoggedActions = true)
{
$controller = lcfirst(Inflector::camelize($controller));
$action = strtolower($action);
$host_org_id = Configure::read('MISP.host_org_id');
$aclList = $this->__aclList;
foreach ($aclList as $k => $v) {
$aclList[$k] = array_change_key_case($v);
}
if (!$soft) {
if ($checkLoggedActions) {
$this->__checkLoggedActions($user, $controller, $action);
}
if ($user && $user['Role']['perm_site_admin']) {
return true;
}
$aclList = $this->__aclList;
foreach ($aclList as $k => $v) {
$aclList[$k] = array_change_key_case($v);
}
if (!isset($aclList[$controller])) {
return $this->__error(404, 'Invalid controller.', $soft);
$this->__error(404);
}
if (isset($aclList[$controller][$action]) && !empty($aclList[$controller][$action])) {
if (in_array('*', $aclList[$controller][$action])) {
$rules = $aclList[$controller][$action];
if (in_array('*', $rules)) {
return true;
}
if (isset($aclList[$controller][$action]['OR'])) {
foreach ($aclList[$controller][$action]['OR'] as $permission) {
if ($permission === 'host_org_user') {
if ((int)$user['org_id'] === (int)$host_org_id) {
if (isset($rules['OR'])) {
foreach ($rules['OR'] as $permission) {
if (isset($this->dynamicChecks[$permission])) {
if ($this->dynamicChecks[$permission]($user)) {
return true;
}
} else {
@ -803,11 +850,11 @@ class ACLComponent extends Component
}
}
}
} elseif (isset($aclList[$controller][$action]['AND'])) {
} elseif (isset($rules['AND'])) {
$allConditionsMet = true;
foreach ($aclList[$controller][$action]['AND'] as $permission) {
if ($permission === 'host_org_user') {
if ((int)$user['org_id'] !== (int)$host_org_id) {
foreach ($rules['AND'] as $permission) {
if (isset($this->dynamicChecks[$permission])) {
if (!$this->dynamicChecks[$permission]($user)) {
$allConditionsMet = false;
}
} else {
@ -819,27 +866,30 @@ class ACLComponent extends Component
if ($allConditionsMet) {
return true;
}
} elseif ($aclList[$controller][$action][0] !== 'host_org_user' && $user['Role'][$aclList[$controller][$action][0]]) {
return true;
} elseif ($aclList[$controller][$action][0] === 'host_org_user' && (int)$user['org_id'] === (int)$host_org_id) {
} elseif (isset($this->dynamicChecks[$rules[0]])) {
if ($this->dynamicChecks[$rules[0]]($user)) {
return true;
}
} elseif ($user['Role'][$rules[0]]) {
return true;
}
}
return $this->__error(403, 'You do not have permission to use this functionality.', $soft);
$this->__error(403);
}
private function __error($code, $message, $soft = false)
/**
* @param int $code
* @throws InternalErrorException|MethodNotAllowedException|NotFoundException
*/
private function __error($code)
{
if ($soft) {
return $code;
}
switch ($code) {
case 404:
throw new NotFoundException($message);
throw new NotFoundException('Invalid controller.');
case 403:
throw new MethodNotAllowedException($message);
throw new MethodNotAllowedException('You do not have permission to use this functionality.');
default:
throw new InternalErrorException('Unknown error: ' . $message);
throw new InternalErrorException('Unknown error');
}
}
@ -911,39 +961,18 @@ class ACLComponent extends Component
return $results;
}
private function __checkRoleAccess($role)
private function __checkRoleAccess(array $role)
{
$result = array();
$fakeUser = ['Role' => $role, 'org_id' => Configure::read('MISP.host_org_id')];
foreach ($this->__aclList as $controller => $actions) {
$controllerNames = Inflector::variable($controller) == Inflector::underscore($controller) ? array(Inflector::variable($controller)) : array(Inflector::variable($controller), Inflector::underscore($controller));
$controllerNames = Inflector::variable($controller) === Inflector::underscore($controller) ?
array(Inflector::variable($controller)) :
array(Inflector::variable($controller), Inflector::underscore($controller));
foreach ($controllerNames as $controllerName) {
foreach ($actions as $action => $permissions) {
if ($role['perm_site_admin']) {
$result[] = DS . $controllerName . DS . $action;
} elseif (in_array('*', $permissions)) {
$result[] = DS . $controllerName . DS . $action . DS . '*';
} elseif (isset($permissions['OR'])) {
$access = false;
foreach ($permissions['OR'] as $permission) {
if ($role[$permission]) {
$access = true;
}
}
if ($access) {
$result[] = DS . $controllerName . DS . $action . DS . '*';
}
} elseif (isset($permissions['AND'])) {
$access = true;
foreach ($permissions['AND'] as $permission) {
if ($role[$permission]) {
$access = false;
}
}
if ($access) {
$result[] = DS . $controllerName . DS . $action . DS . '*';
}
} elseif (isset($permissions[0]) && $role[$permissions[0]]) {
$result[] = DS . $controllerName . DS . $action . DS . '*';
if ($this->canUserAccess($fakeUser, $controllerName, $action)) {
$result[] = "/$controllerName/$action";
}
}
}

View File

@ -310,7 +310,7 @@ class RestResponseComponent extends Component
foreach ($this->__scopedFieldsConstraint as $controller => $actions) {
$controller = Inflector::tableize($controller);
foreach ($actions as $action => $data) {
if ($this->ACL->checkAccess($user, $controller, $action, true) === true) {
if ($this->ACL->canUserAccess($user, $controller, $action)) {
$admin_routing = '';
if (substr($action, 0, 6) === 'admin_') {
$action = substr($action, 6);
@ -331,7 +331,7 @@ class RestResponseComponent extends Component
foreach ($this->__descriptions as $controller => $actions) {
$controller = Inflector::tableize($controller);
foreach ($actions as $action => $data) {
if ($this->ACL->checkAccess($user, $controller, $action, true) === true) {
if ($this->ACL->canUserAccess($user, $controller, $action)) {
$admin_routing = '';
if (substr($action, 0, 6) === 'admin_') {
$action = substr($action, 6);

View File

@ -131,9 +131,6 @@ class UsersController extends AppController
public function edit()
{
if (!$this->_isAdmin() && Configure::read('MISP.disableUserSelfManagement')) {
throw new MethodNotAllowedException('User self-management has been disabled on this instance.');
}
$currentUser = $this->User->find('first', array(
'conditions' => array('User.id' => $this->Auth->user('id')),
'recursive' => -1
@ -185,8 +182,11 @@ class UsersController extends AppController
}
if (!$abortPost) {
// What fields should be saved (allowed to be saved)
$fieldList = array('email', 'autoalert', 'gpgkey', 'certif_public', 'nids_sid', 'contactalert', 'disabled');
if (!empty($this->request->data['User']['password'])) {
$fieldList = array('autoalert', 'gpgkey', 'certif_public', 'nids_sid', 'contactalert', 'disabled');
if ($this->__canChangeLogin()) {
$fieldList[] = 'email';
}
if ($this->__canChangePassword() && !empty($this->request->data['User']['password'])) {
$fieldList[] = 'password';
$fieldList[] = 'confirm_password';
}
@ -243,15 +243,14 @@ class UsersController extends AppController
$this->set('complexity', !empty(Configure::read('Security.password_policy_complexity')) ? Configure::read('Security.password_policy_complexity') : $this->Server->serverSettings['Security']['password_policy_complexity']['value']);
$this->set('length', !empty(Configure::read('Security.password_policy_length')) ? Configure::read('Security.password_policy_length') : $this->Server->serverSettings['Security']['password_policy_length']['value']);
$roles = $this->User->Role->find('list');
$this->set(compact('roles'));
$this->set('roles', $roles);
$this->set('id', $id);
$this->set('canChangePassword', $this->__canChangePassword());
$this->set('canChangeLogin', $this->__canChangeLogin());
}
public function change_pw()
{
if (!$this->_isAdmin() && Configure::read('MISP.disableUserSelfManagement')) {
throw new MethodNotAllowedException('User self-management has been disabled on this instance.');
}
$id = $this->Auth->user('id');
$user = $this->User->find('first', array(
'conditions' => array('User.id' => $id),
@ -334,14 +333,11 @@ class UsersController extends AppController
$this->User->set('password', '');
$this->request->data = $this->User->data;
$roles = $this->User->Role->find('list');
$this->set(compact('roles'));
$this->set('roles', $roles);
}
public function admin_index()
{
if (!$this->_isAdmin()) {
throw new NotFoundException(__('Invalid user or not authorised.'));
}
$this->User->virtualFields['org_ci'] = 'UPPER(Organisation.name)';
$urlParams = "";
$passedArgsArray = array();
@ -497,9 +493,6 @@ class UsersController extends AppController
public function admin_filterUserIndex()
{
if (!$this->_isAdmin() && !$this->_isSiteAdmin()) {
throw new MethodNotAllowedException();
}
$passedArgsArray = array();
$booleanFields = array('autoalert', 'contactalert', 'termsaccepted');
$textFields = array('role', 'email', 'authkey');
@ -633,9 +626,6 @@ class UsersController extends AppController
public function admin_add()
{
if (!$this->_isAdmin()) {
throw new Exception('Administrators only.');
}
$params = null;
if (!$this->_isSiteAdmin()) {
$params = array('conditions' => array('perm_site_admin !=' => 1, 'perm_sync !=' => 1, 'perm_regexp_access !=' => 1));
@ -908,7 +898,6 @@ class UsersController extends AppController
}
}
}
$fail = false;
if (!$this->_isSiteAdmin() && !$abortPost) {
$organisation = $this->User->Organisation->find('first', array(
'conditions' => array('Organisation.id' => $userToEdit['User']['org_id']),
@ -943,6 +932,13 @@ class UsersController extends AppController
if (!$this->_isSiteAdmin()) {
$blockedFields[] = 'org_id';
}
if (!$this->__canChangeLogin()) {
$blockedFields[] = 'email';
}
if (!$this->__canChangePassword()) {
$blockedFields[] = 'enable_password';
$blockedFields[] = 'change_pw';
}
foreach (array_keys($this->request->data['User']) as $field) {
if (in_array($field, $blockedFields)) {
continue;
@ -1081,6 +1077,8 @@ class UsersController extends AppController
$this->set('id', $id);
$this->set(compact('roles'));
$this->set(compact('syncRoles'));
$this->set('canChangeLogin', $this->__canChangeLogin());
$this->set('canChangePassword', $this->__canChangePassword());
}
public function admin_delete($id = null)
@ -2735,4 +2733,17 @@ class UsersController extends AppController
$this->redirect($this->referer());
}
}
private function __canChangePassword()
{
return $this->ACL->canUserAccess($this->Auth->user(), 'users', 'change_pw');
}
private function __canChangeLogin()
{
if ($this->_isSiteAdmin()) {
return true;
}
return !Configure::read('MISP.disable_user_login_change');
}
}

View File

@ -918,8 +918,34 @@ class Server extends AppModel
'test' => 'testBool',
'type' => 'boolean',
'null' => false,
),
'disable_user_login_change' => array(
'level' => self::SETTING_RECOMMENDED,
'description' => __('When enabled only Site admins can change user email. This should be enabled if you manage user logins by external system.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => false,
),
'disable_user_password_change' => array(
'level' => self::SETTING_RECOMMENDED,
'description' => __('When enabled only Site admins can change user password. This should be enabled if you manage user passwords by external system.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => false,
),
'disable_user_add' => array(
'level' => self::SETTING_RECOMMENDED,
'description' => __('When enabled, Org Admins could not add new users. This should be enabled if you manage users by external system.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => false,
),
'block_event_alert' => array(
'level' => 1,
'description' => __('Enable this setting to start blocking alert e-mails for events with a certain tag. Define the tag in MISP.block_event_alert_tag.'),

View File

@ -7,12 +7,12 @@
<th><?php echo $this->Paginator->sort('authkey');?></th>
<th><?php echo $this->Paginator->sort('autoalert');?></th>
<th><?php echo $this->Paginator->sort('contactalert');?></th>
<th><?php echo $this->Paginator->sort('gpgkey');?></th>
<th><?php echo $this->Paginator->sort('gpgkey', __('PGP key'));?></th>
<?php if (Configure::read('SMIME.enabled')): ?>
<th><?php echo $this->Paginator->sort('certif_public', 'SMIME');?></th>
<th><?php echo $this->Paginator->sort('certif_public', 'S/MIME');?></th>
<?php endif; ?>
<th><?php echo $this->Paginator->sort('nids_sid');?></th>
<th><?php echo $this->Paginator->sort('termsaccepted');?></th>
<th><?php echo $this->Paginator->sort('nids_sid', __('NIDS SID'));?></th>
<th><?php echo $this->Paginator->sort('termsaccepted', __('Terms accepted'));?></th>
<th><?php echo $this->Paginator->sort('current_login', __('Last login'));?></th>
<th><?php echo $this->Paginator->sort('date_created', __('Created'));?></th>
<?php
@ -40,7 +40,7 @@
<td ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
<?php echo h($user['User']['email']); ?>&nbsp;
</td>
<td ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" class="<?php echo $user['Role']['perm_auth'] ? 'bold' : 'grey'; ?>">
<td class="bold<?= $user['Role']['perm_auth'] ? '' : ' grey'; ?>">
<span class="privacy-value quickSelect" data-hidden-value="<?= h($user['User']['authkey']) ?>">****************************************</span>&nbsp;<i class="privacy-toggle fas fa-eye useCursorPointer" title="<?= __('Reveal hidden value') ?>"></i>
</td>
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
@ -64,10 +64,10 @@
<?php echo ($user['User']['termsaccepted'] == 1) ? __("Yes") : __("No"); ?>
</td>
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" title="<?php echo !$user['User']['current_login'] ? __('N/A') : h(date("Y-m-d H:i:s",$user['User']['current_login']));?>">
<?php echo !$user['User']['current_login'] ? __('N/A') : h(date("Y-m-d",$user['User']['current_login'])); ?>&nbsp;
<?php echo !$user['User']['current_login'] ? __('N/A') : h(date("Y-m-d", $user['User']['current_login'])); ?>&nbsp;
</td>
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" title="<?php echo !$user['User']['current_login'] ? 'N/A' : h(date("Y-m-d H:i:s",$user['User']['current_login']));?>">
<?php echo !$user['User']['date_created'] ? __('N/A') : h(date("Y-m-d",$user['User']['date_created'])); ?>&nbsp;
<?php echo !$user['User']['date_created'] ? __('N/A') : h(date("Y-m-d", $user['User']['date_created'])); ?>&nbsp;
</td>
<?php
if (Configure::read('Plugin.CustomAuth_enable') && !Configure::read('Plugin.CustomAuth_required')):

View File

@ -1,10 +1,6 @@
<?php
$canAccess = function ($controller, $action) use ($me, $aclComponent) {
$response = $aclComponent->checkAccess($me, $controller, $action, true);
if ($response === 404) {
throw new Exception("Invalid controller '$controller' specified for menu requirements.");
}
return $response === true;
return $aclComponent->canUserAccess($me, $controller, $action);
};
$this->set('menuItem', $menuItem);
@ -549,23 +545,28 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
break;
case 'globalActions':
if (((Configure::read('MISP.disableUserSelfManagement') && $isAdmin) || !Configure::read('MISP.disableUserSelfManagement')) && ($menuItem === 'edit' || $menuItem === 'view' || $menuItem === 'change_pw')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => $baseurl . '/users/edit',
'text' => __('Edit My Profile')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => $baseurl . '/users/change_pw',
'text' => __('Change Password')
));
if ($menuItem === 'edit' || $menuItem === 'view' || $menuItem === 'change_pw') {
if ($canAccess('users', 'edit')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => $baseurl . '/users/edit',
'text' => __('Edit My Profile')
));
}
if ($canAccess('users', 'change_pw')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => $baseurl . '/users/change_pw',
'text' => __('Change Password')
));
} else if (Configure::read('Plugin.CustomAuth_custom_password_reset')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'custom_pw_reset',
'url' => Configure::read('Plugin.CustomAuth_custom_password_reset'),
'text' => __('Change Password')
));
}
echo $divider;
} else if (Configure::read('Plugin.CustomAuth_custom_password_reset')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'custom_pw_reset',
'url' => Configure::read('Plugin.CustomAuth_custom_password_reset'),
'text' => __('Reset Password')
));
}
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'view',
'url' => $baseurl . '/users/view/me',
@ -777,13 +778,15 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
'url' => $baseurl . '/admin/users/view/' . h($id),
'text' => __('View User')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'onClick' => array(
'function' => 'initiatePasswordReset',
'params' => array($id)
),
'text' => __('Reset Password')
));
if ($canAccess('users', 'initiatePasswordReset')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'onClick' => array(
'function' => 'initiatePasswordReset',
'params' => array($id)
),
'text' => __('Reset Password')
));
}
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'editUser',
'url' => $baseurl . '/admin/users/edit/' . h($id),

View File

@ -3,11 +3,7 @@
// New approach how to define menu requirements. It takes ACLs from ACLComponent.
// TODO: Use for every menu item
$canAccess = function ($controller, $action) use ($me, $aclComponent) {
$response = $aclComponent->checkAccess($me, $controller, $action, true);
if ($response === 404) {
throw new Exception("Invalid controller '$controller' specified for menu requirements.");
}
return $response === true;
return $aclComponent->canUserAccess($me, $controller, $action);
};
$menu = array(
@ -334,7 +330,8 @@
),
array(
'text' => __('Add User'),
'url' => $baseurl . '/admin/users/add'
'url' => $baseurl . '/admin/users/add',
'requirement' => $canAccess('users', 'admin_add'),
),
array(
'text' => __('Contact Users'),

View File

@ -2,61 +2,82 @@
App::uses('AppHelper', 'View/Helper');
// Helper to retrieve org images with the given parameters
class OrgImgHelper extends AppHelper {
const IMG_PATH = APP . WEBROOT_DIR . DS . 'img' . DS . 'orgs' . DS;
class OrgImgHelper extends AppHelper
{
const IMG_PATH = APP . WEBROOT_DIR . DS . 'img' . DS . 'orgs' . DS;
public function getOrgImg($options, $returnData = false, $raw = false) {
$imgOptions = array();
$possibleFields = array('id', 'name');
$size = !empty($options['size']) ? $options['size'] : 48;
foreach ($possibleFields as $field) {
if (isset($options[$field]) && file_exists(self::IMG_PATH . $options[$field] . '.png')) {
$imgOptions[$field] = $options[$field] . '.png';
break;
}
}
$baseurl = $this->_View->viewVars['baseurl'];
if (!empty($imgOptions)) {
foreach ($imgOptions as $field => $imgOption) {
$result = sprintf(
'<img src="%s/img/orgs/%s" title="%s" width="%s" height="%s">',
$baseurl,
$imgOption,
isset($options['name']) ? h($options['name']) : h($options['id']),
(int)$size,
(int)$size
);
public function getNameWithImg(array $organisation)
{
if (!isset($organisation['Organisation'])) {
return '';
}
if (!$raw) {
$result = sprintf(
'<a href="%s/organisations/view/%s">%s</a>',
$baseurl,
empty($options['id']) ? h($options['name']) : h($options['id']),
$result
);
}
break;
}
} else {
if ($raw) {
$result = sprintf(
'<span class="welcome">%s</span>',
h($options['name'])
);
} else {
$result = sprintf(
'<a href="%s/organisations/view/%s"><span class="welcome">%s</span></a>',
$baseurl,
empty($options['id']) ? h($options['name']) : h($options['id']),
h($options['name'])
);
}
}
if ($returnData) {
return $result;
} else {
echo $result;
$orgImgName = null;
foreach (['id', 'name'] as $field) {
if (isset($organisation['Organisation'][$field]) && file_exists(self::IMG_PATH . $organisation['Organisation'][$field] . '.png')) {
$orgImgName = $organisation['Organisation'][$field] . '.png';
break;
}
}
$baseurl = $this->_View->viewVars['baseurl'];
$link = $baseurl . '/organisations/view/' . (empty($organisation['Organisation']['id']) ? h($organisation['Organisation']['name']) : h($organisation['Organisation']['id']));
if ($orgImgName) {
$orgImgUrl = $baseurl . '/img/orgs/' . $orgImgName;
return sprintf('<a href="%s" style="background-image: url(\'%s\')" class="orgImg">%s</a>', $link, $orgImgUrl, h($organisation['Organisation']['name']));
} else {
return sprintf('<a href="%s">%s</a>', $link, h($organisation['Organisation']['name']));
}
}
public function getOrgImg($options, $returnData = false, $raw = false)
{
$orgImgName = null;
foreach (['id', 'name'] as $field) {
if (isset($options[$field]) && file_exists(self::IMG_PATH . $options[$field] . '.png')) {
$orgImgName = $options[$field] . '.png';
break;
}
}
$baseurl = $this->_View->viewVars['baseurl'];
if ($orgImgName) {
$size = !empty($options['size']) ? $options['size'] : 48;
$result = sprintf(
'<img src="%s/img/orgs/%s" title="%s" width="%s" height="%s">',
$baseurl,
$orgImgName,
isset($options['name']) ? h($options['name']) : h($options['id']),
(int)$size,
(int)$size
);
if (!$raw) {
$result = sprintf(
'<a href="%s/organisations/view/%s">%s</a>',
$baseurl,
empty($options['id']) ? h($options['name']) : h($options['id']),
$result
);
}
} else {
if ($raw) {
$result = sprintf(
'<span class="welcome">%s</span>',
h($options['name'])
);
} else {
$result = sprintf(
'<a href="%s/organisations/view/%s"><span class="welcome">%s</span></a>',
$baseurl,
empty($options['id']) ? h($options['name']) : h($options['id']),
h($options['name'])
);
}
}
if ($returnData) {
return $result;
} else {
echo $result;
}
}
}

View File

@ -37,7 +37,7 @@
$passwordPopover = '<span class="blue bold">' . __('Minimal length') . '</span>: ' . h($length) . '<br>';
$passwordPopover .= '<span class="blue bold">' . __('Complexity') . '</span>: ' . h($complexity);
echo $this->Form->input('password', array(
'label' => __('Password') . ' <span id="PasswordPopover" class="fas fa-info-circle"></span>'
'label' => __('Password') . ' <span id="PasswordPopover" data-content="' . h($passwordPopover) . '" class="fas fa-info-circle"></span>'
));
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
?>
@ -59,9 +59,9 @@
}
echo $this->Form->input('role_id', $roleOptions);
echo $this->Form->input('authkey', array('value' => $authkey, 'readonly' => 'readonly', 'div' => 'input clear'));
echo $this->Form->input('nids_sid');
echo $this->Form->input('nids_sid', ['label' => __('NIDS SID')]);
?>
<div id = "syncServers" class="hidden">
<div id="syncServers" class="hidden">
<?php
echo $this->Form->input('server_id', array('label' => __('Sync user for'), 'div' => 'clear', 'options' => $servers));
?>
@ -70,6 +70,7 @@
echo $this->Form->input('gpgkey', array('label' => __('GnuPG key'), 'div' => 'clear', 'class' => 'input-xxlarge', 'placeholder' => __('Paste the user\'s GnuPG key here or try to retrieve it from the CIRCL key server by clicking on "Fetch GnuPG key" below.')));
?>
<div class="clear"><span role="button" tabindex="0" aria-label="<?php echo __('Fetch the user\'s GnuPG key');?>" onClick="lookupPGPKey('UserEmail');" class="btn btn-inverse" style="margin-bottom:10px;"><?php echo __('Fetch GnuPG key');?></span></div>
<div class="user-edit-checkboxes" style="margin-bottom: 1em">
<?php
if (Configure::read('SMIME.enabled')) echo $this->Form->input('certif_public', array('label' => __('S/MIME Public certificate (PEM format)'), 'div' => 'clear', 'class' => 'input-xxlarge', 'placeholder' => __('Paste the user\'s S/MIME public key in PEM format here.')));
$default_publish_alert = Configure::check('MISP.default_publish_alert') ? Configure::read('MISP.default_publish_alert') : true;
@ -83,9 +84,6 @@
'type' => 'checkbox',
'checked' => isset($this->request->data['User']['contactalert']) ? $this->request->data['User']['contactalert'] : true
));
?>
<div class="clear"></div>
<?php
echo $this->Form->input('disabled', array('type' => 'checkbox', 'label' => __('Disable this user account')));
echo $this->Form->input('notify', array(
'label' => __('Send credentials automatically'),
@ -93,9 +91,10 @@
'checked' => isset($this->request->data['User']['notify']) ? $this->request->data['User']['notify'] : true
));
?>
</div>
</fieldset>
<?php
echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
echo $this->Form->button(__('Create user'), array('class' => 'btn btn-primary'));
echo $this->Form->end();?>
</div>
<?php
@ -116,11 +115,5 @@ $(function() {
$('#UserExternalAuthRequired').change(function() {
checkUserExternalAuth();
});
$('#PasswordPopover').popover("destroy").popover({
placement: 'right',
html: 'true',
trigger: 'hover',
content: <?= json_encode($passwordPopover); ?>
});
});
</script>

View File

@ -1,9 +1,12 @@
<div class="users form">
<?php echo $this->Form->create('User', array('novalidate'=>true));?>
<?php echo $this->Form->create('User', array('novalidate' => true));?>
<fieldset>
<legend><?php echo __('Admin Edit User'); ?></legend>
<?php
echo $this->Form->input('email');
echo $this->Form->input('email', [
'disabled' => !$canChangeLogin,
'data-disabled-reason' => !$canChangePassword ? __('User login change is disabled on this instance') : '',
]);
?>
<div class="clear"></div>
<?php
@ -29,16 +32,20 @@
<div class="clear"></div>
<div id="passwordDivDiv">
<?php
echo $this->Form->input('enable_password', array('type' => 'checkbox', 'label' => __('Set password')));
echo $this->Form->input('enable_password', [
'type' => 'checkbox',
'label' => __('Set password'),
'disabled' => !$canChangePassword,
'data-disabled-reason' => !$canChangePassword ? __('User password change is disabled on this instance') : '',
]);
?>
<a class="useCursorPointer" onclick="$('#resetAuthKeyForm').submit();"><?= __('Reset Auth Key') ?></a>
<div id="PasswordDiv">
<div class="clear"></div>
<?php
$passwordPopover = '<span class=\"blue bold\">' . __('Length') .'</span>: ' . h($length) . '<br />';
$passwordPopover .= '<span class=\"blue bold\">' . __('Complexity') .'</span>: ' . h($complexity);
$passwordPopover = '<span class="blue bold">' . __('Length') .'</span>: ' . h($length) . '<br>';
$passwordPopover .= '<span class="blue bold">' . __('Complexity') .'</span>: ' . h($complexity);
echo $this->Form->input('password', array(
'label' => __('Password') . ' <span id="PasswordPopover" class="fas fa-info-circle"></span>'
'label' => __('Password') . ' <span id="PasswordPopover" data-content="' . h($passwordPopover) .'" class="fas fa-info-circle"></span>'
));
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
?>
@ -53,10 +60,11 @@
));
}
echo $this->Form->input('role_id', array('label' => __('Role'))); // TODO ACL, User edit role_id.
echo $this->Form->input('authkey', array('disabled' => 'disabled', 'div' => 'input clear'));
echo $this->Form->input('nids_sid');
$authkeyLabel = __('Authkey') . ' <a class="useCursorPointer" onclick="$(\'#resetAuthKeyForm\').submit();">' . __('(Reset)') . '</a>';
echo $this->Form->input('authkey', array('disabled' => true, 'div' => 'input clear', 'label' => $authkeyLabel));
echo $this->Form->input('nids_sid', ['label' => __('NIDS SID')]);
?>
<div id = "syncServers" class="hidden">
<div id="syncServers" class="hidden">
<?php
echo $this->Form->input('server_id', array('label' => __('Sync user for'), 'div' => 'clear', 'options' => $servers));
?>
@ -66,16 +74,21 @@
?>
<div class="clear"><span role="button" tabindex="0" aria-label="<?php echo __('Fetch the user\'s GnuPG key');?>" onClick="lookupPGPKey('UserEmail');" class="btn btn-inverse" style="margin-bottom:10px;"><?php echo __('Fetch GnuPG key');?></span></div>
<?php
if (Configure::read('SMIME.enabled')) echo $this->Form->input('certif_public', array('label' => __('S/MIME Public certificate (PEM format)'), 'div' => 'clear', 'class' => 'input-xxlarge', 'placeholder' => __('Paste the user\'s S/MIME public key in PEM format here.')));
if (Configure::read('SMIME.enabled')) {
echo $this->Form->input('certif_public', array('label' => __('S/MIME Public certificate (PEM format)'), 'div' => 'clear', 'class' => 'input-xxlarge', 'placeholder' => __('Paste the user\'s S/MIME public key in PEM format here.')));
}
echo '<div class="user-edit-checkboxes">';
echo $this->Form->input('termsaccepted', array('type' => 'checkbox', 'label' => __('Terms accepted')));
echo $this->Form->input('change_pw', array('type' => 'checkbox', 'label' => __('Change Password')));
echo $this->Form->input('change_pw', [
'type' => 'checkbox',
'label' => __('User must change password after next login'),
'disabled' => !$canChangePassword,
'data-disabled-reason' => !$canChangePassword ? __('User password change is disabled on this instance') : '',
]);
echo $this->Form->input('autoalert', array('label' => __('Receive alerts when events are published'), 'type' => 'checkbox'));
echo $this->Form->input('contactalert', array('label' => __('Receive alerts from "contact reporter" requests'), 'type' => 'checkbox'));
?>
<div class="clear"></div>
<?php
echo $this->Form->input('disabled', array('type' => 'checkbox', 'label' => __('Disable this user account')));
echo '</div>';
?>
</fieldset>
<div style="border-bottom: 1px solid #e5e5e5;width:100%;">&nbsp;</div>
@ -87,7 +100,7 @@
?>
</div>
<?php
echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
echo $this->Form->button(__('Edit user'), array('class' => 'btn btn-primary'));
echo $this->Form->end();
echo $this->Form->create('User', array(
'url' => array('controller' => 'users', 'action' => 'resetauthkey', $id),
@ -102,7 +115,7 @@
<script type="text/javascript">
var syncRoles = <?php echo json_encode($syncRoles); ?>;
$(document).ready(function() {
$(function() {
syncUserSelected();
$('#UserRoleId').change(function() {
syncUserSelected();
@ -115,11 +128,5 @@
$('#UserExternalAuthRequired').change(function() {
checkUserExternalAuth();
});
$('#PasswordPopover').popover("destroy").popover({
placement: 'right',
html: 'true',
trigger: 'hover',
content: '<?php echo $passwordPopover; ?>'
});
});
</script>

View File

@ -6,7 +6,7 @@
$passwordPopover = '<span class="blue bold">' . __('Minimal length') . '</span>: ' . h($length) . '<br>';
$passwordPopover .= '<span class="blue bold">' . __('Complexity') . '</span>: ' . h($complexity);
echo $this->Form->input('password', array(
'label' => __('Password') . ' <span id="PasswordPopover" class="fas fa-info-circle"></span>', 'autofocus'
'label' => __('Password') . ' <span id="PasswordPopover" data-content="' . h($passwordPopover) . '" class="fas fa-info-circle"></span>', 'autofocus'
));
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
?>
@ -24,16 +24,6 @@ echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
echo $this->Form->end();
?>
</div>
<script type="text/javascript">
$(function() {
$('#PasswordPopover').popover("destroy").popover({
placement: 'right',
html: 'true',
trigger: 'hover',
content: <?= json_encode($passwordPopover) ?>
});
});
</script>
<?php
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'change_pw'));
?>

View File

@ -3,20 +3,22 @@
<fieldset>
<legend><?php echo __('Edit My Profile'); ?></legend>
<?php
echo $this->Form->input('email');
echo $this->Form->input('email', ['disabled' => $canChangeLogin ? false : 'disabled']);
?>
<div class="input clear"></div>
<?php
if ($canChangePassword) {
$passwordPopover = '<span class="blue bold">' . __('Minimal length') . '</span>: ' . h($length) . '<br>';
$passwordPopover .= '<span class="blue bold">' . __('Complexity') . '</span>: ' . h($complexity);
echo $this->Form->input('password', array(
'label' => __('Password') . ' <span id="PasswordPopover" class="fas fa-info-circle"></span>'
'label' => __('Password') . ' <span id="PasswordPopover" data-content="' . h($passwordPopover) . '" class="fas fa-info-circle"></span>'
));
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
}
?>
<div class="input clear"></div>
<?php
echo $this->Form->input('nids_sid');
echo $this->Form->input('nids_sid', ['label' => __('NIDS SID')]);
?>
<div class="input clear"></div>
<?php
@ -24,9 +26,13 @@
?>
<div class="clear"><span role="button" tabindex="0" aria-label="<?php echo __('Fetch GnuPG key');?>" onClick="lookupPGPKey('UserEmail');" class="btn btn-inverse" style="margin-bottom:10px;"><?php echo __('Fetch GnuPG key');?></span></div>
<?php
if (Configure::read('SMIME.enabled')) echo $this->Form->input('certif_public', array('label' => __('S/MIME Public certificate (PEM format)'), 'div' => 'clear', 'class' => 'input-xxlarge'));
if (Configure::read('SMIME.enabled')) {
echo $this->Form->input('certif_public', array('label' => __('S/MIME Public certificate (PEM format)'), 'div' => 'clear', 'class' => 'input-xxlarge'));
}
echo '<div class="user-edit-checkboxes">';
echo $this->Form->input('autoalert', array('label' => __('Receive alerts when events are published'), 'type' => 'checkbox'));
echo $this->Form->input('contactalert', array('label' => __('Receive alerts from "contact reporter" requests'), 'type' => 'checkbox'));
echo '</div>';
?>
</fieldset>
<div style="border-bottom: 1px solid #e5e5e5;width:100%;">&nbsp;</div>
@ -38,7 +44,7 @@
?>
</div>
<?php
echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
echo $this->Form->button(__('Edit'), array('class' => 'btn btn-primary'));
echo $this->Form->end();
?>
</div>
@ -46,14 +52,4 @@
$user['User']['id'] = $id;
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'edit', 'user' => $user));
?>
<script type="text/javascript">
$(function() {
$('#PasswordPopover').popover("destroy").popover({
placement: 'right',
html: 'true',
trigger: 'hover',
content: <?= json_encode($passwordPopover) ?>
});
});
</script>
<?php echo $this->Js->writeBuffer();

View File

@ -13,21 +13,20 @@
);
$table_data[] = array(
'key' => __('Organisation'),
'html' => sprintf(
'<a href="%s/organisations/view/%s">%s</a>',
$baseurl,
h($user['Organisation']['id']),
h($user['Organisation']['name'])
)
'html' => $this->OrgImg->getNameWithImg($user),
);
$table_data[] = array('key' => __('Role'), 'html' => $this->Html->link($user['Role']['name'], array('controller' => 'roles', 'action' => 'view', $user['Role']['id'])));
$table_data[] = array('key' => __('Autoalert'), 'boolean' => $user['User']['autoalert']);
$table_data[] = array('key' => __('Contactalert'), 'boolean' => $user['User']['contactalert']);
$authkey_data = sprintf(
'<a onclick="requestAPIAccess();" style="cursor:pointer;"></a>',
__('Request API access')
);
if (empty(Configure::read('Security.advanced_authkeys'))) {
if (!$admin_view && !$user['Role']['perm_auth']) {
$table_data[] = array(
'key' => __('Auth key'),
'html' => sprintf('<a onclick="requestAPIAccess();" class="useCursorPointer">%s</a>', __('Request API access')),
);
}
if (empty(Configure::read('Security.advanced_authkeys')) && $user['Role']['perm_auth']) {
$authkey_data = sprintf(
'<span class="privacy-value quickSelect authkey" data-hidden-value="%s">****************************************</span>&nbsp;<i class="privacy-toggle fas fa-eye useCursorPointer" title="%s"></i>%s',
h($user['User']['authkey']),
@ -38,7 +37,7 @@
)
);
$table_data[] = array(
'key' => __('Authkey'),
'key' => __('Auth key'),
'html' => $authkey_data
);
}
@ -137,24 +136,3 @@
$this->element('/genericElements/accordion', array('title' => 'Events', 'url' => '/events/index/searchemail:' . urlencode(h($user['User']['email'])))),
$this->element('/genericElements/SideMenu/side_menu', $current_menu[$admin_view ? 'admin_view' : 'view'])
);
?>
<script type="text/javascript">
$(function () {
$.ajax({
url: '<?php echo $baseurl . "/events/index/searchemail:" . urlencode(h($user['User']['email'])); ?>',
type:'GET',
beforeSend: function () {
$(".loading").show();
},
error: function(){
$('#userEvents').html('An error has occurred, please reload the page.');
},
success: function(response){
$('#userEvents').html(response);
},
complete: function() {
$(".loading").hide();
}
});
});
</script>

View File

@ -2645,3 +2645,28 @@ table tr:hover .down-expand-button {
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
font-size: 11px;
}
/*
Make user edit checkboxes nicer
*/
.user-edit-checkboxes div.input {
float: none;
width: inherit;
margin-top: 3px;
}
.user-edit-checkboxes .checkbox input[type="checkbox"] {
margin-top: 4px;
}
.user-edit-checkboxes label {
display: inline;
}
a.orgImg {
background-repeat: no-repeat;
background-size: 20px;
padding-left: 25px;
padding-top: 2px;
padding-bottom: 2px;
}

View File

@ -35,7 +35,7 @@ function rgb2hex(rgb) {
}
function xhrFailCallback(xhr) {
if (xhr.status === 403) {
if (xhr.status === 403 || xhr.status === 405) {
showMessage('fail', 'Not allowed.');
} else if (xhr.status === 404) {
showMessage('fail', 'Resource not found.');
@ -300,18 +300,18 @@ function initiatePasswordReset(id) {
$.get(baseurl + "/users/initiatePasswordReset/" + id, function(data) {
$("#confirmation_box").html(data);
openPopup("#confirmation_box");
});
}).fail(xhrFailCallback)
}
function submitPasswordReset(id) {
var formData = $('#PromptForm').serialize();
var url = baseurl + "/users/initiatePasswordReset/" + id;
$.ajax({
beforeSend: function (XMLHttpRequest) {
beforeSend: function () {
$(".loading").show();
},
data: formData,
success:function (data, textStatus) {
success: function (data) {
handleGenericAjaxResponse(data);
},
complete:function() {
@ -319,9 +319,9 @@ function submitPasswordReset(id) {
$("#confirmation_box").fadeOut();
$("#gray_out").fadeOut();
},
type:"post",
type: "post",
cache: false,
url:url,
url: url,
});
}
@ -4684,6 +4684,14 @@ $(document).ready(function() {
return $(this).data('disabled-reason');
}
});
$('#PasswordPopover').popover("destroy").popover({
placement: 'right',
html: 'true',
trigger: 'hover',
content: function () {
return $(this).data('content');
}
});
$(".queryPopover").click(function() {
url = $(this).data('url');
id = $(this).data('id');