Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PSR-7 support #1099

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"require": {
"php": "^5.4 || ^7.0",
"firebase/php-jwt": "^4.0 || ^5.0",
"phpseclib/phpseclib": "~2.0"
"phpseclib/phpseclib": "~2.0",
"laminas/laminas-diactoros": "^1.4||^2.0"
},
"require-dev": {
"ext-curl": "*",
Expand All @@ -31,7 +32,7 @@
},
"autoload-dev": {
"psr-4": {
"HybridauthTest\\Hybridauth\\": "test/"
"HybridauthTest\\Hybridauth\\": "tests/"
}
}
}
48 changes: 48 additions & 0 deletions src/Adapter/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Hybridauth\HttpClient\HttpClientInterface;
use Hybridauth\HttpClient\Curl as HttpClient;
use Hybridauth\Data;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\ServerRequestFactory;

/**
* Class AbstractAdapter
Expand Down Expand Up @@ -369,4 +371,50 @@ protected function validateApiResponse($error = '')
);
}
}

/**
* @param ServerRequestInterface|null $request
*
* @return ServerRequestInterface
*/
protected function generateRequest(ServerRequestInterface $request = null)
{
if ($request === null) {
$request = ServerRequestFactory::fromGlobals()->withAttribute('HYBRIDAUTH::GENERATED', true);
}

return $request;
}

protected function isGeneratedRequest(ServerRequestInterface $request)
{
return $request->getAttribute('HYBRIDAUTH::GENERATED', false) === true;
}

/**
* @param string|int $paramKey
* @param ServerRequestInterface $request
*
* @return mixed|null
*/
protected function getQueryParamFromRequest($paramKey, ServerRequestInterface $request)
{
return array_key_exists($paramKey, $request->getQueryParams()) ? $request->getQueryParams()[$paramKey] : null;
}

/**
* @param string|int $paramKey
* @param ServerRequestInterface $request
*
* @return mixed|null
*/
protected function getBodyParamFromRequest($paramKey, ServerRequestInterface $request)
{
return array_key_exists($paramKey, $request->getParsedBody()) ? $request->getParsedBody()[$paramKey] : null;
}

protected function getBodyOrQueryParamFromRequest($paramKey, ServerRequestInterface $request)
{
return $request->getMethod() === 'POST' ? $this->getBodyParamFromRequest($paramKey, $request) : $this->getQueryParamFromRequest($paramKey, $request);
}
}
9 changes: 7 additions & 2 deletions src/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use Hybridauth\HttpClient\HttpClientInterface;
use Hybridauth\Storage\StorageInterface;
use Hybridauth\Logger\LoggerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
* Interface AdapterInterface
Expand All @@ -19,9 +21,12 @@ interface AdapterInterface
/**
* Initiate the appropriate protocol and process/automate the authentication or authorization flow.
*
* @return bool|null
* @param ServerRequestInterface|null $request
*
* @return bool|ResponseInterface|null If already connected, returns true.
* If $request is not null a RedirectResponse is returned.
*/
public function authenticate();
public function authenticate(ServerRequestInterface $request = null);

/**
* Returns TRUE if the user is connected
Expand Down
51 changes: 35 additions & 16 deletions src/Adapter/OAuth1.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Hybridauth\Thirdparty\OAuth\OAuthRequest;
use Hybridauth\Thirdparty\OAuth\OAuthSignatureMethodHMACSHA1;
use Hybridauth\Thirdparty\OAuth\OAuthUtil;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\RedirectResponse;

/**
* This class can be used to simplify the authorization flow of OAuth 1 based service providers.
Expand Down Expand Up @@ -206,8 +208,10 @@ protected function initialize()
/**
* {@inheritdoc}
*/
public function authenticate()
public function authenticate(ServerRequestInterface $request = null)
{
/** @var ServerRequestInterface $request */
$request = $this->generateRequest($request);
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));

