public function execute($api_key, $callback_url, $params) { $admin_client = RingsideSocialUtils::getAdminClient(); // TODO: SECURITY: Possibly security hole. We're signing and giving the signed payload to any URL, just by using the API key, which is public. A 3rd-party could hijack the signed payload and implement an offline brute force attack on the secret key $app_props = $admin_client->admin_getAppProperties("application_id,application_name,api_key,secret_key,callback_url", null, null, $api_key); // From RingsideSocialServerRender: // Recreate Session if we have it if (array_key_exists('social_session_key', $params)) { $session_key = $params['social_session_key']; $network_session = new RingsideSocialSession($session_key); $uid = $network_session->getUserId(); if (null == $uid || strlen($uid) == 0) { setcookie('social_session_key', $network_session->getSessionKey()); $uid = $_REQUEST['uid']; $network_session->setUserId($uid); $network_session->setLoggedIn(true); } } else { if (isset($_COOKIE['PHPSESSID'])) { // Optimization if user is already logged into web front-end $network_session = new RingsideSocialSession($_COOKIE['PHPSESSID']); $uid = $network_session->getUserId(); } else { // Not logged in, so login via annonymous user $trust = new RingsideSocialApiTrust($request); $network_session = $trust->getAnonymousSession(); } } $ctx = self::buildCallContext($api_key, $network_session); $sig_params = $ctx->getParameters($app_props['secret_key']); $req_params = array_merge($params, $sig_params); // error_log("Ajax Proxy to $callback_url with params:".var_export($req_params, true)); $result = RingsideSocialUtils::get_request($callback_url, $req_params, $headers); echo str_replace('+', '+', $result); }
public function renderRemote($callbackUrl, $apiKey, $secretKey, $canvasType, $isAppAdded, $sessionKey, RingsideSocialClientInterface $socialClient, &$headers, &$status) { // error_log( "renderRemote : enter ($callbackUrl) ($apiKey) " ); $response = null; if (!empty($this->path)) { // error_log( "renderRemote : path set" ); $callbackUrl .= $this->path; } // Create openFB request. $ctx = new RingsideSocialAppContext(); $ctx->setFlavor($this->flavor); if ($canvasType == RingsideSocialApiRender::CANVASTYPE_IFRAME || $canvasType == RingsideSocialApiRender::CANVASTYPE_OS) { $ctx->setIFrame(1); } else { $ctx->setIFrame(0); } $ctx->setInCanvas(1); $ctx->setTime(time()); if ($socialClient->inSession()) { // We don't know whether the app is added unless the user is logged in, so don't send that part of the context $ctx->setIsAppAdded($isAppAdded); $ctx->setUser($socialClient->getCurrentUser()); $ctx->setSessionKey($sessionKey); // $ctx->setProfileUpdateTime(); $ctx->setExpires(0); if ($socialClient->getNetworkSession()->getPrincipalId()) { $ctx->setPrincipalId($socialClient->getNetworkSession()->getPrincipalId()); } } $ctx->setApiKey($apiKey); $ctx->setRequestMethod($_SERVER['REQUEST_METHOD']); $ctx->setNetworkId($socialClient->getCurrentNetwork()); // $ctx->setDeployedNetwork( RingsideSocialConfig::$apiKey ); // $ctx->setHostNetwork(RingsideSocialConfig::$apiKey); $ctx->setSocialSessionKey($socialClient->getNetworkSession()->getSessionKey()); $deployed_ctx = new RingsideSocialAppContext(array(), RingsideSocialConfig::$apiKey); // $deployed_ctx->setRestUrl(RingsideApiClientsConfig::$serverUrl); // $deployed_ctx->setLoginUrl(RingsideApiClientsConfig::$webUrl.'/login.php'); // $deployed_ctx->setCanvasUrl(RingsideApiClientsConfig::$webUrl.'/canvas.php'); // $ctx->addNetwork($deployed_ctx); $cbReq = $ctx->getParameters($secretKey); // error_log(var_export($cbReq, true)); /* * Special case if we are to return an IFRAME, then the only thing we are returning is the * URL to ship out. It is up to the returning application to place this inside some form of content * frame. */ if ($this->flavor == 'canvas' && $canvasType == RingsideSocialApiRender::CANVASTYPE_IFRAME) { $callbackQuery = http_build_query(array_merge($cbReq, $this->params)); // TODO iframe generationg is off should be more expressive and configurable. $this->iframe = "{$callbackUrl}?{$callbackQuery}"; // error_log( "renderRemote: iframe : " . $this->iframe ); } else { if ($this->flavor == 'canvas' && $canvasType == RingsideSocialApiRender::CANVASTYPE_OS) { //Open Social Gadget description is the $callbackUrl $callbackQuery = http_build_query(array_merge($cbReq, $this->params)); // We also need to define fbsig_owner_id if the param id is present if (array_key_exists('id', $this->params)) { $callbackQuery . '&fb_sig_owner_id=' . $this->params['id']; } //TODO These parm options should be configurable $callbackQuery = $callbackQuery . '&view=canvas&synd=ringside&nocache=1'; //If you change this you must change container.js $this->iframe = RingsideApiClientsConfig::$socialUrl . "/gadgets/ifr?url=" . urlencode($callbackUrl) . "&{$callbackQuery}"; if (isset($this->params['forceIFrame']) && $this->params['forceIFrame'] == 'true') { $headers['content-type'] = 'text/html'; $response = "<iframe width='100%' frameborder='0' src='" . $this->iframe . "' height='" . $this->params['forceIFrameHeight'] . "'/>"; } // error_log( "renderRemote: OS iframe : " . $this->iframe ); } else { $response = RingsideSocialUtils::get_request($callbackUrl, array_merge($cbReq, $this->params), $headers, $status); if (isset($headers['location'])) { $this->redirect = $headers['location']; } } } return $response; }
/** * Re-routes an api request to another network. If trust.php is used as a rest server URL * and a path info is provided such that the request looks like the one below: * * http://localhost/trust.php/facebook/footprints/restserver.php * or * http://localhost/trust.php/{network}/{canvas url}/{restserver path} * * Attempts to remap and resign the api call using the app's secret on the new network * and then to change the uid to the equivelent uid on the forgin network. * * The api call is then re-signed and issued and the response is returned. * * @param unknown_type $params */ private static function proxy_app_request(&$params) { $matches = array(); // All these special cases are to ensure we aren't adding an additional "/" character to the URL. preg_match(',^/([^/]*)/([^/]*)(/?.*)$,', $_SERVER['PATH_INFO'], $matches); $network_key = $matches[1]; $canvas_url = $matches[2]; $rest = $matches[3]; if ($rest == '') { $rest = '/'; } if ($network_key != RingsideSocialConfig::$apiKey) { $skey = isset($_REQUEST['fb_sig_session_key']) ? $_REQUEST['fb_sig_session_key'] : ''; $apiKey = isset($_REQUEST['fb_sig_api_key']) ? $_REQUEST['fb_sig_api_key'] : ''; $ringside_rest = self::createRestClient($params['fb_sig_session_key']); $admin_rest = RingsideSocialUtils::getAdminClient(); $props = $admin_rest->admin_getAppProperties("application_id,application_name,api_key,secret_key,callback_url", null, $canvas_url, NULL); $network_app_props = $admin_rest->admin_getAppKeys(null, null, $props['api_key']); $network_api_key = $props['api_key']; $network_secret = $props['secret_key']; self::getApiKeyAndSecretForNetwork($network_key, $network_app_props, $network_api_key, $network_secret); $network_session = new RingsideSocialSession($params['fb_sig_session_key']); $idmaps = $ringside_rest->users_mapToPrincipal(array($params['fb_sig_user']), $network_key, $props['application_id']); // Create openFB request. These are just overrides for the original request. $has_fb_sig = isset($params['fb_sig']); $cbReq = array(); // We can't append fb_sig unless Facebook has already passed fb_sig; this would prevent the app's client from creating a session during login if ($has_fb_sig) { if (isset($params['fb_sig_nuser'])) { // Since we're proxying a request, do NOT forward the user mapping! unset($params['fb_sig_nuser']); } $cbReq['fb_sig_flavor'] = 'canvas'; // $cbReq['fb_sig_in_iframe'] = 0; $cbReq['fb_sig_nid'] = $network_key; // The social session key needs to be for _this_ social session! $cbReq['fb_sig_soc_session_key'] = $network_session->getSessionKey(); if (!empty($idmaps) && isset($idmaps[0]) && $idmaps[0] !== null) { $cbReq['fb_sig_nuser'] = $idmaps[0]['pid']; } } // error_log("cbReq social session key is {$cbReq['fb_sig_soc_session_key']}; params is $fb_sig_soc_session_key"); // TODO: Set up social session key for trust-based proxy // $cbReq['fb_sig_soc_session_key'] = ; $req_params = array_merge($params, $cbReq); error_log("Invoking {$canvas_url} with params: " . var_export($req_params, true)); // Now, we need to re-sign the parameters, since we've added the "nid" and "nuser" fb_sig params if ($has_fb_sig) { unset($req_params['fb_sig']); $sig = RingsideSocialUtils::makeSig($req_params, $network_secret, 'fb_sig'); $req_params['fb_sig'] = $sig; } // error_log("Logged in user is principal ".$pids[0]); // error_log("Proxying to app callback URL ".$props['callback_url']); $headers = array(); $callback_url = self::safe_append_url($props['callback_url'], $rest); $result = RingsideSocialUtils::get_request($callback_url, $req_params, $headers); // error_log("Result: $result"); if (isset($headers['location'])) { $proxy_redir_url = self::buildProxyUrl($props['callback_url'], $headers['location']); error_log("Proxying for redirect to {$proxy_redir_url}"); // Build the remote network's callback_url // We'll redirect _within_ the frame (the commented-out script will redirect the _top_ of the frame if (isset($params['fb_sig_in_iframe']) && 0 != $params['fb_sig_in_iframe']) { // RingsideWebUtils::redirect($headers['location']); $apps_url = RingsideApiClientsConfig::$webUrl . '/canvas.php'; if ($nid == 'facebook') { $apps_url = 'http://apps.facebook.com/'; } // $real_location = self::buildProxyUrl($props['callback_url'], $headers['location']); // echo "<script>top.location.href='".$real_location."';</script>"; RingsideWebUtils::redirect($proxy_redir_url); } else { // $real_location = self::buildProxyUrl($props['callback_url'], $headers['location']); if (isset($params['fb_sig_in_canvas']) && 0 != $params['fb_sig_in_canvas']) { echo "<fb:redirect url='{$proxy_redir_url}'/>"; } else { RingsideWebUtils::redirect($proxy_redir_url); } } return; } echo $result; return; } // Map network user to principal // Rewrite fb_sig // Proxy to callback_url echo '<ERROR>Unknown Callback_Url!</ERROR>'; }