Skip to content

Commit

Permalink
Generate new Refresh Tokens
Browse files Browse the repository at this point in the history
This PR was merged into the master branch (closes #20).
  • Loading branch information
markitosgv committed Dec 16, 2015
2 parents cabb138 + 02616cb commit b92e6eb
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 34 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: php


php:
- 5.3
- 5.4
- 5.5
- 5.6
Expand All @@ -20,4 +20,4 @@ script: ./bin/phpspec run -fpretty --verbose

notifications:
on_success: never
on_failure: always
on_failure: always
10 changes: 7 additions & 3 deletions EventListener/AttachRefreshTokenOnSuccessListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenManagerInterface;
use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken;
use Gesdinet\JWTRefreshTokenBundle\Request\RequestRefreshToken;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
Expand All @@ -34,14 +35,17 @@ public function attachRefreshToken(AuthenticationSuccessEvent $event)
{
$data = $event->getData();
$user = $event->getUser();
$request = $event->getRequest();

if (!$user instanceof UserInterface) {
return;
}

$refreshToken = $this->refreshTokenManager->getLastFromUsername($user->getUsername());
$refreshTokenString = RequestRefreshToken::getRefreshToken($request);

if (!$refreshToken instanceof RefreshToken) {
if ($refreshTokenString) {
$data['refresh_token'] = $refreshTokenString;
} else {
$datetime = new \DateTime();
$datetime->modify('+'.$this->ttl.' seconds');

Expand All @@ -65,9 +69,9 @@ public function attachRefreshToken(AuthenticationSuccessEvent $event)
}

$this->refreshTokenManager->save($refreshToken);
$data['refresh_token'] = $refreshToken->getRefreshToken();
}

$data['refresh_token'] = $refreshToken->getRefreshToken();
$event->setData($data);
}
}
32 changes: 32 additions & 0 deletions Request/RequestRefreshToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of the GesdinetJWTRefreshTokenBundle package.
*
* (c) Gesdinet <http://www.gesdinet.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gesdinet\JWTRefreshTokenBundle\Request;

use Symfony\Component\HttpFoundation\Request;

class RequestRefreshToken
{
public static function getRefreshToken(Request $request)
{
if ($request->headers->get('content_type') == 'application/json') {
$content = $request->getContent();
$params = !empty($content) ? json_decode($content, true) : array();
$refreshTokenString = trim($params['refresh_token']);

This comment has been minimized.

Copy link
@eliotik

eliotik Dec 18, 2015

Hello, now api consumer always forced on authorization provide key empty or false "refresh_token" other way no index "refresh_token" found notice will be returned.
may be it would be better to change this row to next one:

$refreshTokenString = isset($params['refresh_token']) ? trim($params['refresh_token']) : false;

case: i do POST to my auth route with _username and _password parameters and with Content-Type = application/json

This comment has been minimized.

Copy link
@markitosgv

markitosgv Dec 18, 2015

Author Owner

Ok thanks! Solved in last commit dc51b38

This comment has been minimized.

Copy link
@danielkay

danielkay Dec 22, 2015

any chance of a new release tag? ;)

This comment has been minimized.

Copy link
@markitosgv

markitosgv Dec 22, 2015

Author Owner

put v0.1.3 or dev-master on your composer ;-)

} elseif (null !== $request->get('refresh_token')) {
$refreshTokenString = $request->get('refresh_token');
} else {
$refreshTokenString = $request->request->get('refresh_token');
}

return $refreshTokenString;
}
}
11 changes: 3 additions & 8 deletions Security/Authenticator/RefreshTokenAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Gesdinet\JWTRefreshTokenBundle\Security\Authenticator;

