OAuth metadata endpoints.
This commit is contained in:
parent
e5a947e973
commit
b2f8347526
4 changed files with 99 additions and 2 deletions
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
use Index\Db\DbConnection;
|
||||
use Index\Db\Migration\DbMigration;
|
||||
|
||||
final class AddIndexOnRestrictedFieldForScopes_20250226_173829 implements DbMigration {
|
||||
public function migrate(DbConnection $conn): void {
|
||||
$conn->execute(<<<SQL
|
||||
ALTER TABLE msz_scopes
|
||||
ADD INDEX scopes_restricted_index (scope_restricted);
|
||||
SQL);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,29 @@ class ScopesData {
|
|||
$this->cache = new DbStatementCache($dbConn);
|
||||
}
|
||||
|
||||
public function getScopes(
|
||||
?bool $restricted = null,
|
||||
?bool $deprecated = null
|
||||
): iterable {
|
||||
$args = 0;
|
||||
$query = <<<SQL
|
||||
SELECT scope_id, scope_string, scope_restricted, scope_summary,
|
||||
UNIX_TIMESTAMP(scope_created), UNIX_TIMESTAMP(scope_deprecated)
|
||||
FROM msz_scopes
|
||||
SQL;
|
||||
if($restricted !== null) {
|
||||
++$args;
|
||||
$query .= sprintf(' WHERE scope_restricted %s 0', $restricted ? '<>' : '=');
|
||||
}
|
||||
if($deprecated !== null)
|
||||
$query .= sprintf(' %s scope_deprecated %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $deprecated ? 'IS NOT' : 'IS');
|
||||
|
||||
$stmt = $this->cache->get($query);
|
||||
$stmt->execute();
|
||||
|
||||
return $stmt->getResultIterator(ScopeInfo::fromResult(...));
|
||||
}
|
||||
|
||||
public function getScopeInfo(string $value, ScopeInfoGetField $field): ScopeInfo {
|
||||
$stmt = $this->cache->get(sprintf(
|
||||
<<<SQL
|
||||
|
|
|
@ -2,15 +2,21 @@
|
|||
namespace Misuzu\OAuth2;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\XArray;
|
||||
use Index\Http\{FormHttpContent,HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Routing\{HttpGet,HttpOptions,HttpPost,RouteHandler,RouteHandlerCommon};
|
||||
use Index\Urls\{UrlFormat,UrlSource,UrlSourceCommon};
|
||||
use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
|
||||
use Misuzu\SiteInfo;
|
||||
use Misuzu\Apps\AppsContext;
|
||||
|
||||
final class OAuth2ApiRoutes implements RouteHandler, UrlSource {
|
||||
use RouteHandlerCommon, UrlSourceCommon;
|
||||
|
||||
public function __construct(
|
||||
private OAuth2Context $oauth2Ctx,
|
||||
private AppsContext $appsCtx,
|
||||
private UrlRegistry $urls,
|
||||
private SiteInfo $siteInfo,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +44,62 @@ final class OAuth2ApiRoutes implements RouteHandler, UrlSource {
|
|||
return $result;
|
||||
}
|
||||
|
||||
#[HttpOptions('/.well-known/oauth-protected-resource')]
|
||||
#[HttpGet('/.well-known/oauth-protected-resource')]
|
||||
public function getWellKnownProtectedResource(HttpResponseBuilder $response, HttpRequest $request): array|int {
|
||||
$response->setHeader('Access-Control-Allow-Origin', '*');
|
||||
if($request->method === 'OPTIONS')
|
||||
return 204;
|
||||
|
||||
return [
|
||||
'resource' => $this->siteInfo->url,
|
||||
'authorization_servers' => [$this->siteInfo->url],
|
||||
'scopes_supported' => [],
|
||||
'bearer_methods_supported' => ['header'],
|
||||
];
|
||||
}
|
||||
|
||||
#[HttpOptions('/.well-known/oauth-authorization-server')]
|
||||
#[HttpGet('/.well-known/oauth-authorization-server')]
|
||||
public function getWellKnownAuthorizationServer(HttpResponseBuilder $response, HttpRequest $request): array|int {
|
||||
$response->setHeader('Access-Control-Allow-Origin', '*');
|
||||
if($request->method === 'OPTIONS')
|
||||
return 204;
|
||||
|
||||
return [
|
||||
'issuer' => $this->siteInfo->url,
|
||||
'authorization_endpoint' => sprintf('%s%s', $this->siteInfo->url, $this->urls->format('oauth2-authorise')),
|
||||
'token_endpoint' => sprintf('%s%s', $this->siteInfo->url, $this->urls->format('oauth2-token')),
|
||||
'jwks_uri' => sprintf('%s%s', $this->siteInfo->url, $this->urls->format('openid-jwks')),
|
||||
'protected_resources' => [$this->siteInfo->url],
|
||||
'scopes_supported' => XArray::select(
|
||||
$this->appsCtx->scopes->getScopes(
|
||||
restricted: false,
|
||||
deprecated: false,
|
||||
),
|
||||
fn($scopeInfo) => $scopeInfo->string
|
||||
),
|
||||
'response_types_supported' => ['code', 'code id_token'],
|
||||
'response_modes_supported' => ['query'],
|
||||
'grant_types_supported' => [
|
||||
'authorization_code',
|
||||
'client_credentials',
|
||||
'refresh_token',
|
||||
'urn:ietf:params:oauth:grant-type:device_code',
|
||||
],
|
||||
'token_endpoint_auth_methods_supported' => [
|
||||
'none',
|
||||
'client_secret_basic',
|
||||
'client_secret_post',
|
||||
],
|
||||
//'revocation_endpoint' => 'TODO: implement this',
|
||||
//'revocation_endpoint_auth_methods_supported' => ['client_secret_basic'],
|
||||
//'introspection_endpoint ' => 'TODO: implement this',
|
||||
//'introspection_endpoint_auth_methods_supported' => ['Bearer'],
|
||||
'code_challenge_methods_supported' => ['plain', 'S256'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* device_code: string,
|
||||
|
|
|
@ -23,7 +23,7 @@ class OpenIDRoutes implements RouteHandler, UrlSource {
|
|||
private ProfileContext $profileCtx,
|
||||
private SiteInfo $siteInfo,
|
||||
private AuthInfo $authInfo,
|
||||
private UrlRegistry $urls
|
||||
private UrlRegistry $urls,
|
||||
) {}
|
||||
|
||||
#[HttpOptions('/.well-known/openid-configuration')]
|
||||
|
|
Loading…
Add table
Reference in a new issue