Configurable refresh token lifetimes.

This commit is contained in:
flash 2024-07-27 03:42:33 +00:00
parent dd968eae44
commit 61dad487f6
5 changed files with 39 additions and 23 deletions

View file

@ -0,0 +1,9 @@
<?php
use Index\Data\IDbConnection;
use Index\Data\Migration\IDbMigration;
final class ConfigurableRefreshLifetime_20240727_025524 implements IDbMigration {
public function migrate(IDbConnection $conn): void {
$conn->execute('ALTER TABLE hau_apps ADD COLUMN app_refresh_lifetime INT UNSIGNED NULL DEFAULT NULL AFTER app_type');
}
}

View file

@ -11,6 +11,7 @@ class AppInfo {
private string $website,
private bool $trusted,
private string $type,
private ?int $refreshLifetime,
private string $clientId,
private string $clientSecret,
private int $created,
@ -26,11 +27,12 @@ class AppInfo {
website: $result->getString(3),
trusted: $result->getBoolean(4),
type: $result->getString(5),
clientId: $result->getString(6),
clientSecret: $result->getString(7),
created: $result->getInteger(8),
updated: $result->getInteger(9),
deleted: $result->getIntegerOrNull(10),
refreshLifetime: $result->getIntegerOrNull(6),
clientId: $result->getString(7),
clientSecret: $result->getString(8),
created: $result->getInteger(9),
updated: $result->getInteger(10),
deleted: $result->getIntegerOrNull(11),
);
}
@ -71,6 +73,16 @@ class AppInfo {
return strcasecmp($this->type, 'confidential') === 0;
}
public function getRefreshTokenLifetime(): ?int {
return $this->refreshLifetime;
}
public function shouldIssueRefreshToken(): bool {
if($this->refreshLifetime === null)
return $this->isConfidential();
return $this->refreshLifetime > 0;
}
public function getClientId(): string {
return $this->clientId;
}

View file

@ -28,7 +28,7 @@ class AppsData {
throw new InvalidArgumentException('you must specify either $appId or $clientId');
$values = [];
$query = 'SELECT app_id, app_name, app_summary, app_website, app_trusted, app_type, app_client_id, app_client_secret, UNIX_TIMESTAMP(app_created), UNIX_TIMESTAMP(app_updated), UNIX_TIMESTAMP(app_deleted) FROM hau_apps';
$query = 'SELECT app_id, app_name, app_summary, app_website, app_trusted, app_type, app_refresh_lifetime, app_client_id, app_client_secret, UNIX_TIMESTAMP(app_created), UNIX_TIMESTAMP(app_updated), UNIX_TIMESTAMP(app_deleted) FROM hau_apps';
$query .= sprintf(' WHERE %s = ?', $hasAppId ? 'app_id' : 'app_client_id');
if($hasDeleted)
$query .= sprintf(' AND app_deleted %s NULL', $deleted ? 'IS NOT' : 'IS');

View file

@ -27,18 +27,16 @@ class OAuth2Context {
return $this->devices;
}
public function createRefreshFromAccessInfo(
OAuth2AccessInfo $accessInfo,
?string $token = null,
?int $lifetime = null
public function createRefresh(
AppInfo $appInfo,
OAuth2AccessInfo $accessInfo
): OAuth2RefreshInfo {
return $this->tokens->createRefresh(
$accessInfo->getAppId(),
$accessInfo,
$accessInfo->getUserId(),
$token,
$accessInfo->getScope(),
$lifetime
userId: $accessInfo->getUserId(),
scope: $accessInfo->getScope(),
lifetime: $appInfo->getRefreshTokenLifetime()
);
}

View file

@ -595,9 +595,8 @@ final class OAuth2Routes extends RouteHandler {
if($scope === $authoriseInfo->getScope())
unset($scope);
// this should probably check something else
if($appInfo->isConfidential())
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
if($appInfo->shouldIssueRefreshToken())
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
} elseif($type === 'refresh_token') {
$tokensData = $this->oauth2Ctx->getTokensData();
try {
@ -639,9 +638,8 @@ final class OAuth2Routes extends RouteHandler {
unset($refreshInfo);
// this should probably check something else
if($appInfo->isConfidential())
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
if($appInfo->shouldIssueRefreshToken())
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
} elseif($type === 'client_credentials') {
if(!$appInfo->isConfidential()) {
$response->setStatusCode(400);
@ -723,9 +721,8 @@ final class OAuth2Routes extends RouteHandler {
if($scope === $deviceInfo->getScope())
unset($scope);
// this should probably check something else
if($appInfo->isConfidential())
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
if($appInfo->shouldIssueRefreshToken())
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
} else {
$response->setStatusCode(400);
return self::error('unsupported_grant_type', 'Requested grant type is not supported by this server.');