Configurable refresh token lifetimes.
This commit is contained in:
parent
dd968eae44
commit
61dad487f6
5 changed files with 39 additions and 23 deletions
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ class AppInfo {
|
||||||
private string $website,
|
private string $website,
|
||||||
private bool $trusted,
|
private bool $trusted,
|
||||||
private string $type,
|
private string $type,
|
||||||
|
private ?int $refreshLifetime,
|
||||||
private string $clientId,
|
private string $clientId,
|
||||||
private string $clientSecret,
|
private string $clientSecret,
|
||||||
private int $created,
|
private int $created,
|
||||||
|
@ -26,11 +27,12 @@ class AppInfo {
|
||||||
website: $result->getString(3),
|
website: $result->getString(3),
|
||||||
trusted: $result->getBoolean(4),
|
trusted: $result->getBoolean(4),
|
||||||
type: $result->getString(5),
|
type: $result->getString(5),
|
||||||
clientId: $result->getString(6),
|
refreshLifetime: $result->getIntegerOrNull(6),
|
||||||
clientSecret: $result->getString(7),
|
clientId: $result->getString(7),
|
||||||
created: $result->getInteger(8),
|
clientSecret: $result->getString(8),
|
||||||
updated: $result->getInteger(9),
|
created: $result->getInteger(9),
|
||||||
deleted: $result->getIntegerOrNull(10),
|
updated: $result->getInteger(10),
|
||||||
|
deleted: $result->getIntegerOrNull(11),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +73,16 @@ class AppInfo {
|
||||||
return strcasecmp($this->type, 'confidential') === 0;
|
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 {
|
public function getClientId(): string {
|
||||||
return $this->clientId;
|
return $this->clientId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class AppsData {
|
||||||
throw new InvalidArgumentException('you must specify either $appId or $clientId');
|
throw new InvalidArgumentException('you must specify either $appId or $clientId');
|
||||||
|
|
||||||
$values = [];
|
$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');
|
$query .= sprintf(' WHERE %s = ?', $hasAppId ? 'app_id' : 'app_client_id');
|
||||||
if($hasDeleted)
|
if($hasDeleted)
|
||||||
$query .= sprintf(' AND app_deleted %s NULL', $deleted ? 'IS NOT' : 'IS');
|
$query .= sprintf(' AND app_deleted %s NULL', $deleted ? 'IS NOT' : 'IS');
|
||||||
|
|
|
@ -27,18 +27,16 @@ class OAuth2Context {
|
||||||
return $this->devices;
|
return $this->devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createRefreshFromAccessInfo(
|
public function createRefresh(
|
||||||
OAuth2AccessInfo $accessInfo,
|
AppInfo $appInfo,
|
||||||
?string $token = null,
|
OAuth2AccessInfo $accessInfo
|
||||||
?int $lifetime = null
|
|
||||||
): OAuth2RefreshInfo {
|
): OAuth2RefreshInfo {
|
||||||
return $this->tokens->createRefresh(
|
return $this->tokens->createRefresh(
|
||||||
$accessInfo->getAppId(),
|
$accessInfo->getAppId(),
|
||||||
$accessInfo,
|
$accessInfo,
|
||||||
$accessInfo->getUserId(),
|
userId: $accessInfo->getUserId(),
|
||||||
$token,
|
scope: $accessInfo->getScope(),
|
||||||
$accessInfo->getScope(),
|
lifetime: $appInfo->getRefreshTokenLifetime()
|
||||||
$lifetime
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -595,9 +595,8 @@ final class OAuth2Routes extends RouteHandler {
|
||||||
if($scope === $authoriseInfo->getScope())
|
if($scope === $authoriseInfo->getScope())
|
||||||
unset($scope);
|
unset($scope);
|
||||||
|
|
||||||
// this should probably check something else
|
if($appInfo->shouldIssueRefreshToken())
|
||||||
if($appInfo->isConfidential())
|
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
|
||||||
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
|
|
||||||
} elseif($type === 'refresh_token') {
|
} elseif($type === 'refresh_token') {
|
||||||
$tokensData = $this->oauth2Ctx->getTokensData();
|
$tokensData = $this->oauth2Ctx->getTokensData();
|
||||||
try {
|
try {
|
||||||
|
@ -639,9 +638,8 @@ final class OAuth2Routes extends RouteHandler {
|
||||||
|
|
||||||
unset($refreshInfo);
|
unset($refreshInfo);
|
||||||
|
|
||||||
// this should probably check something else
|
if($appInfo->shouldIssueRefreshToken())
|
||||||
if($appInfo->isConfidential())
|
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
|
||||||
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
|
|
||||||
} elseif($type === 'client_credentials') {
|
} elseif($type === 'client_credentials') {
|
||||||
if(!$appInfo->isConfidential()) {
|
if(!$appInfo->isConfidential()) {
|
||||||
$response->setStatusCode(400);
|
$response->setStatusCode(400);
|
||||||
|
@ -723,9 +721,8 @@ final class OAuth2Routes extends RouteHandler {
|
||||||
if($scope === $deviceInfo->getScope())
|
if($scope === $deviceInfo->getScope())
|
||||||
unset($scope);
|
unset($scope);
|
||||||
|
|
||||||
// this should probably check something else
|
if($appInfo->shouldIssueRefreshToken())
|
||||||
if($appInfo->isConfidential())
|
$refreshInfo = $this->oauth2Ctx->createRefresh($appInfo, $accessInfo);
|
||||||
$refreshInfo = $this->oauth2Ctx->createRefreshFromAccessInfo($accessInfo);
|
|
||||||
} else {
|
} else {
|
||||||
$response->setStatusCode(400);
|
$response->setStatusCode(400);
|
||||||
return self::error('unsupported_grant_type', 'Requested grant type is not supported by this server.');
|
return self::error('unsupported_grant_type', 'Requested grant type is not supported by this server.');
|
||||||
|
|
Reference in a new issue