if ($this->isConnected()) {
Expand All @@ -217,14 +221,16 @@ public function authenticate()
try {
if (!$this->getStoredData('request_token')) {
// Start a new flow.
$this->authenticateBegin();
} elseif (empty($_GET['oauth_token']) && empty($_GET['denied'])) {
return $this->authenticateBegin($request);
}

if (empty($_GET['oauth_token']) && empty($_GET['denied'])) {
// A previous authentication was not finished, and this request is not finishing it.
$this->authenticateBegin();
} else {
// Finish a flow.
$this->authenticateFinish();
return $this->authenticateBegin($request);
}

// Finish a flow.
$this->authenticateFinish($request);
} catch (Exception $exception) {
$this->clearStoredData();

Expand All @@ -248,8 +254,15 @@ public function isConnected()
* 1. Obtaining an Unauthorized Request Token
* 2. Build Authorization URL for Authorization Request and redirect the user-agent to the
* Authorization Server.
*
* @param ServerRequestInterface $request
*
* @return RedirectResponse|void
* @throws InvalidOauthTokenException
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
*/
protected function authenticateBegin()
protected function authenticateBegin(ServerRequestInterface $request)
{
$response = $this->requestAuthToken();

Expand All @@ -259,29 +272,35 @@ protected function authenticateBegin()

$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);

if (!$this->isGeneratedRequest($request)) {
return new RedirectResponse($authUrl);
}

HttpClient\Util::redirect($authUrl);
}

/**
* Finalize the authorization process
*
* @param ServerRequestInterface $request
*
* @throws AuthorizationDeniedException
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
* @throws InvalidAccessTokenException
* @throws InvalidOauthTokenException
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
*/
protected function authenticateFinish()
protected function authenticateFinish(ServerRequestInterface $request)
{
$this->logger->debug(
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
[HttpClient\Util::getCurrentUrl(true)]
[(string)$request->getUri()]
);

$denied = filter_input(INPUT_GET, 'denied');
$oauth_problem = filter_input(INPUT_GET, 'oauth_problem');
$oauth_token = filter_input(INPUT_GET, 'oauth_token');
$oauth_verifier = filter_input(INPUT_GET, 'oauth_verifier');
$denied = $this->getQueryParamFromRequest('denied', $request);
$oauth_problem = $this->getQueryParamFromRequest('oauth_problem', $request);
$oauth_token = $this->getQueryParamFromRequest('oauth_token', $request);
$oauth_verifier = $this->getQueryParamFromRequest('oauth_verifier', $request);

if ($denied) {
throw new AuthorizationDeniedException(
Expand Down
46 changes: 31 additions & 15 deletions src/Adapter/OAuth2.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use Hybridauth\Exception\InvalidAccessTokenException;
use Hybridauth\Data;
use Hybridauth\HttpClient;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\RedirectResponse;

/**
* This class can be used to simplify the authorization flow of OAuth 2 based service providers.
Expand Down Expand Up @@ -300,24 +302,26 @@ protected function initialize()
/**
* {@inheritdoc}
*/
public function authenticate()
public function authenticate(ServerRequestInterface $request = null)
{
/** @var ServerRequestInterface $request */
$request = $this->generateRequest($request);
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));

if ($this->isConnected()) {
return true;
}

try {
$this->authenticateCheckError();
$this->authenticateCheckError($request);

$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
$code = $this->getBodyOrQueryParamFromRequest('code', $request);

if (empty($code)) {
$this->authenticateBegin();
} else {
$this->authenticateFinish();
return $this->authenticateBegin($request);
}

$this->authenticateFinish($request);
} catch (Exception $e) {
$this->clearStoredData();

Expand Down Expand Up @@ -357,16 +361,18 @@ public function isRefreshTokenAvailable()
*
* http://tools.ietf.org/html/rfc6749#section-4.1.2.1
*
* @param ServerRequestInterface|null $request
*
* @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
* @throws \Hybridauth\Exception\AuthorizationDeniedException
*/
protected function authenticateCheckError()
protected function authenticateCheckError(ServerRequestInterface $request)
{
$error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
$error = filter_var($this->getQueryParamFromRequest('error', $request), FILTER_SANITIZE_SPECIAL_CHARS);

if (!empty($error)) {
$error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
$error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
$error_description = filter_var($this->getQueryParamFromRequest('error_description', $request), FILTER_SANITIZE_SPECIAL_CHARS);
$error_uri = filter_var($this->getQueryParamFromRequest('error_uri', $request), FILTER_SANITIZE_SPECIAL_CHARS);

$collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);

Expand All @@ -383,33 +389,43 @@ protected function authenticateCheckError()
*
* Build Authorization URL for Authorization Request and redirect the user-agent to the
* Authorization Server.
*
* @param ServerRequestInterface $request
*
* @return RedirectResponse|void
*/
protected function authenticateBegin()
protected function authenticateBegin(ServerRequestInterface $request)
{
$authUrl = $this->getAuthorizeUrl();

$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);

if (!$this->isGeneratedRequest($request)) {
return new RedirectResponse($authUrl);
}

HttpClient\Util::redirect($authUrl);
}

/**
* Finalize the authorization process
*
* @param ServerRequestInterface $request
*
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
* @throws InvalidAccessTokenException
* @throws InvalidAuthorizationStateException
*/
protected function authenticateFinish()
protected function authenticateFinish(ServerRequestInterface $request)
{
$this->logger->debug(
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
[HttpClient\Util::getCurrentUrl(true)]
[(string)$request->getUri()]
);

$state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
$state = $this->getBodyOrQueryParamFromRequest('state', $request);
$code = $this->getBodyOrQueryParamFromRequest('code', $request);

/**
* Authorization Request State
Expand Down
22 changes: 16 additions & 6 deletions src/Adapter/OpenID.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Hybridauth\HttpClient;
use Hybridauth\User;
use Hybridauth\Thirdparty\OpenID\LightOpenID;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\RedirectResponse;

/**
* This class can be used to simplify the authentication flow of OpenID based service providers.
Expand Down Expand Up @@ -82,21 +84,21 @@ protected function initialize()
/**
* {@inheritdoc}
*/
public function authenticate()
public function authenticate(ServerRequestInterface $request = null)
{
/** @var ServerRequestInterface $request */
$request = $this->generateRequest($request);
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));

if ($this->isConnected()) {
return true;
}

if (empty($_REQUEST['openid_mode'])) {
$this->authenticateBegin();
} else {
return $this->authenticateFinish();
return $this->authenticateBegin($request);
}

return null;
return $this->authenticateFinish();
}

/**
Expand All @@ -121,8 +123,12 @@ public function disconnect()
* Initiate the authorization protocol
*
* Include and instantiate LightOpenID
*
* @param ServerRequestInterface $request
*
* @return RedirectResponse|void
*/
protected function authenticateBegin()
protected function authenticateBegin(ServerRequestInterface $request)
{
$this->openIdClient->identity = $this->openidIdentifier;
$this->openIdClient->returnUrl = $this->callback;
Expand All @@ -149,6 +155,10 @@ protected function authenticateBegin()

$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);

if (!$this->isGeneratedRequest($request)) {
return new RedirectResponse($authUrl);
}

HttpClient\Util::redirect($authUrl);
}

Expand Down
Loading