From 7774f52fe7004eb8aebb630d5cf3a32be614a8d8 Mon Sep 17 00:00:00 2001 From: Cristian Bell Date: Tue, 23 Aug 2016 16:20:39 +0200 Subject: [PATCH 1/3] chg: only show API/authkey to user with API key rights, fixes #1311 --- app/Controller/Component/ACLComponent.php | 1 + app/Controller/UsersController.php | 131 +++++++++++++--------- app/Model/User.php | 97 +++++++++++----- app/View/Users/request__a_p_i.ctp | 5 + app/View/Users/view.ctp | 10 +- app/webroot/css/main.css | 3 + app/webroot/js/misp2.4.50.js | 25 +++++ 7 files changed, 186 insertions(+), 86 deletions(-) create mode 100644 app/View/Users/request__a_p_i.ctp diff --git a/app/Controller/Component/ACLComponent.php b/app/Controller/Component/ACLComponent.php index 161370930..32af69db4 100644 --- a/app/Controller/Component/ACLComponent.php +++ b/app/Controller/Component/ACLComponent.php @@ -328,6 +328,7 @@ class ACLComponent extends Component { 'logout' => array('*'), 'attributehistogram' => array('*'), 'resetauthkey' => array('*'), + 'request_API' => array('*'), 'routeafterlogin' => array('*'), 'statistics' => array('*'), 'terms' => array('*'), diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php index 8f9b00a2d..a2e0cb513 100644 --- a/app/Controller/UsersController.php +++ b/app/Controller/UsersController.php @@ -34,33 +34,52 @@ class UsersController extends AppController { $this->Auth->allow('login', 'logout'); } -/** - * view method - * - * @param string $id - * @return void - * @throws NotFoundException - */ + /** + * 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.')); + $responsibleAdmin = []; + if (!$this->_isSiteAdmin()) { + $responsibleAdmin = $this->User->findAdminsResponsibleForUser($id); + if($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 request_API(){ + $subject = "[MISP ".Configure::read('MISP.org')."] User requesting API access"; + $body = "A user (".$this->Auth->user('email').") has sent you a request to enable his/her API key access. + Click here to edit his profile to change his role."; + $user = $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')))); + $result = $this->User->sendEmail($user, $body, false, $subject); + if($result) + $message = "API access requested."; + else + $message = "Something went wrong, please try again later."; + + $this->set('message', $message); + $this->layout = 'ajax'; + } + + /** + * edit method + * + * @param string $id + * @return void + * @throws NotFoundException + */ public function edit($id = null) { if (!$this->_isAdmin() && Configure::read('MISP.disableUserSelfManagement')) throw new MethodNotAllowedException('User self-management has been disabled on this instance.'); $me = false; @@ -127,11 +146,11 @@ class UsersController extends AppController { $this->set(compact('roles')); } -/** - * admin_index method - * - * @return void - */ + /** + * admin_index method + * + * @return void + */ public function admin_index() { $this->User->virtualFields['org_ci'] = 'UPPER(Organisation.name)'; $urlParams = ""; @@ -312,13 +331,13 @@ class UsersController extends AppController { $this->layout = 'ajax'; } -/** - * admin_view method - * - * @param string $id - * @return void - * @throws NotFoundException - */ + /** + * admin_view method + * + * @param string $id + * @return void + * @throws NotFoundException + */ public function admin_view($id = null) { $this->User->id = $id; if (!$this->User->exists()) { @@ -333,11 +352,11 @@ class UsersController extends AppController { $this->set('user2', $this->User->read(null, $temp)); } -/** - * admin_add method - * - * @return void - */ + /** + * 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')); @@ -406,13 +425,13 @@ class UsersController extends AppController { $this->set(compact('syncRoles')); } -/** - * admin_edit method - * - * @param string $id - * @return void - * @throws NotFoundException - */ + /** + * 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; @@ -548,14 +567,14 @@ class UsersController extends AppController { $this->set(compact('syncRoles')); } -/** - * admin_delete method - * - * @param string $id - * @return void - * @throws MethodNotAllowedException - * @throws NotFoundException - */ + /** + * 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(); @@ -849,11 +868,11 @@ class UsersController extends AppController { } } -/** - * Used for fields_before and fields for audit - * - * @param $array - */ + /** + * Used for fields_before and fields for audit + * + * @param $array + */ public function arrayCopy(array $array) { $result = array(); foreach ($array as $key => $val) { @@ -868,9 +887,9 @@ class UsersController extends AppController { return $result; } -/** - * @throws NotFoundException - **/ + /** + * @throws NotFoundException + **/ public function checkAndCorrectPgps() { if (!self::_isAdmin()) throw new NotFoundException(); $this->set('fails', $this->User->checkAndCorrectPgps()); diff --git a/app/Model/User.php b/app/Model/User.php index 0c30a8cb8..cb920cd91 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -10,21 +10,21 @@ App::uses('AuthComponent', 'Controller/Component'); */ class User extends AppModel { -/** - * Display field - * - * @var string - */ + /** + * Display field + * + * @var string + */ public $displayField = 'email'; public $orgField = array('Organisation', 'name'); // TODO Audit, LogableBehaviour + org -/** - * Validation rules - * - * @var array - */ + /** + * Validation rules + * + * @var array + */ public $validate = array( 'role_id' => array( 'numeric' => array( @@ -181,11 +181,11 @@ class User extends AppModel { // The Associations below have been created with all possible keys, those that are not needed can be removed -/** - * belongsTo associations - * - * @var array - */ + /** + * belongsTo associations + * + * @var array + */ public $belongsTo = array( 'Role' => array( 'className' => 'Role', @@ -210,11 +210,11 @@ class User extends AppModel { ) ); -/** - * hasMany associations - * - * @var array - */ + /** + * hasMany associations + * + * @var array + */ public $hasMany = array( 'Event' => array( 'className' => 'Event', @@ -281,10 +281,10 @@ class User extends AppModel { return true; } -/** - * Checks if the GPG key is a valid key - * But also import it in the keychain. - */ + /** + * Checks if the GPG key is a valid key + * But also import it in the keychain. + */ // TODO: this will NOT fail on keys that can only be used for signing but not encryption! // the method in verifyUsers will fail in that case. public function validateGpgkey($check) { @@ -418,9 +418,9 @@ class User extends AppModel { return true; } -/** - * Generates an authentication key for each user - */ + /** + * Generates an authentication key for each user + */ public function generateAuthKey() { $length = 40; $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -935,4 +935,47 @@ class User extends AppModel { } return $usersPerOrg; } + + public function findAdminsResponsibleForUser($id){ + $userOrg = $this->find('first', array( + 'conditions' => array( + 'User.id' => $id, + ), + 'contain' => array( + 'Organisation' => array('fields' => array('id')), + ), + 'fields' => array('Organisation.id') + )); + + $admin = $this->find('first', array( + 'recursive' => -1, + 'conditions' => array( + 'Role.perm_site_admin' => 0, + 'User.disabled' => 0, + 'User.org_id' => $userOrg['Organisation']['id'], + 'Role.perm_admin' => 1 + ), + 'contain' => array( + 'Organisation' => array('fields' => array('id')), + 'Role' => array('fields' => array('perm_admin')) + ), + 'fields' => array('User.id', 'User.email', 'User.org_id') + )); + if(count($admin) == 0) { + $admin = $this->find('first', array( + 'recursive' => -1, + 'conditions' => array( + 'Role.perm_site_admin' => 1, + 'User.disabled' => 0, + ), + 'contain' => array( + 'Organisation' => array('fields' => array('id')), + 'Role' => array('fields' => array('perm_site_admin')) + ), + 'fields' => array('User.id', 'User.email', 'User.org_id') + )); + } + + return $admin['User']; + } } diff --git a/app/View/Users/request__a_p_i.ctp b/app/View/Users/request__a_p_i.ctp new file mode 100644 index 000000000..c134171ad --- /dev/null +++ b/app/View/Users/request__a_p_i.ctp @@ -0,0 +1,5 @@ +

