Skip to content
Snippets Groups Projects
Commit 7f2d6a61 authored by totten's avatar totten
Browse files

CRM-12613 - Forward port REST.php

This file had been held back from normal merge-forward due to
merge-conflicts.  Investigating upstream/master, it seems that there were
two changes that may have been source of conflict:

 * 2ede60ec - This is formatting change and a bad-commit of a debug code
 * c5f77b41 - This is a real functional change but was backported (and
   further fixed) in 4.3, so 4.3's version is better.

----------------------------------------
* CRM-12613: Resolve merge of REST.php (4.3=>master)
  http://issues.civicrm.org/jira/browse/CRM-12613
parent 5c21350f
No related branches found
No related tags found
No related merge requests found
......@@ -66,53 +66,13 @@ class CRM_Utils_REST {
* @return string $var
* @access public
*/
public function ping($var = NULL) {
public static function ping($var = NULL) {
$session = CRM_Core_Session::singleton();
$key = $session->get('key');
//$session->set( 'key', $var );
return self::simple(array('message' => "PONG: $key"));
}
/**
* Authentication wrapper to the UF Class
*
* @param string $name Login name
* @param string $pass Password
*
* @return string The REST Client key
* @access public
* @static
*/
public function authenticate($name, $pass) {
$result = CRM_Utils_System::authenticate($name, $pass);
if (empty($result)) {
return self::error('Could not authenticate user, invalid name or password.');
}
$session = CRM_Core_Session::singleton();
$api_key = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $result[0], 'api_key');
if (empty($api_key)) {
// These two lines can be used to set the initial value of the key. A better means is needed.
//CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Contact', $result[0], 'api_key', sha1($result[2]) );
//$api_key = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $result[0], 'api_key');
return self::error("This user does not have a valid API key in the database, and therefore cannot authenticate through this interface");
}
// Test to see if I can pull the data I need, since I know I have a good value.
$user = &CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $api_key, 'id', $api_key);
$session->set('api_key', $api_key);
$session->set('key', $result[2]);
$session->set('rest_time', time());
$session->set('PHPSESSID', session_id());
$session->set('cms_user_id', $result[1]);
return self::simple(array('api_key' => $api_key, 'PHPSESSID' => session_id(), 'key' => sha1($result[2])));
}
// Generates values needed for error messages
static function error($message = 'Unknown Error') {
$values = array(
......@@ -134,6 +94,14 @@ class CRM_Utils_REST {
return self::output($result);
}
function bootAndRun() {
$response = $this->loadCMSBootstrap();
if (is_array($response)) {
return self::output($response);
}
return $this->run();
}
static function output(&$result) {
$hier = FALSE;
if (is_scalar($result)) {
......@@ -284,32 +252,26 @@ class CRM_Utils_REST {
}
// If the query string is malformed, reject the request.
if ((count($args) != 3) && ($args[1] != 'login') && ($args[1] != 'ping')) {
// Does this mean it will reject it
if ((count($args) != 3) && ($args[1] != 'ping')) {
return self::error('Unknown function invocation.');
}
$store = NULL;
if ($args[1] == 'login') {
$name = CRM_Utils_Request::retrieve('name', 'String', $store, FALSE, NULL, 'REQUEST');
$pass = CRM_Utils_Request::retrieve('pass', 'String', $store, FALSE, NULL, 'REQUEST');
if (empty($name) ||
empty($pass)
) {
return self::error('Invalid name / password.');
}
return self::authenticate($name, $pass);
}
elseif ($args[1] == 'ping') {
if ($args[1] == 'ping') {
return self::ping();
}
}
else {
} else {
// or the new format (entity+action)
$args = array();
$args[0] = 'civicrm';
$args[1] = CRM_Utils_array::value('entity', $_REQUEST);
$args[2] = CRM_Utils_array::value('action', $_REQUEST);
}
// Everyone should be required to provide the server key, so the whole
// interface can be disabled in more change to the configuration file.
// This used to be done in the authenticate function, but that was bad...trust me
// first check for civicrm site key
if (!CRM_Utils_System::authenticateKey(FALSE)) {
$docLink = CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
......@@ -321,38 +283,22 @@ class CRM_Utils_REST {
}
// At this point we know we are not calling either login or ping (neither of which
// require authentication prior to being called. Therefore, at this point we need
// to make sure we're working with a trusted user.
// There are two ways to check for a trusted user:
// First: they can be someone that has a valid session currently
// Second: they can be someone that has provided an API_Key
// At this point we know we are not calling ping which does not require authentication.
// Therefore, at this point we need to make sure we're working with a trusted user.
// Valid users are those who provide a valid server key and API key
$valid_user = FALSE;
// Check for valid session. Session ID's only appear here if you have
// run the rest_api login function. That might be a problem for the
// AJAX methods.
$session = CRM_Core_Session::singleton();
if ($session->get('PHPSESSID')) {
$valid_user = TRUE;
}
// If the user does not have a valid session (most likely to be used by people using
// an ajax interface), we need to check to see if they are carring a valid user's
// secret key.
if (!$valid_user) {
$api_key = CRM_Utils_Request::retrieve('api_key', 'String', $store, FALSE, NULL, 'REQUEST');
if (!$api_key || strtolower($api_key) == 'null') {
return ("FATAL:mandatory param 'api_key' (user key) missing");
}
$valid_user = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $api_key, 'id', 'api_key');
// Check and see if a valid secret API key is provided.
$api_key = CRM_Utils_Request::retrieve('api_key', 'String', $store, FALSE, NULL, 'REQUEST');
if (!$api_key || strtolower($api_key) == 'null') {
return self::error("FATAL: mandatory param 'api_key' (user key) missing");
}
$valid_user = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $api_key, 'id', 'api_key');
// If we didn't find a valid user either way, then die.
// If we didn't find a valid user, die
if (empty($valid_user)) {
return self::error("Invalid session or user api_key invalid");
return self::error("User API key invalid");
}
return self::process($args);
......@@ -536,11 +482,9 @@ class CRM_Utils_REST {
**/
static function ajaxJson() {
require_once 'api/v3/utils.php';
if (!$config->debug &&
(!array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) ||
if (!$config->debug && (!array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) ||
$_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest"
)
) {
)) {
$error = civicrm_api3_create_error("SECURITY ALERT: Ajax requests can only be issued by javascript clients, eg. CRM.api().",
array(
'IP' => $_SERVER['REMOTE_ADDR'],
......@@ -592,7 +536,7 @@ class CRM_Utils_REST {
// restrict calls to this etc
// the request has to be sent by an ajax call. First line of protection against csrf
$config = CRM_Core_Config::singleton();
if (0 && !$config->debug &&
if (!$config->debug &&
(!array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) ||
$_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest"
)
......@@ -640,50 +584,42 @@ class CRM_Utils_REST {
CRM_Utils_System::civiExit();
}
/**
* @return array|NULL NULL if execution should proceed; array if the response is already known
*/
function loadCMSBootstrap() {
$q = CRM_Utils_array::value('q', $_REQUEST);
$args = explode('/', $q);
// If no 'q' parameter is provided, try to populate args
// with entity and action (API v3)
if ( empty($args) || $args[0] == '' ) {
$entity = CRM_Utils_array::value( 'entity', $_REQUEST );
$action = CRM_Utils_array::value( 'action', $_REQUEST );
if (($entity !== null) && ($action !== null)) {
$args[0] = 'civicrm';
$args[1] = $entity;
$args[2] = $action;
}
}
// If the function isn't in the civicrm namespace or request
// is for login or ping
if (empty($args) || $args[0] != 'civicrm' ||
((count($args) != 3) && ($args[1] != 'login') && ($args[1] != 'ping')) ||
$args[1] == 'ping'
) {
return;
// Proceed with bootstrap for "?entity=X&action=Y"
// Proceed with bootstrap for "?q=civicrm/X/Y" but not "?q=civicrm/ping"
if (!empty($q)) {
if (count($args) == 2 && $args[1] == 'ping') {
return NULL; // this is pretty wonky but maybe there's some reason I can't see
}
if (count($args) != 3) {
return self::error('ERROR: Malformed REST path');
}
if ($args[0] != 'civicrm') {
return self::error('ERROR: Malformed REST path');
}
// Therefore we have reasonably well-formed "?q=civicrm/X/Y"
}
if (!CRM_Utils_System::authenticateKey(FALSE)) {
return;
}
if ($args[1] == 'login') {
CRM_Utils_System::loadBootStrap(CRM_Core_DAO::$_nullArray, TRUE, FALSE);
return;
// FIXME: At time of writing, this doesn't actually do anything because
// authenticateKey abends, but that's a bad behavior which sends a
// malformed response.
return self::error('Failed to authenticate key');
}
$uid = NULL;
$session = CRM_Core_Session::singleton();
if ($session->get('PHPSESSID') && $session->get('cms_user_id')) {
$uid = $session->get('cms_user_id');
}
if (!$uid) {
$store = NULL;
$api_key = CRM_Utils_Request::retrieve('api_key', 'String', $store, FALSE, NULL, 'REQUEST');
if (empty($api_key)) {
return self::error("FATAL: mandatory param 'api_key' (user key) missing");
}
$contact_id = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $api_key, 'id', 'api_key');
if ($contact_id) {
$uid = CRM_Core_BAO_UFMatch::getUFId($contact_id);
......@@ -692,6 +628,10 @@ class CRM_Utils_REST {
if ($uid) {
CRM_Utils_System::loadBootStrap(array('uid' => $uid), TRUE, FALSE);
return NULL;
}
else {
return self::error('ERROR: No CMS user associated with given api-key');
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment