/** * Write the jsConnect string for single sign on. * * @param array $User An array containing information about the currently signed on user. If no user is signed in then this should be an empty array. * @param array $Request An array of the $_GET request. * @param string $ClientID The string client ID that you set up in the jsConnect settings page. * @param string $Secret The string secred that you set up in the jsConnect settings page. * @param string|bool $Secure Whether or not to check for security. This is one of these values. * - true: Check for security and sign the response with an md5 hash. * - false: Don't check for security, but sign the response with an md5 hash. * - string: Check for security and sign the response with the given hash algorithm. See hash_algos() for what your server can support. * - null: Don't check for security and don't sign the response. * @since 1.1b Added the ability to provide a hash algorithm to $Secure. */ function writeJsConnect($User, $Request, $ClientID, $Secret, $Secure = true) { $User = array_change_key_case($User); // Error checking. if ($Secure) { // Check the client. if (!isset($Request['client_id'])) { $Error = ['error' => 'invalid_request', 'message' => 'The client_id parameter is missing.']; } elseif ($Request['client_id'] != $ClientID) { $Error = ['error' => 'invalid_client', 'message' => "Unknown client {$Request['client_id']}."]; } elseif (!isset($Request['timestamp']) && !isset($Request['signature'])) { if (is_array($User) && count($User) > 0) { // This isn't really an error, but we are just going to return public information when no signature is sent. $Error = ['name' => $User['name'], 'photourl' => @$User['photourl']]; } else { $Error = ['name' => '', 'photourl' => '']; } } elseif (!isset($Request['timestamp']) || !is_numeric($Request['timestamp'])) { $Error = ['error' => 'invalid_request', 'message' => 'The timestamp parameter is missing or invalid.']; } elseif (!isset($Request['signature'])) { $Error = ['error' => 'invalid_request', 'message' => 'Missing signature parameter.']; } elseif (($Diff = abs($Request['timestamp'] - jsTimestamp())) > JS_TIMEOUT) { $Error = ['error' => 'invalid_request', 'message' => 'The timestamp is invalid.']; } else { // Make sure the timestamp hasn't timed out. $Signature = jsHash($Request['timestamp'] . $Secret, $Secure); if ($Signature != $Request['signature']) { $Error = ['error' => 'access_denied', 'message' => 'Signature invalid.']; } } } if (isset($Error)) { $Result = $Error; } elseif (is_array($User) && count($User) > 0) { if ($Secure === null) { $Result = $User; } else { $Result = signJsConnect($User, $ClientID, $Secret, $Secure, true); } } else { $Result = ['name' => '', 'photourl' => '']; } $Json = json_encode($Result); if (isset($Request['callback'])) { safeHeader('Content-Type: application/javascript'); echo "{$Request['callback']}({$Json})"; } else { safeHeader('Content-Type: application/json'); echo $Json; } }
/** * * @param EntryController $Sender * @param array $Args */ public function base_connectData_handler($Sender, $Args) { if (GetValue(0, $Args) != 'jsconnect') { return; } include_once dirname(__FILE__) . '/functions.jsconnect.php'; $Form = $Sender->Form; $JsConnect = $Form->GetFormValue('JsConnect', $Form->GetFormValue('Form/JsConnect')); parse_str($JsConnect, $JsData); // Make sure the data is valid. $client_id = GetValue('client_id', $JsData, GetValue('clientid', $JsData, $Sender->Request->Get('client_id'), TRUE), TRUE); $Signature = GetValue('signature', $JsData, FALSE, TRUE); $String = GetValue('sigStr', $JsData, FALSE, TRUE); // debugging unset($JsData['string']); if (!$client_id) { throw new Gdn_UserException(sprintf(T('ValidateRequired'), 'client_id'), 400); } $Provider = self::getProvider($client_id); if (!$Provider) { throw new Gdn_UserException(sprintf(T('Unknown client: %s.'), $client_id), 400); } if (!GetValue('TestMode', $Provider)) { if (!$Signature) { throw new Gdn_UserException(sprintf(T('ValidateRequired'), 'signature'), 400); } // Validate the signature. $CalculatedSignature = signJsConnect($JsData, $client_id, GetValue('AssociationSecret', $Provider), GetValue('HashType', $Provider, 'md5')); if ($CalculatedSignature != $Signature) { throw new Gdn_UserException(T("Signature invalid."), 400); } } // Map all of the standard jsConnect data. $Map = array('uniqueid' => 'UniqueID', 'name' => 'Name', 'email' => 'Email', 'photourl' => 'Photo', 'fullname' => 'FullName', 'roles' => 'Roles'); foreach ($Map as $Key => $Value) { if (array_key_exists($Key, $JsData)) { $Form->SetFormValue($Value, $JsData[$Key]); } } // Now add any extended information that jsConnect might have sent. $ExtData = array_diff_key($JsData, $Map); if (class_exists('SimpleAPIPlugin')) { SimpleAPIPlugin::translatePost($ExtData, FALSE); } Gdn::UserModel()->DefineSchema(); $Keys = array_keys(Gdn::UserModel()->Schema->Fields()); $UserFields = array_change_key_case(array_combine($Keys, $Keys)); foreach ($ExtData as $Key => $Value) { $lkey = strtolower($Key); if (array_key_exists($lkey, $UserFields)) { $Form->SetFormValue($UserFields[$lkey], $Value); } else { $Form->SetFormValue($Key, $Value); } } $Form->SetFormValue('Provider', $client_id); $Form->SetFormValue('ProviderName', GetValue('Name', $Provider, '')); $Form->AddHidden('JsConnect', $JsData); $Sender->SetData('ClientID', $client_id); $Sender->SetData('Verified', TRUE); $Sender->SetData('Trusted', GetValue('Trusted', $Provider, TRUE)); // this is a trusted connection. $Sender->SetData('SSOUser', $JsData); }