Merge branch '355-api-security' into '2-6-0'

Improve API Security

Closes #355

See merge request !13
merge-requests/14/head
Mike Koch 8 years ago
commit 514dae4c57

@ -32,7 +32,7 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiSuccess {Integer} priority The ID of the priority the ticket is in
* @apiSuccess {String} subject The subject of the ticket
* @apiSuccess {String} message The original message of the ticket
* @apiSuccess {String} dateCreated The date and time the ticket was submitted, in `YYYY-MM-DD hh:mm:ss`
* @apiSuccess {Date} dateCreated The date and time the ticket was submitted
* @apiSuccess {Integer} articles The knowledgebase article IDs suggested when the user created the ticket
* @apiSuccess {String} ip The IP address of the submitter
* @apiSuccess {String} language The language the ticket was submitted in
@ -41,7 +41,6 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiSuccess {String} timeWorked The total time worked on the ticket, in `hh:mm:ss`
* @apiSuccess {Boolean} archive `true` if the ticket is tagged<br>`false` otherwise
* @apiSuccess {Boolean} locked `true` if the ticket is locked<br>`false` otherwise
* @apiSuccess {Binary[]} attachments Array of attachments, in base-64 encoded binary
* @apiSuccess {Integer[]} merged Array of merged ticket IDs
* @apiSuccess {String} legacyAuditTrail HTML markup of the entire "Audit Trail" section
* @apiSuccess {String} custom1-20 Custom fields 1-20's values.
@ -52,6 +51,8 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiSuccess {String} userAgent The user agent of the user who submitted the ticket
* @apiSuccess {Integer} screenResolutionWidth The width of the screen resolution of the user who submitted the ticket
* @apiSuccess {Integer} screenResolutionHeight The height of the screen resolution of the user who submitted the ticket
* @apiSuccess {Date} dueDate The ticket's due date, if there is one
* @apiSuccess {Boolean} overdueEmailSent Set to `true` if an overdue email has been sent.<br>`false` otherwise
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
@ -102,7 +103,9 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* "html": false,
* "userAgent": null,
* "screenResolutionWidth": null,
* "screenResolutionHeight": null
* "screenResolutionHeight": null,
* "dueDate": "2016-01-01 00:00:00",
* "overdueEmailSent": "true"
* }
*
* @apiError (noTokenProvided) 400 No `X-Auth-Token` was provided where it is required
@ -110,17 +113,18 @@ $request_method = $_SERVER['REQUEST_METHOD'];
*/
if ($request_method == 'GET') {
$token = get_header('X-Auth-Token');
$user = NULL;
try {
get_user_for_token($token, $hesk_settings);
$user = get_user_for_token($token, $hesk_settings);
} catch (AccessException $e) {
return http_response_code($e->getCode());
}
if (isset($_GET['id'])) {
$results = get_ticket_for_staff($hesk_settings, $_GET['id']);
$results = get_ticket_for_staff($hesk_settings, $user, $_GET['id']);
} else {
$results = get_ticket_for_staff($hesk_settings);
$results = get_ticket_for_staff($hesk_settings, $user);
}
if ($results == NULL) {

@ -20,7 +20,7 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiVersion 0.0.0
* @apiName GetUser
* @apiGroup User
* @apiPermission protected
* @apiPermission canManUsers
*
* @apiParam {Number} [id] The ID of the user. Omit for all users.
*
@ -30,7 +30,6 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiSuccess {String} name The user's name
* @apiSuccess {String} email The user's email address
* @apiSuccess {String} signature The user's signature, in plaintext
* @apiSuccess {Unknown} language ??? (Unknown)
* @apiSuccess {String[]} categories Ticket categories the user has access to. If the user is an admin, this list has one element: ""
* @apiSuccess {Integer} afterReply Action to perform after replying to a ticket:<br>
* `0` - Show the ticket I just replied to<br>
@ -55,6 +54,11 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* @apiSuccess {String} rating The overall rating of the user, as a floating point decimal
* @apiSuccess {Integer} autorefresh The ticket table autorefresh time for the user, in milliseconds
* @apiSuccess {Boolean} active `true` if the user is active<br>`false` otherwise
* @apiSuccess {Integer} defaultCalendarView The default view displayed on the calendar screen:<br>
* `0` - Month<br>
* `1` - Week<br>
* `2` - Day<br>
* @apiSuccess {Boolean} notifyOverdueUnassigned Notify user of overdue tickets assigned to others / not assigned
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
@ -65,7 +69,6 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* "name": "Your name",
* "email": "mkoch227@gmail.com",
* "signature": "Sincerely,\r\n\r\nYour name\r\nYour website\r\nhttp://www.yourwebsite.com\r\n& < > ^ &",
* "language": null,
* "categories": [
* ""
* ],
@ -91,21 +94,28 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* "ratingPos": 0,
* "rating": "0",
* "autorefresh": 0,
* "active": true
* "active": true,
* "defaultCalendarView": 0,
* "notifyOverdueUnassigned": true
* }
*
* @apiError (noTokenProvided) 400 No `X-Auth-Token` was provided where it is required
* @apiError (invalidXAuthToken) 401 The `X-Auth-Token` provided was invalid
* @apiError (invalidXAuthToken) 401 The `X-Auth-Token` provided was invalid, or the user does not have the 'can_man_users' permission
*/
if ($request_method == 'GET') {
$token = get_header('X-Auth-Token');
$user = NULL;
try {
get_user_for_token($token, $hesk_settings);
$user = get_user_for_token($token, $hesk_settings);
} catch (AccessException $e) {
return http_response_code($e->getCode());
}
if (!$user['isadmin'] && strpos($user['heskprivileges'], 'can_man_users') === false) {
return http_response_code(401);
}
if (isset($_GET['id'])) {
$results = retrieve_user($hesk_settings, $_GET['id']);
} else {

@ -1,8 +1,12 @@
<?php
require_once(API_PATH . 'dao/ticket_dao.php');
function get_ticket_for_staff($hesk_settings, $id = NULL) {
$tickets = get_ticket_for_id($hesk_settings, $id);
function get_ticket_for_staff($hesk_settings, $user, $id = NULL) {
$tickets = get_ticket_for_id($hesk_settings, $user, $id);
if ($tickets == NULL) {
return NULL;
}
if ($id === NULL) {
$original_tickets = $tickets;
@ -10,10 +14,12 @@ function get_ticket_for_staff($hesk_settings, $id = NULL) {
foreach ($original_tickets as $ticket) {
$ticket = remove_common_properties($ticket);
$ticket = convert_to_camel_case($ticket);
$ticket = handle_dates($ticket);
$tickets[] = $ticket;
}
} else {
$tickets = remove_common_properties($tickets);
$tickets = handle_dates($tickets);
$tickets = convert_to_camel_case($tickets);
}
@ -36,27 +42,37 @@ function remove_common_properties($ticket) {
return $ticket;
}
function handle_dates($ticket) {
$ticket['dt'] = hesk_date($ticket['dt'], true);
return $ticket;
}
function convert_to_camel_case($ticket) {
if (isset($ticket['articles'])) {
$ticket['suggestedArticles'] = $ticket['articles'];
unset($ticket['articles']);
$ticket['legacyAuditTrail'] = $ticket['history'];
unset($ticket['history']);
$ticket['linkedTo'] = $ticket['parent'];
unset($ticket['parent']);
$ticket['timeWorked'] = $ticket['time_worked'];
unset($ticket['time_worked']);
$ticket['userAgent'] = $ticket['user_agent'];
unset($ticket['user_agent']);
$ticket['screenResolutionWidth'] = $ticket['screen_resolution_width'];
unset($ticket['screen_resolution_width']);
$ticket['screenResolutionHeight'] = $ticket['screen_resolution_height'];
unset($ticket['screen_resolution_height']);
}
$ticket['legacyAuditTrail'] = $ticket['history'];
unset($ticket['history']);
$ticket['linkedTo'] = $ticket['parent'];
unset($ticket['parent']);
$ticket['timeWorked'] = $ticket['time_worked'];
unset($ticket['time_worked']);
$ticket['userAgent'] = $ticket['user_agent'];
unset($ticket['user_agent']);
$ticket['screenResolutionWidth'] = $ticket['screen_resolution_width'];
unset($ticket['screen_resolution_width']);
$ticket['screenResolutionHeight'] = $ticket['screen_resolution_height'];
unset($ticket['screen_resolution_height']);
$ticket['trackingId'] = $ticket['trackid'];
unset($ticket['trackid']);
$ticket['dateCreated'] = $ticket['dt'];
unset($ticket['dt']);
$ticket['dueDate'] = $ticket['due_date'];
unset($ticket['due_date']);
$ticket['overdueEmailSent'] = $ticket['overdue_email_sent'];
return $ticket;
}
@ -83,6 +99,8 @@ function remove_staff_specific_properties($ticket) {
unset($ticket['screen_resolution_width']);
unset($ticket['screen_resolution_height']);
unset($ticket['parent']);
unset($ticket['due_date']);
unset($ticket['overdue_email_sent']);
return $ticket;
}

@ -68,6 +68,10 @@ function convert_to_camel_case($user) {
unset($user['ratingpos']);
$user['heskPrivileges'] = $user['heskprivileges'];
unset($user['heskprivileges']);
$user['defaultCalendarView'] = $user['default_calendar_view'];
unset($user['default_calendar_view']);
$user['notifyOverdueUnassigned'] = $user['notify_overdue_unassigned'];
unset($user['notify_overdue_unassigned']);
return $user;
}

@ -5,8 +5,8 @@
*
*/
/**
* @apiDefine protected Protected
* A protected API can only be utilized by those with a valid `X-Auth-Token`.
* @apiDefine protected Protected (Any)
* A protected API can only be utilized by any user with a valid `X-Auth-Token`.
*/
/**
* @apiDefine invalidXAuthToken 401 Unauthorized
@ -15,4 +15,7 @@
/**
* @apiDefine noTokenProvided 400 Bad Request
* No `X-Auth-Token` was provided.
*
* @apiDefine canManUsers Protected (Can Manage Users)
* A protected API can only be utilized by users with a valid `X-Auth-Token` and have the 'can_man_users' permission (or is an admin)
*/

@ -1,9 +1,22 @@
<?php
function get_ticket_for_id($hesk_settings, $id = NULL) {
$sql = "SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` ";
function get_ticket_for_id($hesk_settings, $user, $id = NULL) {
$sql = "SELECT `tickets`.* FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` AS `tickets` ";
$sql .= "INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` AS `users` ON `users`.`id` = " . intval($user['id']) . " ";
$used_where_clause = false;
if ($id != NULL) {
$sql .= "WHERE `id` = ".intval($id);
$used_where_clause = true;
$sql .= "WHERE `tickets`.`id` = " . intval($id);
}
if (!$user['isadmin']) {
$clause = $used_where_clause ? ' AND ' : ' WHERE ';
$used_where_clause = true;
$sql .= $clause . ' `category` IN (' . $user['categories'] . ')';
$sql .= " AND ((`heskprivileges` LIKE '%can_view_tickets%' AND `owner` = " . intval($user['id']) . ")";
$sql .= " OR (`heskprivileges` LIKE '%can_view_unassigned%' AND `owner` = 0)";
$sql .= " OR (`heskprivileges` LIKE '%can_view_ass_others%' AND `owner` <> " . intval($user['id']) . "))";
}
$response = hesk_dbQuery($sql);
@ -32,6 +45,7 @@ function build_results($response) {
$row['screen_resolution_width'] = convert_to_int($row['screen_resolution_width']);
$row['owner'] = convert_to_int($row['owner']);
$row['parent'] = convert_to_int($row['parent']);
$row['overdue_email_sent'] = $row['overdue_email_sent'] == true;
$results[] = $row;

@ -36,6 +36,8 @@ function get_user($hesk_settings, $id = NULL) {
$row['ratingpos'] = intval($row['ratingpos']);
$row['autorefresh'] = intval($row['autorefresh']);
$row['active'] = get_boolean($row['active']);
$row['default_calendar_view'] = intval($row['default_calendar_view']);
$row['notify_overdue_unassigned'] = get_boolean($row['notify_overdue_unassigned']);
// TODO: Remove this once GitHub #346 is complete

@ -78,7 +78,7 @@ $request_method = $_SERVER['REQUEST_METHOD'];
* "custom18": "",
* "custom19": "",
* "custom20": "",
* "html": false,
* "html": false
* }
*
* @apiError (noTokenProvided) 400 No `X-Auth-Token` was provided where it is required

@ -4,15 +4,23 @@ define('HESK_PATH', '../../../');
define('INTERNAL_API_PATH', '../../');
require_once(HESK_PATH . 'hesk_settings.inc.php');
require_once(HESK_PATH . 'inc/common.inc.php');
require_once(HESK_PATH . 'inc/admin_functions.inc.php');
require_once(INTERNAL_API_PATH . 'core/output.php');
require_once(INTERNAL_API_PATH . 'dao/api_authentication_dao.php');
hesk_session_start();
hesk_load_internal_api_database_functions();
hesk_dbConnect();
// Routing
$request_method = $_SERVER['REQUEST_METHOD'];
if ($request_method == 'POST') {
if (!isset($_SESSION['heskprivileges']) || !hesk_checkPermission('can_man_settings', 0)) {
print_error('Access Denied', 'Access Denied!');
return http_response_code(401);
}
$user_id = $_POST['userId'];
$action = $_POST['action'];

@ -4,12 +4,19 @@ define('HESK_PATH', '../../../');
define('INTERNAL_API_PATH', '../../');
require_once(HESK_PATH . 'hesk_settings.inc.php');
require_once(HESK_PATH . 'inc/common.inc.php');
require_once(HESK_PATH . 'inc/admin_functions.inc.php');
require_once(INTERNAL_API_PATH . 'core/output.php');
require_once(INTERNAL_API_PATH . 'dao/settings_dao.php');
hesk_session_start();
hesk_load_internal_api_database_functions();
hesk_dbConnect();
if (!isset($_SESSION['heskprivileges']) || !hesk_checkPermission('can_man_settings', 0)) {
print_error('Access Denied', 'Access Denied!');
return http_response_code(401);
}
// Routing
$request_method = $_SERVER['REQUEST_METHOD'];
if ($request_method == 'POST') {

@ -24,6 +24,11 @@ if ($request_method === 'GET') {
return output($events);
} elseif ($request_method === 'POST') {
if ($request_method !== 'update-ticket' && !hesk_checkPermission('can_man_calendar', 0)) {
print_error('Access Denied', 'Access Denied!');
return http_response_code(401);
}
$action = hesk_POST('action');
if ($action === 'create') {

Loading…
Cancel
Save