+
+
+ Close +
diff --git a/app/View/Users/view.ctp b/app/View/Users/view.ctp index e04860a10..d99f46787 100644 --- a/app/View/Users/view.ctp +++ b/app/View/Users/view.ctp @@ -34,9 +34,13 @@
Html->link('reset', array('controller' => 'users', 'action' => 'resetauthkey', $user['User']['id'])) . ')'; + if ($user['Role']['perm_auth']) { + echo h($user['User']['authkey']); + if (!Configure::read('MISP.disableUserSelfManagement') || $isAdmin) { + echo '(' . $this->Html->link('reset', array('controller' => 'users', 'action' => 'resetauthkey', $user['User']['id'])) . ')'; + } + } else { + echo "Request API access"; } ?>   diff --git a/app/webroot/css/main.css b/app/webroot/css/main.css index 01bb06ad1..c4542c35c 100644 --- a/app/webroot/css/main.css +++ b/app/webroot/css/main.css @@ -1600,6 +1600,9 @@ a.discrete { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } +#confirmation_box .message2user div{text-align: center;} +#confirmation_box .message2user .btn{margin: -1em 0.6em 0.6em;} + @-webkit-keyframes rotation { from {-webkit-transform: rotate(0deg);} to {-webkit-transform: rotate(359deg);} diff --git a/app/webroot/js/misp2.4.50.js b/app/webroot/js/misp2.4.50.js index 95de26f8b..36129a6bf 100644 --- a/app/webroot/js/misp2.4.50.js +++ b/app/webroot/js/misp2.4.50.js @@ -60,6 +60,11 @@ function cancelPrompt() { $("#confirmation_box").empty(); } +function showPrompt(){ + $("#confirmation_box").fadeIn(); + $("#gray_out").fadeIn(); +} + function submitDeletion(context_id, action, type, id) { var context = 'event'; if (type == 'template_elements') context = 'template'; @@ -2489,3 +2494,23 @@ $(".queryPopover").click(function() { }); }); +function requestAPIAccess() { + var destination = 'users'; + var action = 'request_API'; + url = "/" + destination + "/" + action + "/"; + $.ajax({ + type:"get", + url:url, + beforeSend: function (XMLHttpRequest) { + $(".loading").show(); + }, + success:function (data) { + $("#confirmation_box").html(data); + showPrompt(); + $(".loading").hide(); + }, + error:function() { + showMessage('fail', 'Something went wrong - could not request API access.'); + } + }); +} From 139de849524a04e4429b80d4ff93f9bdce6b5591 Mon Sep 17 00:00:00 2001 From: Cristian Bell Date: Tue, 23 Aug 2016 17:12:55 +0200 Subject: [PATCH 2/3] chg: only show API/authkey to user with API key rights, fixes #1311 - adds some missing code parts from the initial commit. --- app/Controller/UsersController.php | 32 ++++++++++++++++-------------- app/Model/User.php | 6 ++---- app/View/Users/view.ctp | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php index a2e0cb513..9bf45bc8d 100644 --- a/app/Controller/UsersController.php +++ b/app/Controller/UsersController.php @@ -43,10 +43,7 @@ class UsersController extends AppController { */ public function view($id = null) { if ("me" == $id) $id = $this->Auth->user('id'); - $responsibleAdmin = []; - if (!$this->_isSiteAdmin()) { - $responsibleAdmin = $this->User->findAdminsResponsibleForUser($id); - if($this->Auth->user('id') != $id) + if (!$this->_isSiteAdmin() && ($this->Auth->user('id') != $id)) { throw new NotFoundException(__('Invalid user or not authorised.')); } $this->User->id = $id; @@ -59,16 +56,17 @@ class UsersController extends AppController { } public function request_API(){ - $subject = "[MISP ".Configure::read('MISP.org')."] User requesting API access"; - $body = "A user (".$this->Auth->user('email').") has sent you a request to enable his/her API key access. - Click here to edit his profile to change his role."; - $user = $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')))); - $result = $this->User->sendEmail($user, $body, false, $subject); - if($result) - $message = "API access requested."; - else - $message = "Something went wrong, please try again later."; - + $responsibleAdmin = $this->User->findAdminsResponsibleForUser($this->Auth->user('id')); + $message = "Something went wrong, please try again later."; + if(isset($responsibleAdmin['email']) && !empty($responsibleAdmin['email'])){ + $subject = "[MISP ".Configure::read('MISP.org')."] User requesting API access"; + $body = "A user (".$this->Auth->user('email').") has sent you a request to enable his/her API key access.
"; + $body .= "Click here to edit his profile to change his role."; + $user = $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')))); + $result = $this->User->sendEmail($user, $body, false, $subject); + if($result) + $message = "API access requested."; + } $this->set('message', $message); $this->layout = 'ajax'; } @@ -590,7 +588,7 @@ class UsersController extends AppController { } $fieldsDescrStr = 'User (' . $id . '): ' . $user['User']['email']; if ($this->User->delete($id)) { - $this->__extralog("delete", $fieldsDescrStr, ''); // TODO Audit, check: modify User + $this->__extralog("delete", $fieldsDescrStr, '');//TODO Audit, check: modify User $this->Session->setFlash(__('User deleted')); $this->redirect(array('action' => 'index')); } @@ -722,6 +720,10 @@ class UsersController extends AppController { $this->Session->setFlash(__('Invalid id for user', true), 'default', array(), 'error'); $this->redirect(array('action' => 'view', $this->Auth->user('id'))); } + if (!$this->userRole['perm_auth']) { + $this->Session->setFlash(__('Invalid action', 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)) { diff --git a/app/Model/User.php b/app/Model/User.php index cb920cd91..a12e8705f 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -951,12 +951,11 @@ class User extends AppModel { 'recursive' => -1, 'conditions' => array( 'Role.perm_site_admin' => 0, + 'Role.perm_admin' => 1, 'User.disabled' => 0, - 'User.org_id' => $userOrg['Organisation']['id'], - 'Role.perm_admin' => 1 + 'User.org_id' => $userOrg['Organisation']['id'] ), 'contain' => array( - 'Organisation' => array('fields' => array('id')), 'Role' => array('fields' => array('perm_admin')) ), 'fields' => array('User.id', 'User.email', 'User.org_id') @@ -969,7 +968,6 @@ class User extends AppModel { 'User.disabled' => 0, ), 'contain' => array( - 'Organisation' => array('fields' => array('id')), 'Role' => array('fields' => array('perm_site_admin')) ), 'fields' => array('User.id', 'User.email', 'User.org_id') diff --git a/app/View/Users/view.ctp b/app/View/Users/view.ctp index d99f46787..df4729381 100644 --- a/app/View/Users/view.ctp +++ b/app/View/Users/view.ctp @@ -40,7 +40,7 @@ echo '(' . $this->Html->link('reset', array('controller' => 'users', 'action' => 'resetauthkey', $user['User']['id'])) . ')'; } } else { - echo "Request API access"; + echo "Request API access"; } ?>   From c19fa90e922431e701452ccd311a621b0a6270dc Mon Sep 17 00:00:00 2001 From: Cristian Bell Date: Wed, 24 Aug 2016 09:59:38 +0200 Subject: [PATCH 3/3] chg: only show API/authkey to user with API key rights, fixes #1311 - code improvements as per @iglocska 's comments. thanks. --- app/Controller/UsersController.php | 2 +- app/Model/User.php | 16 +++------------- app/webroot/js/misp2.4.50.js | 4 +--- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php index 9bf45bc8d..ba365c01f 100644 --- a/app/Controller/UsersController.php +++ b/app/Controller/UsersController.php @@ -56,7 +56,7 @@ class UsersController extends AppController { } public function request_API(){ - $responsibleAdmin = $this->User->findAdminsResponsibleForUser($this->Auth->user('id')); + $responsibleAdmin = $this->User->findAdminsResponsibleForUser($this->Auth->user()); $message = "Something went wrong, please try again later."; if(isset($responsibleAdmin['email']) && !empty($responsibleAdmin['email'])){ $subject = "[MISP ".Configure::read('MISP.org')."] User requesting API access"; diff --git a/app/Model/User.php b/app/Model/User.php index a12e8705f..7d65c4827 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -936,27 +936,17 @@ class User extends AppModel { return $usersPerOrg; } - public function findAdminsResponsibleForUser($id){ - $userOrg = $this->find('first', array( - 'conditions' => array( - 'User.id' => $id, - ), - 'contain' => array( - 'Organisation' => array('fields' => array('id')), - ), - 'fields' => array('Organisation.id') - )); - + public function findAdminsResponsibleForUser($user){ $admin = $this->find('first', array( 'recursive' => -1, 'conditions' => array( 'Role.perm_site_admin' => 0, 'Role.perm_admin' => 1, 'User.disabled' => 0, - 'User.org_id' => $userOrg['Organisation']['id'] + 'User.org_id' => $user['org_id'] ), 'contain' => array( - 'Role' => array('fields' => array('perm_admin')) + 'Role' => array('fields' => array('perm_admin', 'perm_site_admin')) ), 'fields' => array('User.id', 'User.email', 'User.org_id') )); diff --git a/app/webroot/js/misp2.4.50.js b/app/webroot/js/misp2.4.50.js index 36129a6bf..72c31073d 100644 --- a/app/webroot/js/misp2.4.50.js +++ b/app/webroot/js/misp2.4.50.js @@ -2495,9 +2495,7 @@ $(".queryPopover").click(function() { }); function requestAPIAccess() { - var destination = 'users'; - var action = 'request_API'; - url = "/" + destination + "/" + action + "/"; + url = "/users/request_API/"; $.ajax({ type:"get", url:url,