Skip to content

Commit

Permalink
feat(openapi): HTTP Authentication Support for Swagger UI (#6665)
Browse files Browse the repository at this point in the history
* feat(openapi): http authentication support

add support for http authentication (for example http basic or bearer tokens)

Closes: #6664

* add symfony support

---------

Co-authored-by: soyuka <[email protected]>
  • Loading branch information
toitzi and soyuka authored Dec 13, 2024
1 parent c78ed0b commit bd0e929
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Laravel/ApiPlatformProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ public function register(): void
contactEmail: $config->get('api-platform.swagger_ui.contact.email', ''),
licenseName: $config->get('api-platform.swagger_ui.license.name', ''),
licenseUrl: $config->get('api-platform.swagger_ui.license.url', ''),
httpAuth: $config->get('api-platform.swagger_ui.http_auth', []),
);
});

Expand Down
6 changes: 6 additions & 0 deletions src/Laravel/config/api-platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@
// 'url' => 'https://www.example.com/support',
// 'email' => '[email protected]',
//],
//'http_auth' => [
// 'Personal Access Token' => [
// 'scheme' => 'bearer',
// 'bearerFormat' => 'JWT'
// ]
//]
],

'url_generation_strategy' => UrlGeneratorInterface::ABS_PATH,
Expand Down
5 changes: 5 additions & 0 deletions src/OpenApi/Factory/OpenApiFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,11 @@ private function getSecuritySchemes(): array
$securitySchemes[$key] = new SecurityScheme('apiKey', $description, $apiKey['name'], $apiKey['type']);
}

foreach ($this->openApiOptions->getHttpAuth() as $key => $httpAuth) {
$description = \sprintf('Value for the http %s parameter.', $httpAuth['scheme']);
$securitySchemes[$key] = new SecurityScheme('http', $description, null, null, $httpAuth['scheme'], $httpAuth['bearerFormat'] ?? null);
}

return $securitySchemes;
}

Expand Down
7 changes: 6 additions & 1 deletion src/OpenApi/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

final class Options
{
public function __construct(private readonly string $title, private readonly string $description = '', private readonly string $version = '', private readonly bool $oAuthEnabled = false, private readonly ?string $oAuthType = null, private readonly ?string $oAuthFlow = null, private readonly ?string $oAuthTokenUrl = null, private readonly ?string $oAuthAuthorizationUrl = null, private readonly ?string $oAuthRefreshUrl = null, private readonly array $oAuthScopes = [], private readonly array $apiKeys = [], private readonly ?string $contactName = null, private readonly ?string $contactUrl = null, private readonly ?string $contactEmail = null, private readonly ?string $termsOfService = null, private readonly ?string $licenseName = null, private readonly ?string $licenseUrl = null, private bool $overrideResponses = true)
public function __construct(private readonly string $title, private readonly string $description = '', private readonly string $version = '', private readonly bool $oAuthEnabled = false, private readonly ?string $oAuthType = null, private readonly ?string $oAuthFlow = null, private readonly ?string $oAuthTokenUrl = null, private readonly ?string $oAuthAuthorizationUrl = null, private readonly ?string $oAuthRefreshUrl = null, private readonly array $oAuthScopes = [], private readonly array $apiKeys = [], private readonly ?string $contactName = null, private readonly ?string $contactUrl = null, private readonly ?string $contactEmail = null, private readonly ?string $termsOfService = null, private readonly ?string $licenseName = null, private readonly ?string $licenseUrl = null, private bool $overrideResponses = true, private readonly array $httpAuth = [])
{
}

Expand Down Expand Up @@ -74,6 +74,11 @@ public function getApiKeys(): array
return $this->apiKeys;
}

public function getHttpAuth(): array
{
return $this->httpAuth;
}

