mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-20 17:15:51 +02:00
Added possibility to manage client_credentials OAuth tokens
This commit is contained in:
parent
1b3fc2c23c
commit
6a00b8e168
3 changed files with 82 additions and 10 deletions
31
migrations/Version20230730131708.php
Normal file
31
migrations/Version20230730131708.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230730131708 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE oauth_tokens CHANGE token token LONGTEXT DEFAULT NULL, CHANGE refresh_token refresh_token LONGTEXT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE oauth_tokens CHANGE token token VARCHAR(255) DEFAULT NULL, CHANGE refresh_token refresh_token VARCHAR(255) NOT NULL');
|
||||
}
|
||||
}
|
|
@ -39,26 +39,34 @@ use League\OAuth2\Client\Token\AccessTokenInterface;
|
|||
class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface
|
||||
{
|
||||
/** @var string|null The short-term usable OAuth2 token */
|
||||
#[ORM\Column(type: 'string', nullable: true)]
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $token = null;
|
||||
|
||||
/** @var \DateTimeInterface The date when the token expires */
|
||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $expires_at = null;
|
||||
|
||||
/** @var string The refresh token for the OAuth2 auth */
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $refresh_token = '';
|
||||
/** @var string|null The refresh token for the OAuth2 auth */
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $refresh_token = null;
|
||||
|
||||
/**
|
||||
* The default expiration time for a authorization token, if no expiration time is given
|
||||
*/
|
||||
private const DEFAULT_EXPIRATION_TIME = 3600;
|
||||
|
||||
public function __construct(string $name, string $refresh_token, string $token = null, \DateTimeInterface $expires_at = null)
|
||||
public function __construct(string $name, ?string $refresh_token, ?string $token = null, \DateTimeInterface $expires_at = null)
|
||||
{
|
||||
//If token is given, you also have to give the expires_at date
|
||||
if ($token !== null && $expires_at === null) {
|
||||
throw new \InvalidArgumentException('If you give a token, you also have to give the expires_at date');
|
||||
}
|
||||
|
||||
//If no refresh_token is given, the token is a client credentials grant token, which must have a token
|
||||
if ($refresh_token === null && $token === null) {
|
||||
throw new \InvalidArgumentException('If you give no refresh_token, you have to give a token!');
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->refresh_token = $refresh_token;
|
||||
$this->expires_at = $expires_at;
|
||||
|
@ -109,6 +117,16 @@ class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface
|
|||
return $this->expires_at->getTimestamp() < time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this token is a client credentials grant token (meaning it has no refresh token), and
|
||||
* needs to be refreshed via the client credentials grant.
|
||||
* @return bool
|
||||
*/
|
||||
public function isClientCredentialsGrant(): bool
|
||||
{
|
||||
return $this->refresh_token === null;
|
||||
}
|
||||
|
||||
public function replaceWithNewToken(AccessTokenInterface $accessToken): void
|
||||
{
|
||||
$this->token = $accessToken->getToken();
|
||||
|
|
|
@ -39,9 +39,9 @@ final class OAuthTokenManager
|
|||
* Saves the given token to the database, so it can be retrieved later
|
||||
* @param string $app_name
|
||||
* @param AccessTokenInterface $token
|
||||
* @return void
|
||||
* @return OAuthToken The saved token as database entity
|
||||
*/
|
||||
public function saveToken(string $app_name, AccessTokenInterface $token): void
|
||||
public function saveToken(string $app_name, AccessTokenInterface $token): OAuthToken
|
||||
{
|
||||
//Check if we already have a token for this app
|
||||
$tokenEntity = $this->entityManager->getRepository(OAuthToken::class)->findOneBy(['name' => $app_name]);
|
||||
|
@ -54,7 +54,7 @@ final class OAuthTokenManager
|
|||
$this->entityManager->flush($tokenEntity);
|
||||
|
||||
//We are done
|
||||
return;
|
||||
return $tokenEntity;
|
||||
}
|
||||
|
||||
//If the token was not existing, we create a new one
|
||||
|
@ -63,7 +63,7 @@ final class OAuthTokenManager
|
|||
//@phpstan-ignore-next-line
|
||||
$this->entityManager->flush($tokenEntity);
|
||||
|
||||
return;
|
||||
return $tokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +102,14 @@ final class OAuthTokenManager
|
|||
}
|
||||
|
||||
$client = $this->clientRegistry->getClient($app_name);
|
||||
$new_token = $client->refreshAccessToken($token->getRefreshToken());
|
||||
|
||||
//Check if the token is refreshable or if it is an client credentials token
|
||||
if ($token->isClientCredentialsGrant()) {
|
||||
$new_token = $client->getOAuth2Provider()->getAccessToken('client_credentials');
|
||||
} else {
|
||||
//Otherwise we can use the refresh token to get a new access token
|
||||
$new_token = $client->refreshAccessToken($token->getRefreshToken());
|
||||
}
|
||||
|
||||
//Persist the token
|
||||
$token->replaceWithNewToken($new_token);
|
||||
|
@ -139,4 +146,20 @@ final class OAuthTokenManager
|
|||
//And return the new token
|
||||
return $token->getToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an access token for the given app name using the client credentials grant (so no user flow is needed)
|
||||
* The app_name must be registered in the knpu_oauth2_client.yaml
|
||||
* The token is saved to the database, and afterward can be used as usual
|
||||
* @param string $app_name
|
||||
* @return OAuthToken
|
||||
*/
|
||||
public function retrieveClientCredentialsToken(string $app_name): OAuthToken
|
||||
{
|
||||
$client = $this->clientRegistry->getClient($app_name);
|
||||
$access_token = $client->getOAuth2Provider()->getAccessToken('client_credentials');
|
||||
|
||||
|
||||
return $this->saveToken($app_name, $access_token);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue