예제 #1
0
 /**
  * validates all options that have been defined throwing rpc gateway faults if any of the
  * options fail to validate. see constant descriptions for what each constant does
  *
  * @error 14015
  * @param string $option expects the option name
  * @param null|mixed $value expects the options value
  * @throws Xapp_Rpc_Gateway_Exception
  * @throws Xapp_Rpc_Fault
  */
 protected function validate($option, $value = null)
 {
     $user = null;
     $option = strtoupper($option);
     switch ($option) {
         case self::BASIC_AUTH:
             if ($this->request()->has('PHP_AUTH_USER', 'SERVER') && $this->request()->has('PHP_AUTH_PW', 'SERVER') && isset($value[0]) && isset($value[1])) {
                 if ($this->server()->request()->getFrom('PHP_AUTH_USER', 'SERVER') !== $value[0] || $this->server()->request()->getFrom('PHP_AUTH_PW', 'SERVER') !== $value[1]) {
                     Xapp_Rpc_Fault::t("basic auth error - user or password not correct", array(1401501, -32001));
                 }
             } else {
                 Xapp_Rpc_Fault::t("basic auth error - credentials not set", array(1401502, -32002));
             }
             break;
         case self::ALLOW_IP:
             if (Xapp_Rpc_Request::getClientIp() !== null && !in_array(Xapp_Rpc_Request::getClientIp(), $value)) {
                 Xapp_Rpc_Fault::t("request denied from service", array(1401503, -32003));
             }
             break;
         case self::DENY_IP:
             if (Xapp_Rpc_Request::getClientIp() !== null && in_array(Xapp_Rpc_Request::getClientIp(), $value)) {
                 Xapp_Rpc_Fault::t("request denied from service", array(1401503, -32003));
             }
             break;
         case self::DISABLE:
             if ((bool) $value) {
                 Xapp_Rpc_Fault::t("gateway is disabled", array(1401504, -32004));
             }
             break;
         case self::DISABLE_SERVICE:
             if ($this->server()->hasServices()) {
                 foreach ($this->server()->getServices() as $service) {
                     if (preg_match(Xapp_Rpc::regex($value), $service)) {
                         Xapp_Rpc_Fault::t("requested service: {$service} is disabled", array(1401505, -32005));
                     }
                 }
             }
             break;
         case self::ALLOW_HOST:
             if (Xapp_Rpc_Request::getHost() !== null && !in_array(Xapp_Rpc_Request::getHost(), $value)) {
                 Xapp_Rpc_Fault::t("host denied from service", array(1401506, -32006));
             }
             break;
         case self::DENY_HOST:
             if (Xapp_Rpc_Request::getHost() !== null && in_array(Xapp_Rpc_Request::getHost(), $value)) {
                 Xapp_Rpc_Fault::t("host denied from service", array(1401506, -32006));
             }
             break;
         case self::FORCE_HTTPS:
             if ((bool) $value && Xapp_Rpc_Request::getScheme() !== 'HTTPS') {
                 Xapp_Rpc_Fault::t("request from none http secure host denied", array(1401507, -32007));
             }
             break;
         case self::ALLOW_USER_AGENT:
             if ($this->request()->has('HTTP_USER_AGENT', 'SERVER') && !preg_match('/(' . implode('|', trim($value, '()')) . ')/i', $this->request()->getFrom('HTTP_USER_AGENT', 'SERVER'))) {
                 Xapp_Rpc_Fault::t("client denied from service", array(1401508, -32008));
             }
             break;
         case self::DENY_USER_AGENT:
             if ($this->request()->has('HTTP_USER_AGENT', 'SERVER') && preg_match('/(' . implode('|', trim($value, '()')) . ')/i', $this->request()->getFrom('HTTP_USER_AGENT', 'SERVER'))) {
                 Xapp_Rpc_Fault::t("client denied from service", array(1401508, -32008));
             }
             break;
         case self::ALLOW_REFERER:
             if (Xapp_Rpc_Request::getReferer() !== null && !preg_match('/(' . implode('|', trim($value, '()')) . ')/i', Xapp_Rpc_Request::getReferer())) {
                 Xapp_Rpc_Fault::t("referer denied from service", array(1401509, -32009));
             }
             break;
         case self::SIGNED_REQUEST:
             if ((bool) $value) {
                 $tmp = array();
                 if (xapp_is_option(self::SIGNED_REQUEST_EXCLUDES, $this)) {
                     foreach ($this->server()->getServices() as $service) {
                         if (!preg_match(Xapp_Rpc::regex(xapp_get_option(self::SIGNED_REQUEST_EXCLUDES, $this)), $service)) {
                             $tmp[] = $service;
                         }
                     }
                 }
                 if (sizeof($tmp) > 0) {
                     $sign = $this->request()->getParam(xapp_get_option(self::SIGNED_REQUEST_SIGN_PARAM, $this), false);
                     $method = strtolower(xapp_get_option(self::SIGNED_REQUEST_METHOD, $this));
                     switch ($method) {
                         case 'host':
                             $user = $this->request()->getHost();
                             break;
                         case 'ip':
                             $user = $this->request()->getClientIp();
                             break;
                         case 'user':
                             $user = $this->request()->getParam(xapp_get_option(self::SIGNED_REQUEST_USER_PARAM, $this), false);
                             break;
                         default:
                             throw new Xapp_Rpc_Gateway_Exception(_("unsupported signed request user identification method"), 1401514);
                     }
                     if ($user === false || $user === null) {
                         Xapp_Rpc_Fault::t(vsprintf("signed request value for: %s not found in request", array(xapp_get_option(self::SIGNED_REQUEST_USER_PARAM, $this))), array(1401512, -32011));
                     }
                     if ($sign === false || $sign === null) {
                         Xapp_Rpc_Fault::t(vsprintf("signed request value for: %s not found in request", array(xapp_get_option(self::SIGNED_REQUEST_SIGN_PARAM, $this))), array(1401513, -32011));
                     }
                     $key = $this->getKey($user, null);
                     $params = $this->request()->getParams();
                     if (array_key_exists('xdmTarget', $params)) {
                         unset($params['xdmTarget']);
                     }
                     if (array_key_exists('view', $params)) {
                         unset($params['view']);
                     }
                     if (array_key_exists('xfToken', $params)) {
                         unset($params['xfToken']);
                     }
                     if (array_key_exists('time', $params)) {
                         unset($params['time']);
                     }
                     if (array_key_exists('xdm_e', $params)) {
                         unset($params['xdm_e']);
                     }
                     if (array_key_exists('user', $params)) {
                         unset($params['user']);
                     }
                     if (array_key_exists('xdm_c', $params)) {
                         unset($params['xdm_c']);
                     }
                     if (array_key_exists('xdm_p', $params)) {
                         unset($params['xdm_p']);
                     }
                     if (xapp_is_option(self::SIGNED_REQUEST_CALLBACK, $this)) {
                         if (!(bool) call_user_func_array(xapp_get_option(self::SIGNED_REQUEST_CALLBACK, $this), array($this->request(), $params, $key))) {
                             Xapp_Rpc_Fault::t("verifying signed request failed", array(1401510, -32010));
                         }
                     } else {
                         if ($key !== null) {
                             if (isset($params[xapp_get_option(self::SIGNED_REQUEST_SIGN_PARAM, $this)])) {
                                 unset($params[xapp_get_option(self::SIGNED_REQUEST_SIGN_PARAM, $this)]);
                             }
                             if ($sign !== self::sign($params, $key)) {
                                 Xapp_Rpc_Fault::t("verifying signed request failed", array(1401510, -32010));
                             }
                         } else {
                             throw new Xapp_Rpc_Gateway_Exception(_("user identification key must be set when using internal signed request verification"), 1401511);
                         }
                     }
                 }
             }
             break;
         default:
     }
 }
