/** * @param Token $newToken * @param bool $sameToken * @return bool|string */ public function setToken(Token $newToken, $sameToken = false) { if ($newToken->getLocation()) { $this->em->persist($newToken); $this->em->flush(); return true; } // Check whether the token already exists in relation to a channel. $repository = $this->em->getRepository('CampaignChainSecurityAuthenticationClientOAuthBundle:Token'); $query = $repository->createQueryBuilder('token')->where('token.application = :application')->andWhere('token.accessToken = :accessToken')->andWhere('token.location IS NOT NULL')->setParameter('application', $newToken->getApplication())->setParameter('accessToken', $newToken->getAccessToken())->setMaxResults(1)->getQuery(); $oldToken = $query->getOneOrNullResult(); if (!$oldToken) { // So, there's no token related to a specific channel, but perhaps there is one // that has been persisted at a previous attempt to connect to the channel? // TODO: Implement what to do if token was persisted previously without channel relationship? $this->token = $newToken; $this->em->persist($this->token); $this->em->flush(); return self::STATUS_NEW_TOKEN; } // Has a scope been set? if (!$newToken->getScope() && !$sameToken) { return self::STATUS_NO_CHANGE; } //With LinkedIn if a user connects multiple times, he will get the same access token //And even though they are same, it has to be saved as a new token if ($sameToken) { $this->token = $newToken; $this->em->persist($this->token); $this->em->flush(); return self::STATUS_NEW_TOKEN; } $newScope = $newToken->getScope(); $newAccessToken = $newToken->getAccessToken(); $existingScope = $oldToken->getScope(); $existingAccessToken = $oldToken->getAccessToken(); // If the channel has the same access token and the same scope, // or no scope has been defined, then we're done. if ($existingScope === $newScope) { return self::STATUS_SAME_SCOPE; } // Is the scope different for the same profile? if ($existingAccessToken !== $newAccessToken) { // If the channel has a different scope and access token, // then create a new token entry for the existing profile. // This takes care of how Google handles scopes for its APIs. $this->token = $newToken; $status = self::STATUS_NEW_TOKEN; } else { // If the channel has the same access token, but a different scope, // then just update the scope for the token. // This takes care of how Facebook deals with scope changes. $this->token = $oldToken; $this->token->setScope($newScope); $status = self::STATUS_NEW_SCOPE; } $this->em->persist($this->token); $this->em->flush(); return $status; }
/** * @param $resourceOwner * @param $applicationInfo * @param bool $sameToken * * @throws \Exception */ public function authenticate($resourceOwner, $applicationInfo, $sameToken = false) { // Get application credentials $oauthApp = $this->container->get('campaignchain.security.authentication.client.oauth.application'); $application = $oauthApp->getApplication($resourceOwner); $bundleParams = $this->container->getParameter('campaignchain_security_authentication_client_oauth'); if (isset($_SERVER['HTTPS']) && (!empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'off')) { $hostScheme = 'https://'; } else { $hostScheme = 'http://'; } $config = array("base_url" => $hostScheme . $_SERVER['HTTP_HOST'] . $this->container->get('router')->generate('campaignchain_security_authentication_client_oauth_login'), "providers" => array($resourceOwner => array("enabled" => true, "keys" => array($applicationInfo['key_labels'][0] => $application->getKey(), $applicationInfo['secret_labels'][0] => $application->getSecret()))), "debug_mode" => $bundleParams['debug_mode'], "debug_file" => $bundleParams['debug_file']); $config['providers'][$resourceOwner] = array_merge($config['providers'][$resourceOwner], $applicationInfo['parameters']); if (isset($applicationInfo['wrapper'])) { $config['providers'][$resourceOwner]['wrapper']['class'] = $applicationInfo['wrapper']['class']; $config['providers'][$resourceOwner]['wrapper']['path'] = $this->container->get('kernel')->getRootDir() . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $applicationInfo['wrapper']['path']); } try { $hybridauth = new Hybrid_Auth($config); $resource = $hybridauth->authenticate($resourceOwner); $this->profile = $resource->getUserProfile(); $accessToken = $resource->getAccessToken(); $hybridauth->logoutAllProviders(); $token = new Token(); $token->setApplication($application); $token->setAccessToken($accessToken["access_token"]); $token->setTokenSecret($accessToken["access_token_secret"]); $token->setRefreshToken($accessToken["refresh_token"]); $token->setExpiresIn($accessToken["expires_in"]); $token->setExpiresAt($accessToken["expires_at"]); if (isset($resource->adapter->api->api_base_url)) { $token->setEndpoint($resource->adapter->api->api_base_url); } if (isset($applicationInfo['parameters']['scope'])) { $token->setScope($applicationInfo['parameters']['scope']); } $this->oauthToken = $this->container->get('campaignchain.security.authentication.client.oauth.token'); return $this->oauthToken->setToken($token, $sameToken); } catch (\Exception $e) { throw new ExternalApiException($e->getMessage(), $e->getCode(), $e); } }