mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6b18a9441a | ||
|
44ff7b33a1 | ||
|
db055f790d | ||
|
d1bc4848c8 | ||
|
cf63403585 | ||
|
cdf43e498e | ||
|
a12fc98b0d | ||
|
019d285235 | ||
|
0bb968f413 | ||
|
88b19ad2d0 | ||
|
6856699cab | ||
|
72cd9a62e1 | ||
|
acf262f879 | ||
|
5241309bdb | ||
|
9a93dca05c | ||
|
a6b7a5cedc | ||
|
78b6bddc4d | ||
|
14b6761c0f | ||
|
7c61922f07 | ||
|
20535ad95b | ||
|
e885114714 | ||
|
f80d0d39a4 | ||
|
7bfd5b7d0d | ||
|
143a2e32f7 | ||
|
8f418cff08 | ||
|
fcec1f3442 | ||
|
46e7eef14e | ||
|
51f44fdf17 | ||
|
f8b2e80ef3 | ||
|
7045785d89 | ||
|
301ddc53c7 | ||
|
2a6f900323 | ||
|
fb8f47e868 | ||
|
5b192b3548 |
@@ -2,7 +2,6 @@ filter:
|
|||||||
excluded_paths:
|
excluded_paths:
|
||||||
- tests/*
|
- tests/*
|
||||||
- vendor/*
|
- vendor/*
|
||||||
- examples/*
|
|
||||||
checks:
|
checks:
|
||||||
php:
|
php:
|
||||||
code_rating: true
|
code_rating: true
|
||||||
|
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,6 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 5.0.0 (release 2016-04-17)
|
## 5.0.3 (released 2016-05-04)
|
||||||
|
|
||||||
|
* Fix hints in PasswordGrant (Issue #560)
|
||||||
|
* Add meaning of `Resource owner` to terminology.md (Issue #561)
|
||||||
|
* Use constant for event name instead of explicit string (Issue #563)
|
||||||
|
* Remove unused request property (Issue #564)
|
||||||
|
* Correct wrong phpdoc (Issue #569)
|
||||||
|
* Fixed typo in exception string (Issue #570)
|
||||||
|
|
||||||
|
## 5.0.2 (released 2016-04-18)
|
||||||
|
|
||||||
|
* `state` parameter is now correctly returned after implicit grant authorization
|
||||||
|
* Small code and docblock improvements
|
||||||
|
|
||||||
|
## 5.0.1 (released 2016-04-18)
|
||||||
|
|
||||||
|
* Fixes an issue (#550) whereby it was unclear whether or not to validate a client's secret during a request.
|
||||||
|
|
||||||
|
## 5.0.0 (released 2016-04-17)
|
||||||
|
|
||||||
Version 5 is a complete code rewrite.
|
Version 5 is a complete code rewrite.
|
||||||
|
|
||||||
|
@@ -43,11 +43,6 @@ You can contribute to the documentation in the [gh-pages branch](https://github.
|
|||||||
|
|
||||||
Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details.
|
Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details.
|
||||||
|
|
||||||
## Integration
|
|
||||||
|
|
||||||
- [CakePHP 3](https://github.com/uafrica/oauth-server)
|
|
||||||
- [Laravel](https://github.com/lucadegasperi/oauth2-server-laravel)
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues).
|
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues).
|
||||||
@@ -56,7 +51,7 @@ If you have any questions about OAuth _please_ open a ticket here; please **don'
|
|||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
If you discover any security related issues, please email hello@alexbilbie.com instead of using the issue tracker.
|
If you discover any security related issues, please email `hello@alexbilbie.com` instead of using the issue tracker.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@@ -1,11 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
|
||||||
* @copyright Copyright (c) Alex Bilbie
|
|
||||||
* @license http://mit-license.org/
|
|
||||||
*
|
|
||||||
* @link https://github.com/thephpleague/oauth2-server
|
|
||||||
*/
|
|
||||||
|
|
||||||
use League\OAuth2\Server\ResourceServer;
|
use League\OAuth2\Server\ResourceServer;
|
||||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||||
@@ -16,63 +9,65 @@ use Slim\App;
|
|||||||
include __DIR__ . '/../vendor/autoload.php';
|
include __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
$app = new App([
|
$app = new App([
|
||||||
'settings' => [
|
// Add the resource server to the DI container
|
||||||
'displayErrorDetails' => true,
|
|
||||||
],
|
|
||||||
ResourceServer::class => function () {
|
ResourceServer::class => function () {
|
||||||
// Setup the authorization server
|
|
||||||
$server = new ResourceServer(
|
$server = new ResourceServer(
|
||||||
new AccessTokenRepository(),
|
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
||||||
'file://' . __DIR__ . '/../public.key'
|
'file://' . __DIR__ . '/../public.key' // the authorization server's public key
|
||||||
);
|
);
|
||||||
|
|
||||||
return $server;
|
return $server;
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Add the resource server middleware which will intercept and validate requests
|
||||||
$app->add(
|
$app->add(
|
||||||
new \League\OAuth2\Server\Middleware\ResourceServerMiddleware(
|
new \League\OAuth2\Server\Middleware\ResourceServerMiddleware(
|
||||||
$app->getContainer()->get(ResourceServer::class)
|
$app->getContainer()->get(ResourceServer::class)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$app->get('/users', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
// An example endpoint secured with OAuth 2.0
|
||||||
|
$app->get(
|
||||||
|
'/users',
|
||||||
|
function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||||
|
|
||||||
$users = [
|
$users = [
|
||||||
[
|
[
|
||||||
'id' => 123,
|
'id' => 123,
|
||||||
'name' => 'Alex',
|
'name' => 'Alex',
|
||||||
'email' => 'alex@thephpleague.com',
|
'email' => 'alex@thephpleague.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 124,
|
'id' => 124,
|
||||||
'name' => 'Frank',
|
'name' => 'Frank',
|
||||||
'email' => 'frank@thephpleague.com',
|
'email' => 'frank@thephpleague.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 125,
|
'id' => 125,
|
||||||
'name' => 'Phil',
|
'name' => 'Phil',
|
||||||
'email' => 'phil@thephpleague.com',
|
'email' => 'phil@thephpleague.com',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// If the access token doesn't have the `basic` scope hide users' names
|
// If the access token doesn't have the `basic` scope hide users' names
|
||||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < count($users); $i++) {
|
||||||
unset($users[$i]['name']);
|
unset($users[$i]['name']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If the access token doesn't have the `emal` scope hide users' email addresses
|
// If the access token doesn't have the `email` scope hide users' email addresses
|
||||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < count($users); $i++) {
|
||||||
unset($users[$i]['email']);
|
unset($users[$i]['email']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode($users));
|
||||||
|
|
||||||
|
return $response->withStatus(200);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$response->getBody()->write(json_encode($users));
|
$app->run();
|
||||||
|
|
||||||
return $response->withStatus(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
$app->run();
|
|
@@ -30,9 +30,9 @@ $app = new App([
|
|||||||
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface
|
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface
|
||||||
|
|
||||||
// Path to public and private keys
|
// Path to public and private keys
|
||||||
$privateKey = 'file://path/to/private.key';
|
$privateKey = 'file://'.__DIR__.'/../private.key';
|
||||||
//$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase
|
//$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase
|
||||||
$publicKey = 'file://path/to/public.key';
|
$publicKey = 'file://'.__DIR__.'/../public.key';
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
|
@@ -1,11 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
|
||||||
* @copyright Copyright (c) Alex Bilbie
|
|
||||||
* @license http://mit-license.org/
|
|
||||||
*
|
|
||||||
* @link https://github.com/thephpleague/oauth2-server
|
|
||||||
*/
|
|
||||||
|
|
||||||
use League\OAuth2\Server\AuthorizationServer;
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
@@ -18,58 +11,64 @@ use OAuth2ServerExamples\Repositories\UserRepository;
|
|||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Slim\App;
|
use Slim\App;
|
||||||
use Zend\Diactoros\Stream;
|
|
||||||
|
|
||||||
include __DIR__ . '/../vendor/autoload.php';
|
include __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
$app = new App([
|
$app = new App([
|
||||||
'settings' => [
|
// Add the authorization server to the DI container
|
||||||
'displayErrorDetails' => true,
|
|
||||||
],
|
|
||||||
AuthorizationServer::class => function () {
|
AuthorizationServer::class => function () {
|
||||||
// Init our repositories
|
|
||||||
$clientRepository = new ClientRepository();
|
|
||||||
$accessTokenRepository = new AccessTokenRepository();
|
|
||||||
$scopeRepository = new ScopeRepository();
|
|
||||||
$userRepository = new UserRepository();
|
|
||||||
$refreshTokenRepository = new RefreshTokenRepository();
|
|
||||||
|
|
||||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
|
||||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
$clientRepository,
|
new ClientRepository(), // instance of ClientRepositoryInterface
|
||||||
$accessTokenRepository,
|
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
||||||
$scopeRepository,
|
new ScopeRepository(), // instance of ScopeRepositoryInterface
|
||||||
$privateKeyPath,
|
'file://'.__DIR__.'/../private.key', // path to private key
|
||||||
$publicKeyPath
|
'file://'.__DIR__.'/../public.key' // path to public key
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$grant = new PasswordGrant(
|
||||||
|
new UserRepository(), // instance of UserRepositoryInterface
|
||||||
|
new RefreshTokenRepository() // instance of RefreshTokenRepositoryInterface
|
||||||
|
);
|
||||||
|
$grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month
|
||||||
|
|
||||||
// Enable the password grant on the server with a token TTL of 1 hour
|
// Enable the password grant on the server with a token TTL of 1 hour
|
||||||
$server->enableGrantType(
|
$server->enableGrantType(
|
||||||
new PasswordGrant($userRepository, $refreshTokenRepository),
|
$grant,
|
||||||
new \DateInterval('PT1H')
|
new \DateInterval('PT1H') // access tokens will expire after 1 hour
|
||||||
);
|
);
|
||||||
|
|
||||||
return $server;
|
return $server;
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
$app->post(
|
||||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
'/access_token',
|
||||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||||
|
|
||||||
try {
|
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||||
return $server->respondToAccessTokenRequest($request, $response);
|
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||||
} catch (OAuthServerException $exception) {
|
|
||||||
return $exception->generateHttpResponse($response);
|
|
||||||
} catch (\Exception $exception) {
|
|
||||||
$body = new Stream('php://temp', 'r+');
|
|
||||||
$body->write($exception->getMessage());
|
|
||||||
|
|
||||||
return $response->withStatus(500)->withBody($body);
|
try {
|
||||||
|
|
||||||
|
// Try to respond to the access token request
|
||||||
|
return $server->respondToAccessTokenRequest($request, $response);
|
||||||
|
|
||||||
|
} catch (OAuthServerException $exception) {
|
||||||
|
|
||||||
|
// All instances of OAuthServerException can be converted to a PSR-7 response
|
||||||
|
return $exception->generateHttpResponse($response);
|
||||||
|
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
|
||||||
|
// Catch unexpected exceptions
|
||||||
|
$body = $response->getBody();
|
||||||
|
$body->write($exception->getMessage());
|
||||||
|
return $response->withStatus(500)->withBody($body);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
$app->run();
|
$app->run();
|
||||||
|
@@ -17,13 +17,14 @@ class ClientRepository implements ClientRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getClientEntity($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null)
|
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true)
|
||||||
{
|
{
|
||||||
$clients = [
|
$clients = [
|
||||||
'myawesomeapp' => [
|
'myawesomeapp' => [
|
||||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||||
'name' => 'My Awesome App',
|
'name' => 'My Awesome App',
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'is_confidential' => true,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -32,6 +33,14 @@ class ClientRepository implements ClientRepositoryInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$mustValidateSecret === true
|
||||||
|
&& $clients[$clientIdentifier]['is_confidential'] === true
|
||||||
|
&& password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier($clientIdentifier);
|
$client->setIdentifier($clientIdentifier);
|
||||||
$client->setName($clients[$clientIdentifier]['name']);
|
$client->setName($clients[$clientIdentifier]['name']);
|
||||||
|
@@ -156,7 +156,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
||||||
* @param \Psr\Http\Message\ResponseInterface $response
|
* @param \Psr\Http\Message\ResponseInterface $response
|
||||||
*
|
*
|
||||||
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
|
* @return \Psr\Http\Message\ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
|
public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
|
||||||
{
|
{
|
||||||
@@ -204,7 +204,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
protected function getResponseType()
|
protected function getResponseType()
|
||||||
{
|
{
|
||||||
if (!$this->responseType instanceof ResponseTypeInterface) {
|
if (!$this->responseType instanceof ResponseTypeInterface) {
|
||||||
$this->responseType = new BearerTokenResponse($this->accessTokenRepository);
|
$this->responseType = new BearerTokenResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->responseType->setPrivateKey($this->privateKey);
|
$this->responseType->setPrivateKey($this->privateKey);
|
||||||
|
@@ -13,6 +13,8 @@ use Lcobucci\JWT\Builder;
|
|||||||
use Lcobucci\JWT\Signer\Key;
|
use Lcobucci\JWT\Signer\Key;
|
||||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
|
|
||||||
trait AccessTokenTrait
|
trait AccessTokenTrait
|
||||||
{
|
{
|
||||||
@@ -36,4 +38,24 @@ trait AccessTokenTrait
|
|||||||
->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
|
->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
|
||||||
->getToken();
|
->getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ClientEntityInterface
|
||||||
|
*/
|
||||||
|
abstract public function getClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTime
|
||||||
|
*/
|
||||||
|
abstract public function getExpiryDateTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|int
|
||||||
|
*/
|
||||||
|
abstract public function getUserIdentifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ScopeEntityInterface[]
|
||||||
|
*/
|
||||||
|
abstract public function getScopes();
|
||||||
}
|
}
|
||||||
|
@@ -35,11 +35,6 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
|
|
||||||
const SCOPE_DELIMITER_STRING = ' ';
|
const SCOPE_DELIMITER_STRING = ' ';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ServerRequestInterface
|
|
||||||
*/
|
|
||||||
protected $request;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ClientRepositoryInterface
|
* @var ClientRepositoryInterface
|
||||||
*/
|
*/
|
||||||
@@ -161,11 +156,12 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$client = $this->clientRepository->getClientEntity(
|
$client = $this->clientRepository->getClientEntity(
|
||||||
$clientId,
|
$clientId,
|
||||||
$this->getIdentifier(),
|
$this->getIdentifier(),
|
||||||
$clientSecret
|
$clientSecret,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!$client instanceof ClientEntityInterface) {
|
if (!$client instanceof ClientEntityInterface) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,13 +172,13 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
is_string($client->getRedirectUri())
|
is_string($client->getRedirectUri())
|
||||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -108,7 +108,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $authCodePayload->user_id);
|
$scopes = $this->scopeRepository->finalizeScopes(
|
||||||
|
$scopes,
|
||||||
|
$this->getIdentifier(),
|
||||||
|
$client,
|
||||||
|
$authCodePayload->user_id
|
||||||
|
);
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code');
|
throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code');
|
||||||
}
|
}
|
||||||
@@ -165,11 +170,13 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
|
|
||||||
$client = $this->clientRepository->getClientEntity(
|
$client = $this->clientRepository->getClientEntity(
|
||||||
$clientId,
|
$clientId,
|
||||||
$this->getIdentifier()
|
$this->getIdentifier(),
|
||||||
|
null,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($client instanceof ClientEntityInterface === false) {
|
if ($client instanceof ClientEntityInterface === false) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,20 +186,22 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
is_string($client->getRedirectUri())
|
is_string($client->getRedirectUri())
|
||||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request),
|
$this->getQueryStringParameter('scope', $request),
|
||||||
$client->getRedirectUri()
|
is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri()
|
||||||
);
|
);
|
||||||
|
|
||||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||||
@@ -232,25 +241,25 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
$authorizationRequest->getScopes()
|
$authorizationRequest->getScopes()
|
||||||
);
|
);
|
||||||
|
|
||||||
$redirectPayload['code'] = $this->encrypt(
|
|
||||||
json_encode(
|
|
||||||
[
|
|
||||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
|
||||||
'redirect_uri' => $authCode->getRedirectUri(),
|
|
||||||
'auth_code_id' => $authCode->getIdentifier(),
|
|
||||||
'scopes' => $authCode->getScopes(),
|
|
||||||
'user_id' => $authCode->getUserIdentifier(),
|
|
||||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$redirectPayload['state'] = $authorizationRequest->getState();
|
|
||||||
|
|
||||||
$response = new RedirectResponse();
|
$response = new RedirectResponse();
|
||||||
$response->setRedirectUri(
|
$response->setRedirectUri(
|
||||||
$this->makeRedirectUri(
|
$this->makeRedirectUri(
|
||||||
$finalRedirectUri,
|
$finalRedirectUri,
|
||||||
$redirectPayload
|
[
|
||||||
|
'code' => $this->encrypt(
|
||||||
|
json_encode(
|
||||||
|
[
|
||||||
|
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||||
|
'redirect_uri' => $authCode->getRedirectUri(),
|
||||||
|
'auth_code_id' => $authCode->getIdentifier(),
|
||||||
|
'scopes' => $authCode->getScopes(),
|
||||||
|
'user_id' => $authCode->getUserIdentifier(),
|
||||||
|
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'state' => $authorizationRequest->getState(),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
*/
|
*/
|
||||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
||||||
{
|
{
|
||||||
throw new \LogicException('The Implicit Grant does nto return refresh tokens');
|
throw new \LogicException('The Implicit Grant does not return refresh tokens');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +51,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
*/
|
*/
|
||||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||||
{
|
{
|
||||||
throw new \LogicException('The Implicit Grant does nto return refresh tokens');
|
throw new \LogicException('The Implicit Grant does not return refresh tokens');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,11 +117,13 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
|
|
||||||
$client = $this->clientRepository->getClientEntity(
|
$client = $this->clientRepository->getClientEntity(
|
||||||
$clientId,
|
$clientId,
|
||||||
$this->getIdentifier()
|
$this->getIdentifier(),
|
||||||
|
null,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($client instanceof ClientEntityInterface === false) {
|
if ($client instanceof ClientEntityInterface === false) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,20 +133,22 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
is_string($client->getRedirectUri())
|
is_string($client->getRedirectUri())
|
||||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request),
|
$this->getQueryStringParameter('scope', $request),
|
||||||
$client->getRedirectUri()
|
is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri()
|
||||||
);
|
);
|
||||||
|
|
||||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||||
@@ -183,15 +187,16 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
$authorizationRequest->getScopes()
|
$authorizationRequest->getScopes()
|
||||||
);
|
);
|
||||||
|
|
||||||
$redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey);
|
|
||||||
$redirectPayload['token_type'] = 'bearer';
|
|
||||||
$redirectPayload['expires_in'] = $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp();
|
|
||||||
|
|
||||||
$response = new RedirectResponse();
|
$response = new RedirectResponse();
|
||||||
$response->setRedirectUri(
|
$response->setRedirectUri(
|
||||||
$this->makeRedirectUri(
|
$this->makeRedirectUri(
|
||||||
$finalRedirectUri,
|
$finalRedirectUri,
|
||||||
$redirectPayload,
|
[
|
||||||
|
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
||||||
|
'token_type' => 'bearer',
|
||||||
|
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(),
|
||||||
|
'state' => $authorizationRequest->getState(),
|
||||||
|
],
|
||||||
'#'
|
'#'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -77,12 +77,12 @@ class PasswordGrant extends AbstractGrant
|
|||||||
{
|
{
|
||||||
$username = $this->getRequestParameter('username', $request);
|
$username = $this->getRequestParameter('username', $request);
|
||||||
if (is_null($username)) {
|
if (is_null($username)) {
|
||||||
throw OAuthServerException::invalidRequest('username', '`%s` parameter is missing');
|
throw OAuthServerException::invalidRequest('username');
|
||||||
}
|
}
|
||||||
|
|
||||||
$password = $this->getRequestParameter('password', $request);
|
$password = $this->getRequestParameter('password', $request);
|
||||||
if (is_null($password)) {
|
if (is_null($password)) {
|
||||||
throw OAuthServerException::invalidRequest('password', '`%s` parameter is missing');
|
throw OAuthServerException::invalidRequest('password');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->userRepository->getUserEntityByUserCredentials(
|
$user = $this->userRepository->getUserEntityByUserCredentials(
|
||||||
@@ -92,7 +92,7 @@ class PasswordGrant extends AbstractGrant
|
|||||||
$client
|
$client
|
||||||
);
|
);
|
||||||
if (!$user instanceof UserEntityInterface) {
|
if (!$user instanceof UserEntityInterface) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('user.authentication.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
|
||||||
|
|
||||||
throw OAuthServerException::invalidCredentials();
|
throw OAuthServerException::invalidCredentials();
|
||||||
}
|
}
|
||||||
|
@@ -107,7 +107,7 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
|
|
||||||
$refreshTokenData = json_decode($refreshToken, true);
|
$refreshTokenData = json_decode($refreshToken, true);
|
||||||
if ($refreshTokenData['client_id'] !== $clientId) {
|
if ($refreshTokenData['client_id'] !== $clientId) {
|
||||||
$this->getEmitter()->emit(new RequestEvent('refresh_token.client.failed', $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_CLIENT_FAILED, $request));
|
||||||
throw OAuthServerException::invalidRefreshToken('Token is not linked to client');
|
throw OAuthServerException::invalidRefreshToken('Token is not linked to client');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,11 +16,13 @@ interface ClientRepositoryInterface extends RepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get a client.
|
* Get a client.
|
||||||
*
|
*
|
||||||
* @param string $clientIdentifier The client's identifier
|
* @param string $clientIdentifier The client's identifier
|
||||||
* @param string $grantType The grant type used
|
* @param string $grantType The grant type used
|
||||||
* @param null|string $clientSecret The client's secret (if sent)
|
* @param null|string $clientSecret The client's secret (if sent)
|
||||||
|
* @param bool $mustValidateSecret If true the client must attempt to validate the secret unless the client
|
||||||
|
* is confidential
|
||||||
*
|
*
|
||||||
* @return \League\OAuth2\Server\Entities\ClientEntityInterface
|
* @return \League\OAuth2\Server\Entities\ClientEntityInterface
|
||||||
*/
|
*/
|
||||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null);
|
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true);
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,10 @@ use Psr\Http\Message\ServerRequestInterface;
|
|||||||
|
|
||||||
class RequestEvent extends Event
|
class RequestEvent extends Event
|
||||||
{
|
{
|
||||||
|
const CLIENT_AUTHENTICATION_FAILED = 'client.authentication.failed';
|
||||||
|
const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
|
||||||
|
const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Psr\Http\Message\ServerRequestInterface
|
* @var \Psr\Http\Message\ServerRequestInterface
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user