Token expiration and refreshing using the refresh_token flow

This commit is contained in:
Jasper Weyne 2020-07-07 02:26:00 +02:00
parent 25144a13c7
commit 10c890947f
2 changed files with 84 additions and 2 deletions

View File

@ -2,6 +2,11 @@
namespace BookStack\Auth\Access\Guards;
use BookStack\Auth\Access\OpenIdService;
use BookStack\Auth\Access\RegistrationService;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Session\Session;
/**
* OpenId Session Guard
*
@ -14,6 +19,41 @@ namespace BookStack\Auth\Access\Guards;
*/
class OpenIdSessionGuard extends ExternalBaseSessionGuard
{
protected $openidService;
/**
* OpenIdSessionGuard constructor.
*/
public function __construct(
$name,
UserProvider $provider,
Session $session,
OpenIdService $openidService,
RegistrationService $registrationService
) {
$this->openidService = $openidService;
parent::__construct($name, $provider, $session, $registrationService);
}
/**
* Get the currently authenticated user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
// retrieve the current user
$user = parent::user();
// refresh the current user
if ($user && !$this->openidService->refresh()) {
$this->user = null;
}
return $this->user;
}
/**
* Validate a user's credentials.
*

View File

@ -6,6 +6,7 @@ use BookStack\Exceptions\OpenIdException;
use BookStack\Exceptions\UserRegistrationException;
use Exception;
use Lcobucci\JWT\Token;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use OpenIDConnectClient\AccessToken;
use OpenIDConnectClient\OpenIDConnectProvider;
@ -53,6 +54,46 @@ class OpenIdService extends ExternalAuthService
return ['url' => $url, 'id' => $id];
}
/**
* Refresh the currently logged in user.
* @throws Error
*/
public function refresh(): bool
{
// Retrieve access token for current session
$json = session()->get('openid_token');
$accessToken = new AccessToken(json_decode($json, true));
// Check whether the access token or ID token is expired
if (!$accessToken->getIdToken()->isExpired() && !$accessToken->hasExpired()) {
return true;
}
// If no refresh token available, logout
if ($accessToken->getRefreshToken() === null) {
$this->actionLogout();
return false;
}
// ID token or access token is expired, we refresh it using the refresh token
try {
$provider = $this->getProvider();
$accessToken = $provider->getAccessToken('refresh_token', [
'refresh_token' => $accessToken->getRefreshToken(),
]);
} catch (IdentityProviderException $e) {
// Refreshing failed, logout
$this->actionLogout();
return false;
}
// A valid token was obtained, we update the access token
session()->put('openid_token', json_encode($accessToken));
return true;
}
/**
* Process the Authorization response from the authorization server and
* return the matching, or new if registration active, user matched to
@ -86,7 +127,7 @@ class OpenIdService extends ExternalAuthService
}
/**
* Load the underlying Onelogin SAML2 toolkit.
* Load the underlying OpenID Connect Provider.
* @throws Error
* @throws Exception
*/
@ -155,7 +196,7 @@ class OpenIdService extends ExternalAuthService
}
/**
* Extract the details of a user from a SAML response.
* Extract the details of a user from an ID token.
*/
protected function getUserDetails(Token $token): array
{
@ -202,6 +243,7 @@ class OpenIdService extends ExternalAuthService
}
auth()->login($user);
session()->put('openid_token', json_encode($accessToken));
return $user;
}
}