public function getContactName(): ?string
{
return $this->contactName;
Expand Down
12 changes: 12 additions & 0 deletions src/OpenApi/Tests/Factory/OpenApiFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,14 @@ public function testInvoke(): void
'type' => 'query',
'name' => 'key',
],
], null, null, null, null, null, null, true, [
'bearer' => [
'scheme' => 'bearer',
'bearerFormat' => 'JWT',
],
'basic' => [
'scheme' => 'basic',
],
]),
new PaginationOptions(true, 'page', true, 'itemsPerPage', true, 'pagination')
);
Expand Down Expand Up @@ -622,12 +630,16 @@ public function testInvoke(): void
'oauth' => new SecurityScheme('oauth2', 'OAuth 2.0 authorization code Grant', null, null, null, null, new OAuthFlows(null, null, null, new OAuthFlow('/oauth/v2/auth', '/oauth/v2/token', '/oauth/v2/refresh', new \ArrayObject(['scope param'])))),
'header' => new SecurityScheme('apiKey', 'Value for the Authorization header parameter.', 'Authorization', 'header'),
'query' => new SecurityScheme('apiKey', 'Value for the key query parameter.', 'key', 'query'),
'bearer' => new SecurityScheme('http', 'Value for the http bearer parameter.', null, null, 'bearer', 'JWT'),
'basic' => new SecurityScheme('http', 'Value for the http basic parameter.', null, null, 'basic', null),
]));

$this->assertEquals([
['oauth' => []],
['header' => []],
['query' => []],
['bearer' => []],
['basic' => []],
], $openApi->getSecurity());

$paths = $openApi->getPaths();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ private function registerSwaggerConfiguration(ContainerBuilder $container, array
$container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
$container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
$container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
$container->setParameter('api_platform.swagger.http_auth', $config['swagger']['http_auth']);
if ($config['openapi']['swagger_ui_extra_configuration'] && $config['swagger']['swagger_ui_extra_configuration']) {
throw new RuntimeException('You can not set "swagger_ui_extra_configuration" twice - in "openapi" and "swagger" section.');
}
Expand Down
18 changes: 18 additions & 0 deletions src/Symfony/Bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,24 @@ private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
->end()
->end()
->end()
->arrayNode('http_auth')
->info('Creates http security schemes for OpenAPI.')
->useAttributeAsKey('key')
->validate()
->ifTrue(static fn ($v): bool => (bool) array_filter(array_keys($v), fn ($item) => !preg_match('/^[a-zA-Z0-9._-]+$/', $item)))
->thenInvalid('The api keys "key" is not valid according to the pattern enforced by OpenAPI 3.1 ^[a-zA-Z0-9._-]+$.')
->end()
->prototype('array')
->children()
->scalarNode('scheme')
->info('The OpenAPI HTTP auth scheme, for example "bearer"')
->end()
->scalarNode('bearerFormat')
->info('The OpenAPI HTTP bearer format')
->end()
->end()
->end()
->end()
->variableNode('swagger_ui_extra_configuration')
->defaultValue([])
->validate()
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/Resources/config/openapi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<argument>%api_platform.openapi.license.name%</argument>
<argument>%api_platform.openapi.license.url%</argument>
<argument>%api_platform.openapi.overrideResponses%</argument>
<argument>%api_platform.swagger.http_auth%</argument>
</service>
<service id="ApiPlatform\OpenApi\Options" alias="api_platform.openapi.options" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,5 +284,6 @@ public function testEventListenersConfiguration(): void
];

$this->assertContainerHas($services, $aliases);
$this->container->hasParameter('api_platform.swagger.http_auth');
}
}
21 changes: 21 additions & 0 deletions tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm
'swagger' => [
'versions' => [3],
'api_keys' => [],
'http_auth' => [],
'swagger_ui_extra_configuration' => [],
],
'eager_loading' => [
Expand Down Expand Up @@ -391,4 +392,24 @@ public function testEnableElasticsearch(): void

$this->assertTrue($config['elasticsearch']['enabled']);
}

/**
* Test config for http auth.
*/
public function testHttpAuth(): void
{
$config = $this->processor->processConfiguration($this->configuration, [
'api_platform' => [
'swagger' => [
'http_auth' => ['PAT' => [
'scheme' => 'bearer',
'bearerFormat' => 'JWT',
]],
],
],
]);

$this->assertArrayHasKey('http_auth', $config['swagger']);
$this->assertSame(['scheme' => 'bearer', 'bearerFormat' => 'JWT'], $config['swagger']['http_auth']['PAT']);
}
}

0 comments on commit bd0e929

Please sign in to comment.