예제 #2
0
 private function setupRPC()
 {
     /***
      * We support JSONP for all services
      */
     $isJSONP = false;
     $hasJSONP = true;
     if ($hasJSONP) {
         $isJSONP = XApp_Service_Entry_Utils::isJSONP();
     }
     $method = $_SERVER['REQUEST_METHOD'];
     if ($method === 'POST') {
         $hasJSONP = false;
     }
     /***
      * Filtered methods
      */
     $ignoredRPCMethods = array('load', 'getObject', 'init', 'setup', 'log', 'onBeforeCall', 'onAfterCall', 'dumpObject', 'applyFilter', 'getLastJSONError', 'cleanUrl', 'rootUrl', 'siteUrl', 'getXCOption', 'getIndexer', 'getIndexOptions', 'getIndexOptions', 'indexDocument', 'onBeforeSearch', 'toDSURL', 'searchTest');
     if (xapp_get_option(self::IGNORED_RPC_METHODS, $this)) {
         $ignoredRPCMethods = array_merge(xapp_get_option(self::IGNORED_RPC_METHODS, $this), $ignoredRPCMethods);
     } elseif (xapp_has_option(self::AUTH_DELEGATE, $this)) {
         /***
          * Additional security here, mark each service method which has not been authorized by the
          * auth delegate as ignored!
          */
         $authDelegate = xapp_get_option(self::AUTH_DELEGATE, $this);
         if (method_exists($authDelegate, 'authorize')) {
             $xCommanderFunctionTable = XApp_Service_Entry_Utils::getXCommanderFuncTable();
             foreach ($xCommanderFunctionTable as $key => $value) {
                 if (!$authDelegate::authorize($value)) {
                     array_push($ignoredRPCMethods, $value);
                 }
             }
         }
     }
     $server = null;
     if ($hasJSONP && $isJSONP) {
         //Options for SMD based JSONP-RPC classes
         $opt = array(Xapp_Rpc_Smd::IGNORE_METHODS => $ignoredRPCMethods, Xapp_Rpc_Smd::IGNORE_PREFIXES => array('_', '__'));
         $smd = new Xapp_Rpc_Smd_Jsonp($opt);
         //Options for RPC server
         $opt = array(Xapp_Rpc_Server::ALLOW_FUNCTIONS => true, Xapp_Rpc_Server::APPLICATION_ERROR => false, Xapp_Rpc_Server::METHOD_AS_SERVICE => true, Xapp_Rpc_Server::DEBUG => XApp_Service_Entry_Utils::isDebug(), Xapp_Rpc_Server::SMD => $smd);
         $server = Xapp_Rpc::server(XApp_Service_Entry_Utils::isRaw() ? 'raw' : 'jsonp', $opt);
     } else {
         //Options for SMD based RPC classes
         $opt = array(Xapp_Rpc_Smd_Json::IGNORE_METHODS => $ignoredRPCMethods, Xapp_Rpc_Smd_Json::IGNORE_PREFIXES => array('_', '__'), Xapp_Rpc_Smd_Json::METHOD_TARGET => false, Xapp_Rpc_Smd_Json::SERVICE_OVER_GET => true, Xapp_Rpc_Smd_Json::TARGET => xapp_get_option(self::RPC_TARGET, $this));
         $smd = new Xapp_Rpc_Smd_Json($opt);
         //Options for RPC server
         $opt = array(Xapp_Rpc_Server::ALLOW_FUNCTIONS => true, Xapp_Rpc_Server::APPLICATION_ERROR => false, Xapp_Rpc_Server::METHOD_AS_SERVICE => false, Xapp_Rpc_Server::ALLOW_BATCHED_REQUESTS => true, Xapp_Rpc_Server::SERVICE_OVER_GET => true, Xapp_Rpc_Server::DEBUG => XApp_Service_Entry_Utils::isDebug(), Xapp_Rpc_Server::VALIDATE => !XApp_Service_Entry_Utils::isUpload(), Xapp_Rpc_Server::SMD => $smd);
         $server = Xapp_Rpc::server('json', $opt);
     }
     if ($server) {
         xapp_set_option(self::RPC_SERVER, $server, $this);
     }
 }
예제 #3
0
 /**
  * invoke class/method or function via rpc or outside rpc functionality for testing purposes. the first parameter
  * thus can be a valid callable when used outside of rpc service or the internal array containing all call parameters
  * from concrete rpc server implementation. throws exception with extended exception properties if in debug mode.
  * summarizes all caught applications exceptions when invoking callable to a general application error so sensitive
  * error messages can be omitted. when invoked with named parameters will reorder parameters to reflect
  * order of method/function call since call_user_func_array needs to pass parameter named or unnamed in
  * correct order
  *
  * @error 14211
  * @param array|callable $call expects either valid callable or array with all call parameters
  * @param array $params expects the parameters to pass to function/method to invoke
  * @return mixed
  * @throws Xapp_Rpc_Server_Exception
  * @throws Xapp_Rpc_Fault
  * @throws Exception
  */
 public function invoke($call, $params = null)
 {
     $key = null;
     $hash = null;
     $class = null;
     $return = null;
     $result = null;
     $callable = null;
     try {
         //invoke from outside of rpc service
         if (is_callable($call)) {
             $callable = $call;
             if (is_array($call)) {
                 $call = array(null, $call[1], is_object($call[0]) ? get_class($call[0]) : $call[0]);
                 $class = new ReflectionClass($call[2]);
             } else {
                 if (strpos((string) $call, '::') !== false) {
                     $call = array(null, substr($call, strpos($call, '::') + 2), substr($call, 0, strpos($call, '::')));
                     $class = new ReflectionClass($call[2]);
                 } else {
                     $call = array(null, $call, $call);
                     $class = null;
                 }
             }
         } else {
             if (is_array($call)) {
                 if ($call[2] !== null) {
                     if (xapp_get_option(self::NAMESPACE_IDENTIFIER, $this) === NAMESPACE_SEPARATOR) {
                         if (strpos($call[2], NAMESPACE_SEPARATOR) !== false) {
                             $call[2] = NAMESPACE_SEPARATOR . str_replace(array('\\', '/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2], ' ' . NAMESPACE_SEPARATOR));
                         } else {
                             $call[2] = str_replace(array('/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2]));
                         }
                     } else {
                         $call[2] = str_replace(array('\\', '/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2]));
                     }
                     $key = "{$call[2]}.{$call[1]}";
                     try {
                         if (array_key_exists(strtolower($call[2]), $this->_objects)) {
                             $class = new ReflectionClass($this->_objects[strtolower($call[2])]);
                         } else {
                             $class = new ReflectionClass($call[2]);
                         }
                         if ($class->hasMethod($call[1])) {
                             $method = $class->getMethod($call[1]);
                             if ($method->isPublic()) {
                                 if ($method->isStatic()) {
                                     $callable = array($class->getName(), $call[1]);
                                 } else {
                                     $callable = array(array_key_exists(strtolower($call[2]), $this->_objects) ? $this->_objects[strtolower($call[2])] : $class->newInstance(), $call[1]);
                                 }
                             } else {
                                 Xapp_Rpc_Fault::t("method: {$call[1]} of class: {$call[2]} is not public", array(1421105, -32601));
                             }
                         } else {
                             Xapp_Rpc_Fault::t("method: {$call[1]} of class: {$call[2]} does not exist", array(1421104, -32601));
                         }
                     } catch (ReflectionException $e) {
                         throw new Xapp_Rpc_Server_Exception(xapp_sprintf(_("unable to initialize class due to reflection error: %d, %s"), $e->getCode(), $e->getMessage()), 1421103);
                     }
                 } else {
                     $key = $call[1];
                     $callable = $call[1];
                 }
             } else {
                 throw new Xapp_Rpc_Server_Exception(_("invalid callable passed to invoke method"), 1421106);
             }
         }
         if (is_callable($callable)) {
             if (is_array($callable) && is_object($callable[0])) {
                 $this->_class = $callable[0];
             }
             if (!is_null($key) && !is_null($params) && array_values((array) $params) !== (array) $params) {
                 $tmp = array();
                 $arr = (array) $params;
                 $map = $this->smd()->get($key);
                 if (!is_null($map)) {
                     foreach ((array) $map->parameters as $p) {
                         if (array_key_exists($p->name, $arr)) {
                             $tmp[$p->name] = $arr[$p->name];
                         }
                     }
                 }
                 $params = $tmp;
                 $tmp = null;
                 $arr = null;
                 $map = null;
             }
             if (!is_null($key) && xapp_is_option(self::CACHE, $this) && preg_match(Xapp_Rpc::regex(xapp_get_option(self::CACHE_SERVICES, $this)), $call[0])) {
                 if (xapp_get_option(self::CACHE_BY_TRANSACTION_ID, $this)) {
                     $hash = $call[3]['id'];
                 } else {
                     $hash = Xapp_Cache::hash(serialize($call[0]) . serialize($params));
                 }
                 if (xapp_get_option(self::CACHE, $this)->has($hash)) {
                     return xapp_get_option(self::CACHE, $this)->get($hash);
                 }
             }
             if (!xapp_get_option(self::PARAMS_AS_ARRAY, $this)) {
                 $params = xapp_array_to_object($params);
             }
             xapp_event('xapp.rpc.server.beforeCall', array($this, array(&$result, $call[1], $call[2], $params)));
             if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) {
                 $return = $this->getClass()->onBeforeCall($this, array(&$result, $call[1], $call[2], &$params));
             }
             if ($return !== false && $result === null) {
                 $this->response()->result($result = call_user_func_array($callable, (array) $params));
             }
             if ($return === false && $this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) {
                 $return = $this->getClass()->onAbort($this, array(&$result, $call[1], $call[2], &$params));
             } else {
                 $return = null;
             }
             if ($return !== null) {
                 $result = $return;
             }
             if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) {
                 $return = $this->getClass()->onAfterCall($this, array(&$result));
             }
             if ($return !== null) {
                 $result = $return;
             }
             xapp_event('xapp.rpc.server.afterCall', array($this, array(&$result)));
             if (!is_null($hash)) {
                 if (!xapp_get_option(self::CACHE, $this)->has($hash)) {
                     xapp_get_option(self::CACHE, $this)->set($hash, $result);
                 }
             }
             $callable = null;
             $return = null;
             $params = null;
             $class = null;
             $hash = null;
             return $result;
         } else {
             throw new Xapp_Rpc_Server_Exception(_("unable to invoke function since first argument is not a callable"), 1421102);
         }
     } catch (Exception $e) {
         if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) {
             $error = $this->getClass()->onError($this, $e);
             if ($error instanceof Exception) {
                 $e = $error;
                 $error = null;
             }
         }
         if (!$e instanceof Xapp_Rpc_Server_Exception) {
             $data = array();
             $debug = xapp_get_option(self::DEBUG, $this);
             if (is_bool($debug) && $debug === true || is_int($debug) && $debug === 1) {
                 $data['message'] = $e->getMessage();
                 $data['code'] = $e->getCode();
                 $data['class'] = get_class($e);
                 $data['file'] = $e->getFile();
                 $data['line'] = $e->getLine();
                 if ($e instanceof ErrorException) {
                     $data['severity'] = $e->getSeverity();
                 }
                 if ($e instanceof Xapp_Rpc_Fault && $e->hasData()) {
                     $data['data'] = $e->getData();
                 }
             } else {
                 if (is_int($debug) && $debug === 2) {
                     $data['message'] = $e->getMessage();
                     $data['code'] = $e->getCode();
                     if ($e instanceof ErrorException) {
                         $data['severity'] = $e->getSeverity();
                     }
                     if ($e instanceof Xapp_Rpc_Fault && $e->hasData()) {
                         $data['data'] = $e->getData();
                     }
                 }
             }
             if (xapp_is_option(self::APPLICATION_ERROR, $this)) {
                 if ($e instanceof Xapp_Rpc_Fault && $e->hasFault()) {
                     $f = $e->getFault();
                 } else {
                     $f = -32500;
                 }
                 if (($code = (int) $e->getCode()) !== 0) {
                     Xapp_Rpc_Fault::t(xapp_sprintf("application error: %d", array($code)), array(1421101, $f), XAPP_ERROR_IGNORE, $data);
                 } else {
                     Xapp_Rpc_Fault::t("application error", array(1421101, $f), XAPP_ERROR_IGNORE, $data);
                 }
             } else {
                 if ((bool) $debug) {
                     Xapp_Rpc_Fault::t($e->getMessage(), $e->getCode(), XAPP_ERROR_IGNORE, $data);
                 } else {
                     throw $e;
                 }
             }
         } else {
             throw $e;
         }
     }
     return null;
 }