use Gesdinet\JWTRefreshTokenBundle\Request\RequestRefreshToken;
use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
Expand All @@ -28,17 +29,11 @@ class RefreshTokenAuthenticator implements SimplePreAuthenticatorInterface, Auth
{
public function createToken(Request $request, $providerKey)
{
if ($request->headers->get('content_type') == 'application/json') {
$content = $request->getContent();
$params = !empty($content) ? json_decode($content, true) : array();
$refreshToken = trim($params['refresh_token']);
} else {
$refreshToken = $request->request->get('refresh_token');
}
$refreshTokenString = RequestRefreshToken::getRefreshToken($request);

return new PreAuthenticatedToken(
'',
$refreshToken,
$refreshTokenString,
$providerKey
);
}
Expand Down
17 changes: 4 additions & 13 deletions Service/RefreshToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ public function refresh(Request $request)
{
try {
$preAuthenticatedToken = $this->authenticator->authenticateToken(
$this->authenticator->createToken($request, $this->providerKey),
$this->provider,
$this->providerKey
$this->authenticator->createToken($request, $this->providerKey), $this->provider, $this->providerKey
);
} catch (AuthenticationException $e) {
return $this->failureHandler->onAuthenticationFailure($request, $e);
Expand All @@ -65,19 +63,12 @@ public function refresh(Request $request)
$refreshToken = $this->refreshTokenManager->get($preAuthenticatedToken->getCredentials());

if (null === $refreshToken || !$refreshToken->isValid()) {
return $this->failureHandler->onAuthenticationFailure($request,
new AuthenticationException(
sprintf('Refresh token "%s" is invalid.', $refreshToken)
)
return $this->failureHandler->onAuthenticationFailure($request, new AuthenticationException(
sprintf('Refresh token "%s" is invalid.', $refreshToken)
)
);
}

$datetime = new \DateTime();
$datetime->modify('+'.$this->ttl.' seconds');
$refreshToken->setValid($datetime);

$this->refreshTokenManager->save($refreshToken);

return $this->successHandler->onAuthenticationSuccess($request, $preAuthenticatedToken);
}
}
1 change: 1 addition & 0 deletions phpspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ code_coverage:
- Entity
- EventListener
- Model
- Request
- Security
- Service
format:
Expand Down
23 changes: 17 additions & 6 deletions spec/EventListener/AttachRefreshTokenOnSuccessListenerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\ParameterBag;

class AttachRefreshTokenOnSuccessListenerSpec extends ObjectBehavior
{
Expand All @@ -24,26 +27,33 @@ public function it_is_initializable()
$this->shouldHaveType('Gesdinet\JWTRefreshTokenBundle\EventListener\AttachRefreshTokenOnSuccessListener');
}

public function it_attach_an_existing_token(AuthenticationSuccessEvent $event, UserInterface $user, RefreshToken $refreshToken, $refreshTokenManager)
public function it_attach_token_on_refresh(Request $request, AuthenticationSuccessEvent $event, UserInterface $user, RefreshToken $refreshToken, $refreshTokenManager)
{
$event->getData()->willReturn(array());
$event->getUser()->willReturn($user);

$refreshTokenManager->getLastFromUsername(Argument::any())->willReturn($refreshToken);
$refreshTokenArray = array('refresh_token' => 'thepreviouslyissuedrefreshtoken');
$headers = new HeaderBag(array('content_type' => 'not-json'));
$request->headers = $headers;
$request->request = new ParameterBag($refreshTokenArray);

$refreshToken->getRefreshToken()->willReturn(Argument::any());
$event->getRequest()->willReturn($request);

$event->setData(Argument::any())->shouldBeCalled();
$event->setData(Argument::exact($refreshTokenArray))->shouldBeCalled();

$this->attachRefreshToken($event);
}

public function it_attach_a_new_token(AuthenticationSuccessEvent $event, UserInterface $user, RefreshToken $refreshToken, $refreshTokenManager, $validator)
public function it_attach_token_on_credentials_auth(Request $request, HeaderBag $headers, ParameterBag $requestBag, AuthenticationSuccessEvent $event, UserInterface $user, RefreshToken $refreshToken, $refreshTokenManager, $validator)
{
$event->getData()->willReturn(array());
$event->getUser()->willReturn($user);

$refreshTokenManager->getLastFromUsername(Argument::any())->willReturn(null);
$headers = new HeaderBag(array('content_type' => 'not-json'));
$request->headers = $headers;
$request->request = new ParameterBag();

$event->getRequest()->willReturn($request);

$refreshTokenManager->create()->willReturn($refreshToken);

Expand All @@ -61,6 +71,7 @@ public function it_is_not_valid_user(AuthenticationSuccessEvent $event)
{
$event->getData()->willReturn(array());
$event->getUser()->willReturn(null);
$event->getRequest()->willReturn(null);

$this->attachRefreshToken($event);
}
Expand Down
33 changes: 33 additions & 0 deletions spec/Request/RequestRefreshTokenSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace spec\Gesdinet\JWTRefreshTokenBundle\Request;

use PhpSpec\ObjectBehavior;
use Symfony\Component\HttpFoundation\Request;

class RequestRefreshTokenSpec extends ObjectBehavior
{
public function it_gets_from_query_param()
{
$request = Request::createFromGlobals();
$request->attributes->set('refresh_token', 'abcd');

$this::getRefreshToken($request)->shouldBe('abcd');
}

public function it_gets_from_body()
{
$request = Request::createFromGlobals();
$request->request->set('refresh_token', 'abcd');

$this::getRefreshToken($request)->shouldBe('abcd');
}

public function it_gets_from_json()
{
$request = Request::create(null, 'POST', array(), array(), array(), array(), json_encode(array('refresh_token' => 'abcd')));
$request->headers->set('content_type', 'application/json');

$this::getRefreshToken($request)->shouldBe('abcd');
}
}
2 changes: 0 additions & 2 deletions spec/Service/RefreshTokenSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public function it_refresh_token(Request $request, $refreshTokenManager, $authen

$refreshTokenManager->get(Argument::any())->willReturn($refreshToken);
$refreshToken->isValid()->willReturn(true);
$refreshToken->setValid(Argument::any())->shouldBeCalled();
$refreshTokenManager->save(Argument::any())->shouldBeCalled();

$this->refresh($request);
}
Expand Down

0 comments on commit b92e6eb

Please sign in to comment.