diff --git a/html/extrest/.htaccess b/html/extrest/.htaccess deleted file mode 100644 index f973c69e0b..0000000000 --- a/html/extrest/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ -RewriteEngine On - -RewriteRule (.*) index.php [L] \ No newline at end of file diff --git a/html/extrest/.htaccess_maintenance b/html/extrest/.htaccess_maintenance deleted file mode 100644 index dd3fa0a2e8..0000000000 --- a/html/extrest/.htaccess_maintenance +++ /dev/null @@ -1,3 +0,0 @@ -RewriteEngine On - -RewriteRule ^(.*)$ maintenance.php \ No newline at end of file diff --git a/html/extrest/.htaccess_production b/html/extrest/.htaccess_production deleted file mode 100644 index f973c69e0b..0000000000 --- a/html/extrest/.htaccess_production +++ /dev/null @@ -1,3 +0,0 @@ -RewriteEngine On - -RewriteRule (.*) index.php [L] \ No newline at end of file diff --git a/html/extrest/index.php b/html/extrest/index.php deleted file mode 100644 index 70ab20d6ad..0000000000 --- a/html/extrest/index.php +++ /dev/null @@ -1,135 +0,0 @@ - 0644); - - $access_logfile = LOG_DIR . "/" . xd_utilities\getConfiguration('general', 'extrest_access_logfile'); - - $access_logger = Log::factory('file', $access_logfile, 'REST', $logConf); - - // ------------ - - $exception_logfile = LOG_DIR . "/" . xd_utilities\getConfiguration('general', 'extrest_exception_logfile'); - - $exception_logger = Log::factory('file', $exception_logfile, 'REST', $logConf); - - // ----------------------------------------------------------- - - // Clean up request URI (e.g. /extrest/realm/category/action --> realm/category/action) - - $request_uri = preg_replace('/^\/extrest\//', '', $_SERVER['REQUEST_URI']); - - - // Acquire distinguished names from both subject (client / requestor) and the issuer (server) - // Prohibit access if there is a problem retrieving either DN - - $subject_dn = isset($_SERVER['SSL_CLIENT_S_DN']) ? $_SERVER['SSL_CLIENT_S_DN'] : ''; - $issuer_dn = isset($_SERVER['SSL_CLIENT_I_DN']) ? $_SERVER['SSL_CLIENT_I_DN'] : ''; - - if (empty($subject_dn) || empty($issuer_dn)) { - - $exception_logger->log($_SERVER['REMOTE_ADDR'].' -- invalid_handshake -- '.$request_uri); - - print "Invalid handshake"; - exit; - - }//if (empty($subject_dn) || empty($issuer_dn)) - - // ----------------------------------------------------------- - - $cert_details = array(); - - try { - - // If the subject DN is not recognized by us, an exception will be thrown... - - $cert_details = resolveDistinguishedName($subject_dn); - - $access_logger->log($_SERVER['REMOTE_ADDR']." -- {$cert_details['description']} -- ".$request_uri); - - - // Parse the URI here so key-value pairs can be appended to the REST response - - $parser = new RestParser(); - $request = $parser->parseRequest($request_uri); - - - // Make an internal REST call, passing in the API key - - $response = Rest::internalRequest($request_uri, array(), NULL, $cert_details['api_key']); - - $response['action'] = $request->getAction(); - - - // The internal request, if successful, will return an array. At this point, it is the - // responsibility of this front controller to render a response into the appropriate - // output format. - - $rest_response = RestResponse::factory($response); - - $response = $rest_response->{$request->getOutputFormat()}()->render(); - - print $response; - - } - catch(Exception $e) { - - $response['success'] = false; - $response['message'] = $e->getMessage().EXCEPTION_MESSAGE_SUFFIX; - - if (isset($cert_details['description'])) { - $exception_logger->log($_SERVER['REMOTE_ADDR']." -- {$cert_details['description']} -- {$e->getMessage()} -- ".$request_uri); - } - else { - $exception_logger->log($_SERVER['REMOTE_ADDR']." -- {$e->getMessage()} -- ".$request_uri); - } - - // It is important that this message be textual (a RAW format is not entirely - // reliable in this case, so use JSON). - - // Rendering has failed nonetheless, so present the error in a 'reliable' format - // (using json_encode) - - print json_encode($response); - - }//try/catch - - // ----------------------------------------------------------- - // - // @function resolveDistinguishedName - // @description Provided a DN, retrieve additional information from the database (provided the DN was registered with us) - // - // @param $dn type: STRING (The distinguished name to be looked up) - // - // @returns an associative array containing the description and api key mapped to the DN - // @throws an exception if the DN supplied cannot be mapped - // - // ----------------------------------------------------------- - - function resolveDistinguishedName($dn) { - - $pdo = DB::factory('database'); - - $results = $pdo->query("SELECT description, api_key FROM RESTx509 WHERE distinguished_name=:dn", array('dn' => $dn)); - - if (count($results) == 0) { - throw new Exception('DN not registered'); - } - - return $results[0]; - - }//resolveDistinguishedName - -?> diff --git a/html/extrest/maintenance.php b/html/extrest/maintenance.php deleted file mode 100644 index c1cfcc8f2a..0000000000 --- a/html/extrest/maintenance.php +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/html/rest/legacy_router.php b/html/rest/legacy_router.php deleted file mode 100644 index 897307500d..0000000000 --- a/html/rest/legacy_router.php +++ /dev/null @@ -1,317 +0,0 @@ - 0644); -$logger = Log::factory('file', $logfile, 'REST', $logConf); - -$general_logfile = LOG_DIR . "/" . xd_utilities\getConfiguration('general', 'rest_general_logfile'); - -$generalAccessLogger = Log::factory('file', $general_logfile, 'REST', $logConf); - - -$response = array(); -$parser = new RestParser(); -$request = NULL; - -// ============================================================================================ - -$service_handler_start_time = microtime(true); - -$logged_request_uri = cleanURL($_SERVER['REQUEST_URI']); - -try { - -// Break REST query (URL) into its constituent components .. - - $request = $parser->parseRequest(); - - $token = $request->getToken(); - - if (!empty($token)) { - - // If a token has been specified... - - try { - - $user = XDSessionManager::resolveUserFromToken($request); - $rest_caller = 'token_mapped_to_'; - $rest_caller .= ($user->isXSEDEUser() == true) ? $user->getXSEDEUsername().'_xsede' : $user->getUsername(); - - } - catch(\Exception $e) { - - // All exceptions thrown on behalf of XDSessionManager::resolveUserFromToken(...) indicate that the - // token supplied to the REST call was invalid. - - $rest_caller = 'invalid_token'; - - } - - } - else { - - // A token was never specified in the REST call to begin with - - $rest_caller = 'no_token'; - - } - - //$generalAccessLogger->log($_SERVER['REMOTE_ADDR']." $rest_caller ".$logged_request_uri); - - /* - print 'Realm: '.$request->getRealm()."
\n"; - print 'Category: '.$request->getCategory()."
\n"; - print 'Action: '.$request->getAction()."
\n"; - print 'Action Args: '.$request->getActionArguments()."
\n"; - print 'Output Format: '.$request->getOutputFormat()."
\n"; - print 'Token: '.$request->getToken()."
\n"; - */ - - try { - - $handler = RestHandler::factory($request); - - // Attempt to route the request to the proper class residing in the proper namespace - - $category_obj_ref = $handler->{$request->getCategory()}(); - - $arguments = explode('/', $request->getActionArguments()); - - if ($arguments[0] == 'help') { - $category_obj_ref = $category_obj_ref->help(); - } - - // Any exceptions thrown by the action will propogate back up to the front controller, - // and trip the catch { .. } block below. - - $response = $category_obj_ref->{$request->getAction()}(); - - } - catch (\Exception $e) { - - // REASONS FOR ENTERING THIS CATCH { ... } BLOCK: - // (1) There was an issue finding the proper action (function) to invoke. - // (2) The action itself, if found, threw an exception. - - // In this case, parsing of the request succeeded, so allow the response to - // propogate to the logic below in order to present the information in the format - // the caller requested (or use the default format if no recognizable format was - // explicitly provided in the call). - - $logger->log(generateLogMsg($e), PEAR_LOG_ERR); - - // If a SessionExpiredException was thrown, allow the global exception - // handler to process it. There should not be session-checking code in the - // REST API, but the browser client depends on it currently. - if ($e instanceof \SessionExpiredException) { - logTimestamps('FAIL', 'session_expired_exception'); - throw $e; - } - - // If a custom exception was throw, allow the global exception handler - // to process it. - if ($e instanceof \XDException) { - throw $e; - } - - $response['success'] = false; - $response['message'] = $e->getMessage().EXCEPTION_MESSAGE_SUFFIX; - - } // try - -} -catch(\Exception $e) { - - // If a custom exception was thrown, allow the global exception - // handler to process it. - if ($e instanceof \XDException) { - throw $e; - } - - logTimestamps('FAIL', 'parse_exception'); - - // There was an issue parsing the request. Since parsing failed, there is no - // way to determine what return format the end-user wanted -- in this case, - // the default format (JSON) is provided - - $response['success'] = false; - $response['message'] = $e->getMessage().EXCEPTION_MESSAGE_SUFFIX; - - $msg = generateLogMsg($e, "Error parsing request"); - - $logger->log($msg, PEAR_LOG_ERR); - - print json_encode($response); - exit; - -} // try - -// ---------------------------------------------------------------------- - -// At this point, the appropriate handler for the request has been reached, and -// it is now time to analyze and present the response ... - -// Append the action name to the response (which can be used by the caller) - -$response['action'] = $request->getAction(); - -try { - - $rest_response = RestResponse::factory($response); - - $response = $rest_response->{$request->getOutputFormat()}()->render(); - - logTimestamps('SUCCESS'); - - print $response; - -} -catch(\Exception $e) { - - logTimestamps('FAIL', 'response_render_exception'); - - $logger->log(generateLogMsg($e, "Handler error"), PEAR_LOG_ERR); - - // If a SessionExpiredException was thrown, allow the global exception - // handler to process it. There should not be session-checking code in the - // REST API, but the browser client depends on it currently. - if ($e instanceof \SessionExpiredException) { - throw $e; - } - - $response['success'] = false; - - $response['message'] = $e->getMessage().EXCEPTION_MESSAGE_SUFFIX; - - // It is important that this message be textual (a RAW format is not entirely - // reliable in this case, so use JSON). - - // Rendering has failed nonetheless, so present the error in a 'reliable' format - // (using json_encode) - - print json_encode($response); - -} // try - -// -------------------------------------------------------------------------------- -// Generate a log message based on the REST request, exception, and an optional -// message. -// -// @param $request A RestElements object containing the request information -// @param $e An Exception object -// @param $msg An optional message to log -// -// @returns A formatted log string with individual elements separated by -// semi-colons. -// -------------------------------------------------------------------------------- - -function generateLogMsg(\Exception $e, $msg = NULL) { - - $logMsg = array(); - $logMsg[] = $_SERVER['REMOTE_ADDR']; //old: $request->getIPAddress(); - $logMsg[] = $_SERVER['REQUEST_URI']; // old: cleanURL($request->getUrl()); - - $t = $e->getTrace(); - - if ( is_array($t) && count($t) > 0 ) { - $t = array_shift($t); - if ( array_key_exists('file', $t) ) - $logMsg[] = $t['file'] . "::" . $t['function'] . "() (line " . $t['line'] . ")"; - } - - $logMsg[] = ( NULL !== $msg ? $msg . ": " : "" ) . $e->getMessage(); - - return implode("; ", $logMsg); - -}//generateLogMsg() - -// -------------------------------------------------------------------------------- - -// @function cleanURL - -// @description It is critical that any logged REST calls are not storing passwords in plain-text. Should a user make the mistake of passing parameters in the URL -// (as opposed to POSTing them), the following will process the request URI and render a suitable URI for logging purposes (removing any sensitive data -// should it exist). -// -// @param $url type: STRING (the URL to be processed) -// -// @returns a STRING representing the URL devoid of any sensitive information -// -// -------------------------------------------------------------------------------- - -function cleanURL($url) { - - $uri_components = explode('/', $url); - - $uri_components_mod = array(); - - foreach($uri_components as $component) { - - $uri_components_mod[] = preg_replace('/password=(.+)/', 'password=...', $component); - - }//foreach - - return implode('/', $uri_components_mod); - -}//cleanURL - -// -------------------------------------------------------------------------------- - -// @function logTimestamps - -// @description records request status and execution timestamps to general log file -// -// @param $status type: STRING (the status of the request) -// @param $reason type: STRING [optional] (the reason as to why the request failed or succeeded) -// -// -// -------------------------------------------------------------------------------- - -function logTimestamps($status, $reason = '') { - - global $service_handler_start_time; - global $generalAccessLogger; - global $logged_request_uri; - global $rest_caller; - - $service_handler_end_time = microtime(true); - $service_handler_turnaround = $service_handler_end_time - $service_handler_start_time; - - if (!empty($reason)){ $reason = " REASON=$reason"; } - - $generalAccessLogger->log($_SERVER['REMOTE_ADDR']." REQUEST CALLER=$rest_caller ENDPOINT=$logged_request_uri STATUS=$status$reason START=$service_handler_start_time END=$service_handler_end_time DELTA=$service_handler_turnaround"); - -}//logTimestamps - -?> diff --git a/libraries/rest.php b/libraries/rest.php index aea6c490fd..0f1c14daf2 100644 --- a/libraries/rest.php +++ b/libraries/rest.php @@ -5,291 +5,6 @@ namespace xd_rest; -/** - * To account for port changes when reverting from HTTP to HTTPS. - */ -function resolveSecurePort($port) -{ - switch($port) { - // Secure (HTTPS) - case ':9444': - // Non-Secure (HTTP) - return ':9001'; - } - - return $port; -} - -/** - * Returns a string which gets appended to REST-related exceptions - */ -function getExceptionMessageSuffix() -{ - $tech_support_recipient = \xd_utilities\getConfiguration( - 'general', - 'tech_support_recipient' - ); - - return '. If you require assistance, please contact the XDMoD team at ' - . $tech_support_recipient; -} - -/** - * Use retrospection to enumerate a list of valid response formats based - * on what is publicly defined in RestResponse. To disable a format - * from being used, set the visibility of the respective function - * (e.g. jsonFormat) to non-public (e.g. 'private', 'protected', etc.) - */ -function enumerateOutputFormats() -{ - $reflection = new \ReflectionClass('RestResponse'); - $allResponseMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); - - $filteredResponseMethods = array_filter( - $allResponseMethods, - function ($element) { - return preg_match('/^(.+)Format$/', $element->name); - } - ); - - $validFormats = array(); - - // Create a reference to a (dummy) RestResponse object so that the - // description found in the help() functions for each of the - // supported formats can be retrieved. - $r = \RestResponse::factory(array()); - - foreach ($filteredResponseMethods as $f) { - - // The user should not be able to explicitly request 'raw', as - // all request handlers may not explicitly provide a - // content-type - if ($f->name != 'rawFormat') { - $formatName = substr($f->name, 0, -6); - - // TODO: Account for cases where the xxxxxHelp() function - // does not exist (assumption is being made at this point) - - $validFormats[$formatName] = $r->{$formatName . 'Help'}(); - } - } - - return $validFormats; -} - -/** - * Determine the RAW types supported by the REST framework - */ -function enumerateRAWFormats() -{ - $raw_types = array(); - - $raw_formats_dir = REST_BASE_DIRECTORY . 'raw_formats/'; - - if ($dh = opendir($raw_formats_dir)) { - while (($file = readdir($dh)) !== false) { - if ($file == '.' || $file == '..' || $file == '.svn') { - continue; - } - - require_once($raw_formats_dir . $file); - - $formatClass = substr($file, 0, -4); - - $class = new \ReflectionClass($formatClass); - - if ($class->implementsInterface('iBinaryFormat')) { - $obj_format = new $formatClass(); - $raw_types[$obj_format->toString()] = $obj_format->getDescription(); - } - } - - closedir($dh); - } - - return $raw_types; -} - -/** - * Retrieve a listing of the realms recognized by the REST service - */ -function enumerateRealms() -{ - $realms = array(); - - $directories_to_ignore = array('.svn', '.', '..', 'raw_formats'); - - if (is_dir(REST_BASE_DIRECTORY)) { - if ($dh = opendir(REST_BASE_DIRECTORY)) { - while (($file = readdir($dh)) !== false) { - if (filetype(REST_BASE_DIRECTORY . $file) == 'dir' && !in_array($file, $directories_to_ignore) && isUniqueRealm($file)) { - $realms[] = $file; - } - } - - closedir($dh); - } - } - - return $realms; -} - -/** - * Retrieve a listing of the realms recognized by the REST service - */ -function enumerateCategories($realm) -{ - $realmDir = REST_BASE_DIRECTORY . $realm; - - $categories = array(); - - if ($dh = opendir($realmDir)) { - while (($file = readdir($dh)) !== false) { - if (filetype($realmDir . '/' . $file) == 'file' && substr($file, -4) == '.php') { - $relativeClassName = substr($file, 0, -4); - $categories[] = $relativeClassName; - } - } - - closedir($dh); - } - - return $categories; -} - -/** - * Retrieve a listing of the actions for a particular realm and category - */ -function enumerateActions($realm, $category) -{ - require_once REST_BASE_DIRECTORY . "$realm/$category.php"; - - $reflection = new \ReflectionClass($realm . '\\' . $category); - - $methods = $reflection->getMethods(); - - // Only consider method names with 'Action' as their suffix - - $actionMethods = array_filter( - $methods, - function ($element) { - return preg_match('/^(.+)Action$/', $element->name); - } - ); - - $actions = array(); - - foreach ($actionMethods as $action) { - $actionName = preg_replace('/^(.+)Action$/', '\1', $action->name); - - if (!$reflection->hasMethod($actionName . "Visibility")) { - $actions[] = $actionName; - } - } - - return $actions; -} - -/** - * Used primarily by the REST Catalog, resolveEntity analyzes a user - * specified entity, checking against available realms, respective - * categories, and respective actions for a match. - */ -function resolveEntity($entity, $type, $realm = "", $category = "") -{ - $pool = array(); - - switch ($type) { - case REST_REALM: - $pool = enumerateRealms(); - break; - case REST_CATEGORY: - if (empty($realm)){ - throw new \Exception('A realm must be specified for any calls to resolveEntity with REST_CATEGORY passed as an argument for type'); - } - $pool = enumerateCategories($realm); - break; - case REST_ACTION: - if (empty($realm)){ - throw new \Exception('A realm must be specified for any calls to resolveEntity with REST_ACTION passed as an argument for type'); - } - if (empty($category)){ - throw new \Exception('A category must be specified for any calls to resolveEntity with REST_ACTION passed as an argument for type'); - } - $pool = enumerateActions($realm, $category); - break; - default: - throw new \Exception('Unknown REST entity type passed to resolveEntity'); - break; - } - - $index = array_search(strtolower($entity), array_map('strtolower', $pool)); - - if ($index === false) { - throw new \Exception("Unable to resolve REST entity '$entity'"); - } - - return $pool[$index]; -} - -/** - * Is a realm unique? - */ -function isUniqueRealm($realmName) -{ - try { - $directory = resolveRealm($realmName); - return true; - } catch(\Exception $ex) { - return false; - } -} - -/** - * Resolve a realm. - */ -function resolveRealm($realmName) -{ - - // The backend employs a file system which uses a case-sensitive - // naming scheme. Therefore, it is possible for multiple - // directories to have the same alphabetical name (due to multiple - // combinations of 'character case'). This ambiguity makes it - // difficult to determine which specific directory to use as the - // implementation for the realm being considered. - - // resolveRealm determines the directory to use as the - // implementation for the supplied realm name, accounting for - // ambiguity. - - $directories_to_ignore = array('.svn', '.', '..', 'raw_formats'); - - $input_realm_lower = strtolower($realmName); - $realm_dir = ''; - - if ($dh = opendir(REST_BASE_DIRECTORY)) { - while (($file = readdir($dh)) !== false) { - if (filetype(REST_BASE_DIRECTORY . $file) == 'dir' && !in_array($file, $directories_to_ignore)) { - if ($input_realm_lower == strtolower($file)) { - if (empty($realm_dir)){ - $realm_dir = $file; - } else { - throw new \Exception("Ambiguity: unable to resolve realm handler for '$realmName'"); - } - } - } - } - - closedir($dh); - } - - if (empty($realm_dir)) { - throw new \Exception("Unknown realm '$realmName'"); - } - - return $realm_dir; -} - /** * Get the user's REST token. *