Added field for specifying per app access token lifetime length.
This commit is contained in:
parent
12d48cce2e
commit
bf40942e72
4 changed files with 57 additions and 20 deletions
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\IDbMigration;
|
||||
|
||||
final class AccessLifetimeFieldForAppsTable_20240904_205008 implements IDbMigration {
|
||||
public function migrate(IDbConnection $conn): void {
|
||||
$conn->execute(<<<SQL
|
||||
ALTER TABLE hau_apps
|
||||
ADD COLUMN app_access_lifetime INT(10) UNSIGNED NULL DEFAULT NULL AFTER app_type;
|
||||
SQL);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ class AppInfo {
|
|||
private string $website,
|
||||
private bool $trusted,
|
||||
private string $type,
|
||||
private ?int $accessLifetime,
|
||||
private ?int $refreshLifetime,
|
||||
private string $clientId,
|
||||
private string $clientSecret,
|
||||
|
@ -27,12 +28,13 @@ class AppInfo {
|
|||
website: $result->getString(3),
|
||||
trusted: $result->getBoolean(4),
|
||||
type: $result->getString(5),
|
||||
refreshLifetime: $result->getIntegerOrNull(6),
|
||||
clientId: $result->getString(7),
|
||||
clientSecret: $result->getString(8),
|
||||
created: $result->getInteger(9),
|
||||
updated: $result->getInteger(10),
|
||||
deleted: $result->getIntegerOrNull(11),
|
||||
accessLifetime: $result->getIntegerOrNull(6),
|
||||
refreshLifetime: $result->getIntegerOrNull(7),
|
||||
clientId: $result->getString(8),
|
||||
clientSecret: $result->getString(9),
|
||||
created: $result->getInteger(10),
|
||||
updated: $result->getInteger(11),
|
||||
deleted: $result->getIntegerOrNull(12),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -73,6 +75,10 @@ class AppInfo {
|
|||
return strcasecmp($this->type, 'confidential') === 0;
|
||||
}
|
||||
|
||||
public function getAccessTokenLifetime(): ?int {
|
||||
return $this->accessLifetime;
|
||||
}
|
||||
|
||||
public function getRefreshTokenLifetime(): ?int {
|
||||
return $this->refreshLifetime;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,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_refresh_lifetime, 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_access_lifetime, 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');
|
||||
|
@ -60,6 +60,7 @@ class AppsData {
|
|||
string $website = '',
|
||||
?string $clientId = null,
|
||||
#[\SensitiveParameter] ?string $clientSecret = null,
|
||||
?int $accessLifetime = null,
|
||||
?int $refreshLifetime = null
|
||||
): AppInfo {
|
||||
if(trim($name) === '')
|
||||
|
@ -72,6 +73,11 @@ class AppsData {
|
|||
elseif(trim($clientId) === '')
|
||||
throw new InvalidArgumentException('$clientId may not be empty');
|
||||
|
||||
if($accessLifetime !== null && $accessLifetime < 1)
|
||||
throw new InvalidArgumentException('$accessLifetime must be null or greater than zero');
|
||||
if($refreshLifetime !== null && $refreshLifetime < 0)
|
||||
throw new InvalidArgumentException('$refreshLifetime must be null or a positive integer');
|
||||
|
||||
$summary = trim($summary);
|
||||
$website = trim($website);
|
||||
$clientSecret = $clientSecret === null ? '' : password_hash($clientSecret, self::CLIENT_SECRET_ALGO);
|
||||
|
@ -79,15 +85,16 @@ class AppsData {
|
|||
if($type === self::TYPE_CONFIDENTIAL && $clientSecret === '')
|
||||
throw new InvalidArgumentException('$clientSecret must be specified for confidential clients');
|
||||
|
||||
$stmt = $this->cache->get('INSERT INTO hau_apps (app_name, app_summary, app_website, app_trusted, app_type, app_refresh_lifetime, app_client_id, app_client_secret) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
||||
$stmt = $this->cache->get('INSERT INTO hau_apps (app_name, app_summary, app_website, app_trusted, app_type, app_access_lifetime, app_refresh_lifetime, app_client_id, app_client_secret) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
||||
$stmt->addParameter(1, $name);
|
||||
$stmt->addParameter(2, $summary);
|
||||
$stmt->addParameter(3, $website);
|
||||
$stmt->addParameter(4, $trusted ? 1 : 0);
|
||||
$stmt->addParameter(5, $type);
|
||||
$stmt->addParameter(6, $refreshLifetime);
|
||||
$stmt->addParameter(7, $clientId);
|
||||
$stmt->addParameter(8, $clientSecret);
|
||||
$stmt->addParameter(6, $accessLifetime);
|
||||
$stmt->addParameter(7, $refreshLifetime);
|
||||
$stmt->addParameter(8, $clientId);
|
||||
$stmt->addParameter(9, $clientSecret);
|
||||
$stmt->execute();
|
||||
|
||||
return $this->getScopeInfo(appId: (string)$this->dbConn->getLastInsertId());
|
||||
|
|
|
@ -61,12 +61,25 @@ class OAuth2Context {
|
|||
$logAction(' Removed %d!', $pruned);
|
||||
}
|
||||
|
||||
public function createAccess(
|
||||
AppInfo $appInfo,
|
||||
string $scope = '',
|
||||
?string $userInfo = null
|
||||
): OAuth2AccessInfo {
|
||||
return $this->tokens->createAccess(
|
||||
$appInfo,
|
||||
userId: $userInfo,
|
||||
scope: $scope,
|
||||
lifetime: $appInfo->getAccessTokenLifetime()
|
||||
);
|
||||
}
|
||||
|
||||
public function createRefresh(
|
||||
AppInfo $appInfo,
|
||||
OAuth2AccessInfo $accessInfo
|
||||
): OAuth2RefreshInfo {
|
||||
return $this->tokens->createRefresh(
|
||||
$accessInfo->getAppId(),
|
||||
$appInfo,
|
||||
$accessInfo,
|
||||
userId: $accessInfo->getUserId(),
|
||||
scope: $accessInfo->getScope(),
|
||||
|
@ -172,11 +185,10 @@ class OAuth2Context {
|
|||
|
||||
$scope = $this->checkAndBuildScopeString($appInfo, $authsInfo->getScope(), true);
|
||||
|
||||
$tokensData = $this->getTokensData();
|
||||
$accessInfo = $tokensData->createAccess(
|
||||
$accessInfo = $this->createAccess(
|
||||
$appInfo,
|
||||
$scope,
|
||||
$authsInfo->getUserId(),
|
||||
scope: $scope,
|
||||
);
|
||||
|
||||
if($authsInfo->getScope() === $scope)
|
||||
|
@ -226,10 +238,10 @@ class OAuth2Context {
|
|||
|
||||
$scope = $this->checkAndBuildScopeString($appInfo, $scope, true);
|
||||
|
||||
$accessInfo = $tokensData->createAccess(
|
||||
$accessInfo = $this->createAccess(
|
||||
$appInfo,
|
||||
$scope,
|
||||
$refreshInfo->getUserId(),
|
||||
scope: $scope,
|
||||
);
|
||||
|
||||
if($refreshInfo->getScope() === $scope)
|
||||
|
@ -256,7 +268,7 @@ class OAuth2Context {
|
|||
|
||||
$requestedScope = $scope;
|
||||
$scope = $this->checkAndBuildScopeString($appInfo, $requestedScope, true);
|
||||
$accessInfo = $this->getTokensData()->createAccess($appInfo, scope: $scope);
|
||||
$accessInfo = $this->createAccess($appInfo, $scope);
|
||||
|
||||
if($requestedScope !== null && $scope === '')
|
||||
return [
|
||||
|
@ -323,10 +335,10 @@ class OAuth2Context {
|
|||
$scope = $this->checkAndBuildScopeString($appInfo, $deviceInfo->getScope(), true);
|
||||
|
||||
$tokensData = $this->getTokensData();
|
||||
$accessInfo = $tokensData->createAccess(
|
||||
$accessInfo = $this->createAccess(
|
||||
$appInfo,
|
||||
$scope,
|
||||
$deviceInfo->getUserId(),
|
||||
scope: $scope,
|
||||
);
|
||||
|
||||
// 'scope' only has to be in the response if it differs from what was requested
|
||||
|
|
Loading…
Reference in a new issue