Allow access and refresh tokens to not be associated with an app.
This commit is contained in:
parent
d9cf9674f3
commit
093266eb1e
8 changed files with 70 additions and 32 deletions
16
database/2025_04_23_204653_allow_tokens_to_have_null_app.php
Normal file
16
database/2025_04_23_204653_allow_tokens_to_have_null_app.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
use Index\Db\DbConnection;
|
||||
use Index\Db\Migration\DbMigration;
|
||||
|
||||
final class AllowTokensToHaveNullApp_20250423_204653 implements DbMigration {
|
||||
public function migrate(DbConnection $conn): void {
|
||||
$conn->execute(<<<SQL
|
||||
ALTER TABLE msz_oauth2_access
|
||||
CHANGE COLUMN app_id app_id INT(10) UNSIGNED NULL DEFAULT NULL AFTER acc_id;
|
||||
SQL);
|
||||
$conn->execute(<<<SQL
|
||||
ALTER TABLE msz_oauth2_refresh
|
||||
CHANGE COLUMN app_id app_id INT(10) UNSIGNED NULL DEFAULT NULL AFTER ref_id;
|
||||
SQL);
|
||||
}
|
||||
}
|
|
@ -57,10 +57,6 @@ class AppInfo {
|
|||
get => $this->type === AppType::Trusted;
|
||||
}
|
||||
|
||||
public bool $issueRefreshToken {
|
||||
get => $this->refreshTokenLifetime === null ? $this->confidential : $this->refreshTokenLifetime > 0;
|
||||
}
|
||||
|
||||
public function verifyClientSecret(#[\SensitiveParameter] string $input): bool {
|
||||
return $this->confidential && password_verify($input, $this->clientSecret);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class OAuth2AccessInfo {
|
|||
|
||||
public function __construct(
|
||||
public private(set) string $id,
|
||||
public private(set) string $appId,
|
||||
public private(set) ?string $appId,
|
||||
public private(set) ?string $userId,
|
||||
public private(set) string $token,
|
||||
public private(set) string $scope,
|
||||
|
@ -20,7 +20,7 @@ class OAuth2AccessInfo {
|
|||
public static function fromResult(DbResult $result): OAuth2AccessInfo {
|
||||
return new OAuth2AccessInfo(
|
||||
id: $result->getString(0),
|
||||
appId: $result->getString(1),
|
||||
appId: $result->getStringOrNull(1),
|
||||
userId: $result->getStringOrNull(2),
|
||||
token: $result->getString(3),
|
||||
scope: $result->getString(4),
|
||||
|
@ -49,4 +49,8 @@ class OAuth2AccessInfo {
|
|||
public int $remainingLifetime {
|
||||
get => max(0, $this->expiresTime - time());
|
||||
}
|
||||
|
||||
public bool $issueRefreshToken {
|
||||
get => in_array('offline_access', $this->scopes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,4 +67,8 @@ class OAuth2AuthorisationInfo {
|
|||
public int $remainingLifetime {
|
||||
get => max(0, $this->expiresTime - time());
|
||||
}
|
||||
|
||||
public bool $issueRefreshToken {
|
||||
get => in_array('offline_access', $this->scopes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ class OAuth2Context {
|
|||
OAuth2AccessInfo $accessInfo
|
||||
): OAuth2RefreshInfo {
|
||||
return $this->tokens->createRefresh(
|
||||
$appInfo,
|
||||
$accessInfo,
|
||||
$appInfo,
|
||||
userInfo: $accessInfo->userId,
|
||||
scope: $accessInfo->scope,
|
||||
lifetime: $appInfo->refreshTokenLifetime,
|
||||
|
@ -278,7 +278,7 @@ class OAuth2Context {
|
|||
if($authsInfo->scope === $scope)
|
||||
$scope = null;
|
||||
|
||||
$refreshInfo = $appInfo->issueRefreshToken
|
||||
$refreshInfo = $authsInfo->issueRefreshToken
|
||||
? $this->createRefresh($appInfo, $accessInfo)
|
||||
: null;
|
||||
|
||||
|
@ -340,7 +340,7 @@ class OAuth2Context {
|
|||
$scope = null;
|
||||
|
||||
$refreshInfo = null;
|
||||
if($appInfo->issueRefreshToken)
|
||||
if($accessInfo->issueRefreshToken)
|
||||
$refreshInfo = $this->createRefresh($appInfo, $accessInfo);
|
||||
|
||||
return $this->packBearerTokenResult($appInfo, $accessInfo, $refreshInfo, $scope);
|
||||
|
@ -448,7 +448,7 @@ class OAuth2Context {
|
|||
if($deviceInfo->scope === $scope)
|
||||
$scope = null;
|
||||
|
||||
$refreshInfo = $appInfo->issueRefreshToken
|
||||
$refreshInfo = $deviceInfo->issueRefreshToken
|
||||
? $this->createRefresh($appInfo, $accessInfo)
|
||||
: null;
|
||||
|
||||
|
|
|
@ -84,4 +84,8 @@ class OAuth2DeviceInfo {
|
|||
public int $remainingLifetime {
|
||||
get => max(0, $this->expiresTime - time());
|
||||
}
|
||||
|
||||
public bool $issueRefreshToken {
|
||||
get => in_array('offline_access', $this->scopes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use Index\Db\DbResult;
|
|||
class OAuth2RefreshInfo {
|
||||
public function __construct(
|
||||
public private(set) string $id,
|
||||
public private(set) string $appId,
|
||||
public private(set) ?string $appId,
|
||||
public private(set) ?string $userId,
|
||||
public private(set) ?string $accessId,
|
||||
public private(set) string $token,
|
||||
|
@ -19,7 +19,7 @@ class OAuth2RefreshInfo {
|
|||
public static function fromResult(DbResult $result): OAuth2RefreshInfo {
|
||||
return new OAuth2RefreshInfo(
|
||||
id: $result->getString(0),
|
||||
appId: $result->getString(1),
|
||||
appId: $result->getStringOrNull(1),
|
||||
userId: $result->getStringOrNull(2),
|
||||
accessId: $result->getStringOrNull(3),
|
||||
token: $result->getString(4),
|
||||
|
|
|
@ -42,7 +42,7 @@ class OAuth2TokensData {
|
|||
}
|
||||
|
||||
public function createAccess(
|
||||
AppInfo|string $appInfo,
|
||||
AppInfo|string|null $appInfo = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
?string $token = null,
|
||||
string $scope = '',
|
||||
|
@ -72,8 +72,8 @@ class OAuth2TokensData {
|
|||
|
||||
public function deleteAccess(
|
||||
OAuth2AccessInfo|string|null $accessInfo = null,
|
||||
AppInfo|string|null $appInfo = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
AppInfo|string|null|false $appInfo = false,
|
||||
UserInfo|string|null|false $userInfo = false,
|
||||
): void {
|
||||
$selectors = [];
|
||||
$values = [];
|
||||
|
@ -81,14 +81,20 @@ class OAuth2TokensData {
|
|||
$selectors[] = 'acc_id = ?';
|
||||
$values[] = $accessInfo instanceof OAuth2AccessInfo ? $accessInfo->id : $accessInfo;
|
||||
}
|
||||
if($appInfo !== null) {
|
||||
$selectors[] = 'app_id = ?';
|
||||
$values[] = $appInfo instanceof AppInfo ? $appInfo->id : $appInfo;
|
||||
}
|
||||
if($userInfo !== null) {
|
||||
$selectors[] = 'user_id = ?';
|
||||
$values[] = $userInfo instanceof UserInfo ? $userInfo->id : $userInfo;
|
||||
}
|
||||
if($appInfo !== false)
|
||||
if($appInfo === null) {
|
||||
$selectors[] = 'app_id IS NULL';
|
||||
} else {
|
||||
$selectors[] = 'app_id = ?';
|
||||
$values[] = $appInfo instanceof AppInfo ? $appInfo->id : $appInfo;
|
||||
}
|
||||
if($userInfo !== false)
|
||||
if($userInfo === null) {
|
||||
$selectors[] = 'user_id IS NULL';
|
||||
} else {
|
||||
$selectors[] = 'user_id = ?';
|
||||
$values[] = $userInfo instanceof UserInfo ? $userInfo->id : $userInfo;
|
||||
}
|
||||
|
||||
$query = 'DELETE FROM msz_oauth2_access';
|
||||
if(!empty($selectors))
|
||||
|
@ -136,8 +142,8 @@ class OAuth2TokensData {
|
|||
}
|
||||
|
||||
public function createRefresh(
|
||||
AppInfo|string $appInfo,
|
||||
OAuth2AccessInfo|string|null $accessInfo,
|
||||
AppInfo|string|null $appInfo = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
?string $token = null,
|
||||
string $scope = '',
|
||||
|
@ -168,8 +174,8 @@ class OAuth2TokensData {
|
|||
|
||||
public function deleteRefresh(
|
||||
OAuth2RefreshInfo|string|null $refreshInfo = null,
|
||||
AppInfo|string|null $appInfo = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
AppInfo|string|null|false $appInfo = false,
|
||||
UserInfo|string|null|false $userInfo = false,
|
||||
OAuth2AccessInfo|string|null $accessInfo = null
|
||||
): void {
|
||||
$selectors = [];
|
||||
|
@ -178,13 +184,21 @@ class OAuth2TokensData {
|
|||
$selectors[] = 'ref_id = ?';
|
||||
$values[] = $refreshInfo instanceof OAuth2RefreshInfo ? $refreshInfo->id : $refreshInfo;
|
||||
}
|
||||
if($appInfo !== null) {
|
||||
$selectors[] = 'app_id = ?';
|
||||
$values[] = $appInfo instanceof AppInfo ? $appInfo->id : $appInfo;
|
||||
if($appInfo !== false) {
|
||||
if($appInfo === null) {
|
||||
$selectors[] = 'app_id IS NULL';
|
||||
} else {
|
||||
$selectors[] = 'app_id = ?';
|
||||
$values[] = $appInfo instanceof AppInfo ? $appInfo->id : $appInfo;
|
||||
}
|
||||
}
|
||||
if($userInfo !== null) {
|
||||
$selectors[] = 'user_id = ?';
|
||||
$values[] = $userInfo instanceof UserInfo ? $userInfo->id : $userInfo;
|
||||
if($userInfo !== false) {
|
||||
if($userInfo === null) {
|
||||
$selectors[] = 'user_id IS NULL';
|
||||
} else {
|
||||
$selectors[] = 'user_id = ?';
|
||||
$values[] = $userInfo instanceof UserInfo ? $userInfo->id : $userInfo;
|
||||
}
|
||||
}
|
||||
if($accessInfo !== null) {
|
||||
$selectors[] = 'acc_id = ?';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue