/Logica/Facebook/Helpers/FacebookRedirectLoginHelper.php
PHP | 360 lines | 146 code | 42 blank | 172 comment | 12 complexity | e0bc282f269891c1d7eee5eb2a343512 MD5 | raw file
- <?php
- /**
- * Copyright 2014 Facebook, Inc.
- *
- * You are hereby granted a non-exclusive, worldwide, royalty-free license to
- * use, copy, modify, and distribute this software in source code or binary
- * form for use in connection with the web services and APIs provided by
- * Facebook.
- *
- * As with any software that integrates with the Facebook platform, your use
- * of this software is subject to the Facebook Developer Principles and
- * Policies [http://developers.facebook.com/policy/]. This copyright notice
- * shall be included in all copies or substantial portions of the software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
- namespace Facebook\Helpers;
- use Facebook\Authentication\AccessToken;
- use Facebook\Authentication\OAuth2Client;
- use Facebook\Url\UrlDetectionInterface;
- use Facebook\Url\FacebookUrlDetectionHandler;
- use Facebook\Url\FacebookUrlManipulator;
- use Facebook\PersistentData\PersistentDataInterface;
- use Facebook\PersistentData\FacebookSessionPersistentDataHandler;
- use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
- use Facebook\PseudoRandomString\McryptPseudoRandomStringGenerator;
- use Facebook\PseudoRandomString\OpenSslPseudoRandomStringGenerator;
- use Facebook\PseudoRandomString\UrandomPseudoRandomStringGenerator;
- use Facebook\Exceptions\FacebookSDKException;
- /**
- * Class FacebookRedirectLoginHelper
- *
- * @package Facebook
- */
- class FacebookRedirectLoginHelper
- {
- /**
- * @const int The length of CSRF string to validate the login link.
- */
- const CSRF_LENGTH = 32;
- /**
- * @var OAuth2Client The OAuth 2.0 client service.
- */
- protected $oAuth2Client;
- /**
- * @var UrlDetectionInterface The URL detection handler.
- */
- protected $urlDetectionHandler;
- /**
- * @var PersistentDataInterface The persistent data handler.
- */
- protected $persistentDataHandler;
- /**
- * @var PseudoRandomStringGeneratorInterface The cryptographically secure pseudo-random string generator.
- */
- protected $pseudoRandomStringGenerator;
- /**
- * @param OAuth2Client $oAuth2Client The OAuth 2.0 client service.
- * @param PersistentDataInterface|null $persistentDataHandler The persistent data handler.
- * @param UrlDetectionInterface|null $urlHandler The URL detection handler.
- * @param PseudoRandomStringGeneratorInterface|null $prsg The cryptographically secure pseudo-random string generator.
- */
- public function __construct(OAuth2Client $oAuth2Client, PersistentDataInterface $persistentDataHandler = null, UrlDetectionInterface $urlHandler = null, PseudoRandomStringGeneratorInterface $prsg = null)
- {
- $this->oAuth2Client = $oAuth2Client;
- $this->persistentDataHandler = $persistentDataHandler ?: new FacebookSessionPersistentDataHandler();
- $this->urlDetectionHandler = $urlHandler ?: new FacebookUrlDetectionHandler();
- $this->pseudoRandomStringGenerator = $prsg ?: $this->detectPseudoRandomStringGenerator();
- }
- /**
- * Returns the persistent data handler.
- *
- * @return PersistentDataInterface
- */
- public function getPersistentDataHandler()
- {
- return $this->persistentDataHandler;
- }
- /**
- * Returns the URL detection handler.
- *
- * @return UrlDetectionInterface
- */
- public function getUrlDetectionHandler()
- {
- return $this->urlDetectionHandler;
- }
- /**
- * Returns the cryptographically secure pseudo-random string generator.
- *
- * @return PseudoRandomStringGeneratorInterface
- */
- public function getPseudoRandomStringGenerator()
- {
- return $this->pseudoRandomStringGenerator;
- }
- /**
- * Detects which pseudo-random string generator to use.
- *
- * @return PseudoRandomStringGeneratorInterface
- *
- * @throws FacebookSDKException
- */
- public function detectPseudoRandomStringGenerator()
- {
- // Since openssl_random_pseudo_bytes() can sometimes return non-cryptographically
- // secure pseudo-random strings (in rare cases), we check for mcrypt_create_iv() first.
- if (function_exists('mcrypt_create_iv')) {
- return new McryptPseudoRandomStringGenerator();
- }
- if (function_exists('openssl_random_pseudo_bytes')) {
- return new OpenSslPseudoRandomStringGenerator();
- }
- if (!ini_get('open_basedir') && is_readable('/dev/urandom')) {
- return new UrandomPseudoRandomStringGenerator();
- }
- throw new FacebookSDKException('Unable to detect a cryptographically secure pseudo-random string generator.');
- }
- /**
- * Stores CSRF state and returns a URL to which the user should be sent to in order to continue the login process with Facebook.
- *
- * @param string $redirectUrl The URL Facebook should redirect users to after login.
- * @param array $scope List of permissions to request during login.
- * @param array $params An array of parameters to generate URL.
- * @param string $separator The separator to use in http_build_query().
- *
- * @return string
- */
- private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
- {
- $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
- $this->persistentDataHandler->set('state', $state);
- return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
- }
- /**
- * Returns the URL to send the user in order to login to Facebook.
- *
- * @param string $redirectUrl The URL Facebook should redirect users to after login.
- * @param array $scope List of permissions to request during login.
- * @param string $separator The separator to use in http_build_query().
- *
- * @return string
- */
- public function getLoginUrl($redirectUrl, array $scope = [], $separator = '&')
- {
- return $this->makeUrl($redirectUrl, $scope, [], $separator);
- }
- /**
- * Returns the URL to send the user in order to log out of Facebook.
- *
- * @param AccessToken|string $accessToken The access token that will be logged out.
- * @param string $next The url Facebook should redirect the user to after a successful logout.
- * @param string $separator The separator to use in http_build_query().
- *
- * @return string
- *
- * @throws FacebookSDKException
- */
- public function getLogoutUrl($accessToken, $next, $separator = '&')
- {
- if (!$accessToken instanceof AccessToken) {
- $accessToken = new AccessToken($accessToken);
- }
- if ($accessToken->isAppAccessToken()) {
- throw new FacebookSDKException('Cannot generate a logout URL with an app access token.', 722);
- }
- $params = [
- 'next' => $next,
- 'access_token' => $accessToken->getValue(),
- ];
- return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, $separator);
- }
- /**
- * Returns the URL to send the user in order to login to Facebook with permission(s) to be re-asked.
- *
- * @param string $redirectUrl The URL Facebook should redirect users to after login.
- * @param array $scope List of permissions to request during login.
- * @param string $separator The separator to use in http_build_query().
- *
- * @return string
- */
- public function getReRequestUrl($redirectUrl, array $scope = [], $separator = '&')
- {
- $params = ['auth_type' => 'rerequest'];
- return $this->makeUrl($redirectUrl, $scope, $params, $separator);
- }
- /**
- * Returns the URL to send the user in order to login to Facebook with user to be re-authenticated.
- *
- * @param string $redirectUrl The URL Facebook should redirect users to after login.
- * @param array $scope List of permissions to request during login.
- * @param string $separator The separator to use in http_build_query().
- *
- * @return string
- */
- public function getReAuthenticationUrl($redirectUrl, array $scope = [], $separator = '&')
- {
- $params = ['auth_type' => 'reauthenticate'];
- return $this->makeUrl($redirectUrl, $scope, $params, $separator);
- }
- /**
- * Takes a valid code from a login redirect, and returns an AccessToken entity.
- *
- * @param string|null $redirectUrl The redirect URL.
- *
- * @return AccessToken|null
- *
- * @throws FacebookSDKException
- */
- public function getAccessToken($redirectUrl = null)
- {
- if (!$code = $this->getCode()) {
- return null;
- }
- $this->validateCsrf();
- $redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl();
- // At minimum we need to remove the state param
- $redirectUrl = FacebookUrlManipulator::removeParamsFromUrl($redirectUrl, ['state']);
- return $this->oAuth2Client->getAccessTokenFromCode($code, $redirectUrl);
- }
- /**
- * Validate the request against a cross-site request forgery.
- *
- * @throws FacebookSDKException
- */
- protected function validateCsrf()
- {
- $state = $this->getState();
- $savedState = $this->persistentDataHandler->get('state');
- if (!$state || !$savedState) {
- throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
- }
- $savedLen = strlen($savedState);
- $givenLen = strlen($state);
- if ($savedLen !== $givenLen) {
- throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
- }
- $result = 0;
- for ($i = 0; $i < $savedLen; $i++) {
- $result |= ord($state[$i]) ^ ord($savedState[$i]);
- }
- if ($result !== 0) {
- throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
- }
- }
- /**
- * Return the code.
- *
- * @return string|null
- */
- protected function getCode()
- {
- return $this->getInput('code');
- }
- /**
- * Return the state.
- *
- * @return string|null
- */
- protected function getState()
- {
- return $this->getInput('state');
- }
- /**
- * Return the error code.
- *
- * @return string|null
- */
- public function getErrorCode()
- {
- return $this->getInput('error_code');
- }
- /**
- * Returns the error.
- *
- * @return string|null
- */
- public function getError()
- {
- return $this->getInput('error');
- }
- /**
- * Returns the error reason.
- *
- * @return string|null
- */
- public function getErrorReason()
- {
- return $this->getInput('error_reason');
- }
- /**
- * Returns the error description.
- *
- * @return string|null
- */
- public function getErrorDescription()
- {
- return $this->getInput('error_description');
- }
- /**
- * Returns a value from a GET param.
- *
- * @param string $key
- *
- * @return string|null
- */
- private function getInput($key)
- {
- return isset($_GET[$key]) ? $_GET[$key] : null;
- }
- }