diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java index 34e971f607..acbfaec08c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java @@ -22,8 +22,10 @@ import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.CodegenSecurity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.swagger.v3.oas.models.security.SecurityScheme; import java.io.File; import java.util.Collections; @@ -46,6 +48,8 @@ public class PhpSlimServerCodegen extends AbstractPhpCodegen { protected String groupId = "org.openapitools"; protected String artifactId = "openapi-server"; + protected String authDirName = "Auth"; + protected String authPackage = ""; public PhpSlimServerCodegen() { super(); @@ -59,6 +63,7 @@ public class PhpSlimServerCodegen extends AbstractPhpCodegen { setInvokerPackage("OpenAPIServer"); apiPackage = invokerPackage + "\\" + apiDirName; modelPackage = invokerPackage + "\\" + modelDirName; + authPackage = invokerPackage + "\\" + authDirName; outputFolder = "generated-code" + File.separator + "slim"; modelTestTemplateFiles.put("model_test.mustache", ".php"); @@ -118,6 +123,15 @@ public class PhpSlimServerCodegen extends AbstractPhpCodegen { public void processOpts() { super.processOpts(); + if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { + // Update the invokerPackage for the default authPackage + authPackage = invokerPackage + "\\" + authDirName; + } + + // make auth src path available in mustache template + additionalProperties.put("authPackage", authPackage); + additionalProperties.put("authSrcPath", "./" + toSrcPath(authPackage, srcBasePath)); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("composer.mustache", "", "composer.json")); supportingFiles.add(new SupportingFile("index.mustache", "", "index.php")); @@ -158,6 +172,15 @@ public class PhpSlimServerCodegen extends AbstractPhpCodegen { return objs; } + @Override + public List fromSecurity(Map securitySchemeMap) { + List codegenSecurities = super.fromSecurity(securitySchemeMap); + if (Boolean.FALSE.equals(codegenSecurities.isEmpty())) { + supportingFiles.add(new SupportingFile("abstract_authenticator.mustache", toSrcPath(authPackage, srcBasePath), toAbstractName("Authenticator") + ".php")); + } + return codegenSecurities; + } + @Override public String toApiName(String name) { if (name.length() == 0) { diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/README.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/README.mustache index 1620492e5e..a1288abe27 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/README.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/README.mustache @@ -130,6 +130,7 @@ No model defined in this package {{/modelPackage}} {{/generateModelDocs}} +{{#hasAuthMethods}} {{#authMethods}} {{^hasMore}} ## Authentication @@ -138,7 +139,26 @@ No model defined in this package {{/authMethods}} {{#authMethods}} {{#isBasic}} -> Important! To make Basic Authentication work you need to implement `authenticator` function in [SlimRouter]({{srcBasePath}}/SlimRouter.php) class. -> Documentation [tuupola/slim-basic-auth](https://github.com/tuupola/slim-basic-auth#readme) +### Security schema `{{name}}` +> Important! To make Basic authentication work you need to extend [\{{authPackage}}\{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}]({{authSrcPath}}/{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}.php) class by [\{{authPackage}}\BasicAuthenticator](./src/Auth/BasicAuthenticator.php) class. + {{/isBasic}} +{{#isApiKey}} +### Security schema `{{name}}` +> Important! To make ApiKey authentication work you need to extend [\{{authPackage}}\{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}]({{authSrcPath}}/{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}.php) class by [\{{authPackage}}\ApiKeyAuthenticator](./src/Auth/ApiKeyAuthenticator.php) class. + +{{/isApiKey}} +{{#isOAuth}} +### Security schema `{{name}}` +> Important! To make OAuth authentication work you need to extend [\{{authPackage}}\{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}]({{authSrcPath}}/{{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}.php) class by [\{{authPackage}}\OAuthAuthenticator](./src/Auth/OAuthAuthenticator.php) class. + +Scope list: +{{#scopes}} +* `{{scope}}`{{#description}} - {{description}}{{/description}} +{{/scopes}} + +{{/isOAuth}} {{/authMethods}} +### Advanced middleware configuration +Ref to used Slim Token Middleware [dyorg/slim-token-authentication](https://github.com/dyorg/slim-token-authentication/tree/1.x#readme) +{{/hasAuthMethods}} diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache index 09b8925e9a..9bba236a75 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache @@ -2,12 +2,11 @@ /** * SlimRouter * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package {{invokerPackage}} - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package {{invokerPackage}} + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /**{{#apiInfo}}{{#appName}} @@ -34,26 +33,25 @@ namespace {{invokerPackage}}; use Slim\App; +use Slim\Interfaces\RouteInterface; use Psr\Container\ContainerInterface; use InvalidArgumentException; -use Tuupola\Middleware\HttpBasicAuthentication; +use Dyorg\TokenAuthentication; +use Dyorg\TokenAuthentication\TokenSearch; +use Psr\Http\Message\ServerRequestInterface; +use Exception; /** * SlimRouter Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package {{invokerPackage}} - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package {{invokerPackage}} + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ class SlimRouter { - /** - * @var $slimApp Slim\App instance - */ + /** @var App instance */ private $slimApp; /** @var array[] list of all api operations */ @@ -72,12 +70,40 @@ class SlimRouter 'authMethods' => [ {{#hasAuthMethods}} {{#authMethods}} + // {{type}} security schema named '{{name}}' {{#isBasic}} [ 'type' => '{{type}}', 'isBasic' => true, + 'isApiKey' => false, + 'isOAuth' => false, ], {{/isBasic}} + {{#isApiKey}} + [ + 'type' => '{{type}}', + 'isBasic' => false, + 'isApiKey' => true, + 'isOAuth' => false, + 'keyParamName' => '{{keyParamName}}', + 'isKeyInHeader' => {{#isKeyInHeader}}true{{/isKeyInHeader}}{{^isKeyInHeader}}false{{/isKeyInHeader}}, + 'isKeyInQuery' => {{#isKeyInQuery}}true{{/isKeyInQuery}}{{^isKeyInQuery}}false{{/isKeyInQuery}}, + 'isKeyInCookie' => {{#isKeyInCookie}}true{{/isKeyInCookie}}{{^isKeyInCookie}}false{{/isKeyInCookie}}, + ], + {{/isApiKey}} + {{#isOAuth}} + [ + 'type' => '{{type}}', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + {{#scopes}} + '{{scope}}',{{#description}} // {{description}}{{/description}} + {{/scopes}} + ], + ], + {{/isOAuth}} {{/authMethods}} {{/hasAuthMethods}} ], @@ -91,25 +117,34 @@ class SlimRouter * Class constructor * * @param ContainerInterface|array $container Either a ContainerInterface or an associative array of app settings - * @throws InvalidArgumentException when no container is provided that implements ContainerInterface + * + * @throws InvalidArgumentException When no container is provided that implements ContainerInterface + * @throws Exception When implementation class doesn't exists */ public function __construct($container = []) { $this->slimApp = new App($container); - $basicAuth = new HttpBasicAuthentication([ - "secure" => false, - "authenticator" => function ($arguments) { - $user = $arguments["user"]; - $password = $arguments["password"]; - return false; - } - ]); + {{#hasAuthMethods}} + $authPackage = '{{authPackage}}'; + $basicAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\BasicAuthenticator?"; + throw new Exception($message); + }; + $apiKeyAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\ApiKeyAuthenticator?"; + throw new Exception($message); + }; + $oAuthAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\OAuthAuthenticator?"; + throw new Exception($message); + }; + {{/hasAuthMethods}} foreach ($this->operations as $operation) { $callback = function ($request, $response, $arguments) use ($operation) { $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?"; - throw new \Exception($message); + throw new Exception($message); return $response->withStatus(501)->write($message); }; $middlewares = []; @@ -118,12 +153,59 @@ class SlimRouter $callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}"; } - + {{#hasAuthMethods}} foreach ($operation['authMethods'] as $authMethod) { - if ($authMethod['type'] === 'http') { - $middlewares[] = $basicAuth; + switch ($authMethod['type']) { + case 'http': + $authenticatorClassname = "\\{$authPackage}\\BasicAuthenticator"; + if (class_exists($authenticatorClassname)) { + $basicAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $basicAuthenticator, + 'regex' => '/Basic\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + case 'apiKey': + $authenticatorClassname = "\\{$authPackage}\\ApiKeyAuthenticator"; + if (class_exists($authenticatorClassname)) { + $apiKeyAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $apiKeyAuthenticator, + 'regex' => '/^(.*)$/i', + 'header' => $authMethod['isKeyInHeader'] ? $authMethod['keyParamName'] : null, + 'parameter' => $authMethod['isKeyInQuery'] ? $authMethod['keyParamName'] : null, + 'cookie' => $authMethod['isKeyInCookie'] ? $authMethod['keyParamName'] : null, + 'argument' => null, + ])); + break; + case 'oauth2': + $authenticatorClassname = "\\{$authPackage}\\OAuthAuthenticator"; + if (class_exists($authenticatorClassname)) { + $oAuthAuthenticator = new $authenticatorClassname($container, $authMethod['scopes']); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $oAuthAuthenticator, + 'regex' => '/Bearer\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + default: + throw new Exception('Unknown authorization schema type'); } } + {{/hasAuthMethods}} $this->addRoute( [$operation['httpMethod']], @@ -134,6 +216,22 @@ class SlimRouter } } + /** + * Merges user defined options with dynamic params + * + * @param array $options Params which need to merge into user options + * + * @return array Merged array + */ + private function getTokenAuthenticationOptions(array $options) + { + if (is_array($this->slimApp->getContainer()['tokenAuthenticationOptions']) === false) { + return $options; + } + + return array_merge($this->slimApp->getContainer()['tokenAuthenticationOptions'], $options); + } + /** * Add route with multiple methods * @@ -142,11 +240,11 @@ class SlimRouter * @param callable|string $callable The route callback routine * @param array|null $middlewares List of middlewares * - * @return Slim\Interfaces\RouteInterface + * @return RouteInterface * - * @throws InvalidArgumentException if the route pattern isn't a string + * @throws InvalidArgumentException If the route pattern isn't a string */ - public function addRoute($methods, $pattern, $callable, $middlewares = []) + public function addRoute(array $methods, string $pattern, $callable, $middlewares = []) { $route = $this->slimApp->map($methods, $pattern, $callable); foreach ($middlewares as $middleware) { @@ -157,6 +255,7 @@ class SlimRouter /** * Returns Slim Framework instance + * * @return App */ public function getSlimApp() diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/abstract_authenticator.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/abstract_authenticator.mustache new file mode 100644 index 0000000000..ad41f1a72b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/php-slim-server/abstract_authenticator.mustache @@ -0,0 +1,117 @@ +container = $container; + $this->requiredScope = $requiredScope; + } + + /** + * Makes the api key validation of your application + * + * Just an example of implementation. Override this method to fit your needs + * + * @param ServerRequestInterface $request HTTP request + * @param TokenSearch $tokenSearch Middleware instance which contains api key in token + * + * @return bool Must return either true or false + * @throws UnauthorizedExceptionInterface when cannot parse token + */ + public function __invoke(ServerRequestInterface &$request, TokenSearch $tokenSearch) + { + /** + * Try find authorization token via header, parameters, cookie or attribute + * If token not found, return response with status 401 (unauthorized) + */ + $token = $tokenSearch->getToken($request); + + /** + * Verify if token is valid on database + * If token isn't valid, expired or has insufficient scope must throw an UnauthorizedExceptionInterface + */ + $user = $this->getUserByToken($token); + + /** + * Set authenticated user at attributes + */ + $request = $request->withAttribute('authenticated_user', $user); + + return true; + } +} +{{/apiInfo}} diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/api.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/api.mustache index d7eab31400..f265faec95 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/api.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/api.mustache @@ -2,12 +2,11 @@ /** * {{classname}} * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package {{apiPackage}} - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package {{apiPackage}} + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -34,30 +33,32 @@ */ namespace {{apiPackage}}; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * {{classname}} Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package {{apiPackage}} - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package {{apiPackage}} + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class {{classname}} { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -77,13 +78,14 @@ abstract class {{classname}} * Output-Formats: [{{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}] {{/hasProduces}} * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function {{operationId}}($request, $response, $args) + public function {{operationId}}(ServerRequestInterface $request, ResponseInterface $response, array $args) { {{#hasHeaderParams}} $headers = $request->getHeaders(); @@ -116,7 +118,7 @@ abstract class {{classname}} $body = $request->getParsedBody(); {{/hasBodyParam}} $message = "How about implementing {{nickname}} as a {{httpMethod}} method in {{apiPackage}}\{{userClassname}} class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/api_test.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/api_test.mustache index 35cdde8439..5372e34ad8 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/api_test.mustache @@ -1,12 +1,12 @@ '1.1', + + /** + * Size of each chunk read from the Response body when sending to the browser. + * Default: 4096 + */ + // 'responseChunkSize' => 4096, + + /** + * If false, then no output buffering is enabled. If 'append' or 'prepend', then + * any echo or print statements are captured and are either appended or prepended + * to the Response returned from the route callable. + * Default: 'append' + */ + // 'outputBuffering' => 'append', + + /** + * When true, the route is calculated before any middleware is executed. This + * means that you can inspect route parameters in middleware if you need to. + * Default: false + */ + // 'determineRouteBeforeAppMiddleware' => false, + + /** + * When true, additional information about exceptions are displayed by the default + * error handler. + * Default: false + */ + // 'displayErrorDetails' => false, + + /** + * When true, Slim will add a Content-Length header to the response. If you are using + * a runtime analytics tool, such as New Relic, then this should be disabled. + * Default: true + */ + // 'addContentLengthHeader' => true, + + /** + * Filename for caching the FastRoute routes. Must be set to to a valid filename within + * a writeable directory. If the file does not exist, then it is created with the correct + * cache information on first run. + * Set to false to disable the FastRoute cache system. + * Default: false + */ + // 'routerCacheFile' => false, +]; + +/** + * Token Middleware 1.x Options + * Options `header`, `regex`, `parameter`, `cookie`, `attribute`, `path`, `except`, `authenticator` + * are handled by SlimRouter class. These options are ignored by app and they omitted from current + * example. + * Ref: https://github.com/dyorg/slim-token-authentication/tree/1.x + */ +$config['tokenAuthenticationOptions'] = [ + /** + * Tokens are essentially passwords. You should treat them as such and you should always + * use HTTPS. If the middleware detects insecure usage over HTTP it will return unathorized + * with a message Required HTTPS for token authentication. This rule is relaxed for requests + * on localhost. To allow insecure usage you must enable it manually by setting secure to + * false. + * Default: true + */ + // 'secure' => true, + + /** + * Alternatively you can list your development host to have relaxed security. + * Default: ['localhost', '127.0.0.1'] + */ + // 'relaxed' => ['localhost', '127.0.0.1'], + + /** + * By default on ocurred a fail on authentication, is sent a response on json format with a + * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status + * `401 Unauthorized`. You can customize it by setting a callable function on error option. + * Default: null + */ + // 'error' => null, +]; + +$router = new SlimRouter($config); $app = $router->getSlimApp(); $app->run(); diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/model.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/model.mustache index a1f40f818f..9d2f570a7a 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/model.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/model.mustache @@ -1,11 +1,26 @@ Important! To make ApiKey authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\ApiKeyAuthenticator](./src/Auth/ApiKeyAuthenticator.php) class. + +### Security schema `petstore_auth` +> Important! To make OAuth authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\OAuthAuthenticator](./src/Auth/OAuthAuthenticator.php) class. + +Scope list: +* `write:pets` - modify pets in your account *_/ ' \" =end -- \\r\\n \\n \\r +* `read:pets` - read your pets *_/ ' \" =end -- \\r\\n \\n \\r + +### Advanced middleware configuration +Ref to used Slim Token Middleware [dyorg/slim-token-authentication](https://github.com/dyorg/slim-token-authentication/tree/1.x#readme) diff --git a/samples/server/petstore-security-test/php-slim/composer.json b/samples/server/petstore-security-test/php-slim/composer.json index 9c1a1d936c..91d25bb9cb 100644 --- a/samples/server/petstore-security-test/php-slim/composer.json +++ b/samples/server/petstore-security-test/php-slim/composer.json @@ -1,9 +1,15 @@ { "minimum-stability": "RC", + "repositories": [ + { + "type": "github", + "url": "https://github.com/ybelenko/slim-token-authentication" + } + ], "require": { "php": "^7.0", "slim/slim": "3.*", - "tuupola/slim-basic-auth": "^2.0 || ^3.0" + "dyorg/slim-token-authentication": "dev-per_route_apply" }, "require-dev": { "phpunit/phpunit": "^6.0 || ^7.0", diff --git a/samples/server/petstore-security-test/php-slim/index.php b/samples/server/petstore-security-test/php-slim/index.php index 9cc64c9486..767a9340c0 100644 --- a/samples/server/petstore-security-test/php-slim/index.php +++ b/samples/server/petstore-security-test/php-slim/index.php @@ -1,13 +1,110 @@ '1.1', + + /** + * Size of each chunk read from the Response body when sending to the browser. + * Default: 4096 + */ + // 'responseChunkSize' => 4096, + + /** + * If false, then no output buffering is enabled. If 'append' or 'prepend', then + * any echo or print statements are captured and are either appended or prepended + * to the Response returned from the route callable. + * Default: 'append' + */ + // 'outputBuffering' => 'append', + + /** + * When true, the route is calculated before any middleware is executed. This + * means that you can inspect route parameters in middleware if you need to. + * Default: false + */ + // 'determineRouteBeforeAppMiddleware' => false, + + /** + * When true, additional information about exceptions are displayed by the default + * error handler. + * Default: false + */ + // 'displayErrorDetails' => false, + + /** + * When true, Slim will add a Content-Length header to the response. If you are using + * a runtime analytics tool, such as New Relic, then this should be disabled. + * Default: true + */ + // 'addContentLengthHeader' => true, + + /** + * Filename for caching the FastRoute routes. Must be set to to a valid filename within + * a writeable directory. If the file does not exist, then it is created with the correct + * cache information on first run. + * Set to false to disable the FastRoute cache system. + * Default: false + */ + // 'routerCacheFile' => false, +]; + +/** + * Token Middleware 1.x Options + * Options `header`, `regex`, `parameter`, `cookie`, `attribute`, `path`, `except`, `authenticator` + * are handled by SlimRouter class. These options are ignored by app and they omitted from current + * example. + * Ref: https://github.com/dyorg/slim-token-authentication/tree/1.x + */ +$config['tokenAuthenticationOptions'] = [ + /** + * Tokens are essentially passwords. You should treat them as such and you should always + * use HTTPS. If the middleware detects insecure usage over HTTP it will return unathorized + * with a message Required HTTPS for token authentication. This rule is relaxed for requests + * on localhost. To allow insecure usage you must enable it manually by setting secure to + * false. + * Default: true + */ + // 'secure' => true, + + /** + * Alternatively you can list your development host to have relaxed security. + * Default: ['localhost', '127.0.0.1'] + */ + // 'relaxed' => ['localhost', '127.0.0.1'], + + /** + * By default on ocurred a fail on authentication, is sent a response on json format with a + * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status + * `401 Unauthorized`. You can customize it by setting a callable function on error option. + * Default: null + */ + // 'error' => null, +]; + +$router = new SlimRouter($config); $app = $router->getSlimApp(); $app->run(); diff --git a/samples/server/petstore-security-test/php-slim/lib/Api/AbstractFakeApi.php b/samples/server/petstore-security-test/php-slim/lib/Api/AbstractFakeApi.php index 961d47aaa1..2c1606445a 100644 --- a/samples/server/petstore-security-test/php-slim/lib/Api/AbstractFakeApi.php +++ b/samples/server/petstore-security-test/php-slim/lib/Api/AbstractFakeApi.php @@ -2,12 +2,11 @@ /** * AbstractFakeApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -26,30 +25,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractFakeApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractFakeApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -60,17 +61,18 @@ abstract class AbstractFakeApi * Summary: To test code injection *_/ ' \" =end -- \\r\\n \\n \\r * Notes: To test code injection *_/ ' \" =end -- \\r\\n \\n \\r * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testCodeInjectEndRnNR($request, $response, $args) + public function testCodeInjectEndRnNR(ServerRequestInterface $request, ResponseInterface $response, array $args) { $testCodeInjectEndRnNR = $request->getParsedBodyParam('test code inject */ ' " =end -- \r\n \n \r'); $message = "How about implementing testCodeInjectEndRnNR as a PUT method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore-security-test/php-slim/lib/Auth/AbstractAuthenticator.php b/samples/server/petstore-security-test/php-slim/lib/Auth/AbstractAuthenticator.php new file mode 100644 index 0000000000..faaf4d4b70 --- /dev/null +++ b/samples/server/petstore-security-test/php-slim/lib/Auth/AbstractAuthenticator.php @@ -0,0 +1,109 @@ +container = $container; + $this->requiredScope = $requiredScope; + } + + /** + * Makes the api key validation of your application + * + * Just an example of implementation. Override this method to fit your needs + * + * @param ServerRequestInterface $request HTTP request + * @param TokenSearch $tokenSearch Middleware instance which contains api key in token + * + * @return bool Must return either true or false + * @throws UnauthorizedExceptionInterface when cannot parse token + */ + public function __invoke(ServerRequestInterface &$request, TokenSearch $tokenSearch) + { + /** + * Try find authorization token via header, parameters, cookie or attribute + * If token not found, return response with status 401 (unauthorized) + */ + $token = $tokenSearch->getToken($request); + + /** + * Verify if token is valid on database + * If token isn't valid, expired or has insufficient scope must throw an UnauthorizedExceptionInterface + */ + $user = $this->getUserByToken($token); + + /** + * Set authenticated user at attributes + */ + $request = $request->withAttribute('authenticated_user', $user); + + return true; + } +} diff --git a/samples/server/petstore-security-test/php-slim/lib/Model/ModelReturn.php b/samples/server/petstore-security-test/php-slim/lib/Model/ModelReturn.php index 8cf6a29ab8..20dea2a7d5 100644 --- a/samples/server/petstore-security-test/php-slim/lib/Model/ModelReturn.php +++ b/samples/server/petstore-security-test/php-slim/lib/Model/ModelReturn.php @@ -1,11 +1,26 @@ slimApp = new App($container); - $basicAuth = new HttpBasicAuthentication([ - "secure" => false, - "authenticator" => function ($arguments) { - $user = $arguments["user"]; - $password = $arguments["password"]; - return false; - } - ]); + $authPackage = 'OpenAPIServer\Auth'; + $basicAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\BasicAuthenticator?"; + throw new Exception($message); + }; + $apiKeyAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\ApiKeyAuthenticator?"; + throw new Exception($message); + }; + $oAuthAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\OAuthAuthenticator?"; + throw new Exception($message); + }; foreach ($this->operations as $operation) { $callback = function ($request, $response, $arguments) use ($operation) { $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?"; - throw new \Exception($message); + throw new Exception($message); return $response->withStatus(501)->write($message); }; $middlewares = []; @@ -95,10 +100,55 @@ class SlimRouter $callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}"; } - foreach ($operation['authMethods'] as $authMethod) { - if ($authMethod['type'] === 'http') { - $middlewares[] = $basicAuth; + switch ($authMethod['type']) { + case 'http': + $authenticatorClassname = "\\{$authPackage}\\BasicAuthenticator"; + if (class_exists($authenticatorClassname)) { + $basicAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $basicAuthenticator, + 'regex' => '/Basic\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + case 'apiKey': + $authenticatorClassname = "\\{$authPackage}\\ApiKeyAuthenticator"; + if (class_exists($authenticatorClassname)) { + $apiKeyAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $apiKeyAuthenticator, + 'regex' => '/^(.*)$/i', + 'header' => $authMethod['isKeyInHeader'] ? $authMethod['keyParamName'] : null, + 'parameter' => $authMethod['isKeyInQuery'] ? $authMethod['keyParamName'] : null, + 'cookie' => $authMethod['isKeyInCookie'] ? $authMethod['keyParamName'] : null, + 'argument' => null, + ])); + break; + case 'oauth2': + $authenticatorClassname = "\\{$authPackage}\\OAuthAuthenticator"; + if (class_exists($authenticatorClassname)) { + $oAuthAuthenticator = new $authenticatorClassname($container, $authMethod['scopes']); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $oAuthAuthenticator, + 'regex' => '/Bearer\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + default: + throw new Exception('Unknown authorization schema type'); } } @@ -111,6 +161,22 @@ class SlimRouter } } + /** + * Merges user defined options with dynamic params + * + * @param array $options Params which need to merge into user options + * + * @return array Merged array + */ + private function getTokenAuthenticationOptions(array $options) + { + if (is_array($this->slimApp->getContainer()['tokenAuthenticationOptions']) === false) { + return $options; + } + + return array_merge($this->slimApp->getContainer()['tokenAuthenticationOptions'], $options); + } + /** * Add route with multiple methods * @@ -119,11 +185,11 @@ class SlimRouter * @param callable|string $callable The route callback routine * @param array|null $middlewares List of middlewares * - * @return Slim\Interfaces\RouteInterface + * @return RouteInterface * - * @throws InvalidArgumentException if the route pattern isn't a string + * @throws InvalidArgumentException If the route pattern isn't a string */ - public function addRoute($methods, $pattern, $callable, $middlewares = []) + public function addRoute(array $methods, string $pattern, $callable, $middlewares = []) { $route = $this->slimApp->map($methods, $pattern, $callable); foreach ($middlewares as $middleware) { @@ -134,6 +200,7 @@ class SlimRouter /** * Returns Slim Framework instance + * * @return App */ public function getSlimApp() diff --git a/samples/server/petstore/php-slim/README.md b/samples/server/petstore/php-slim/README.md index 6930213b7d..a71823a7b4 100644 --- a/samples/server/petstore/php-slim/README.md +++ b/samples/server/petstore/php-slim/README.md @@ -190,5 +190,21 @@ Class | Method | HTTP request | Description ## Authentication -> Important! To make Basic Authentication work you need to implement `authenticator` function in [SlimRouter](lib/SlimRouter.php) class. -> Documentation [tuupola/slim-basic-auth](https://github.com/tuupola/slim-basic-auth#readme) +### Security schema `api_key` +> Important! To make ApiKey authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\ApiKeyAuthenticator](./src/Auth/ApiKeyAuthenticator.php) class. + +### Security schema `api_key_query` +> Important! To make ApiKey authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\ApiKeyAuthenticator](./src/Auth/ApiKeyAuthenticator.php) class. + +### Security schema `http_basic_test` +> Important! To make Basic authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\BasicAuthenticator](./src/Auth/BasicAuthenticator.php) class. + +### Security schema `petstore_auth` +> Important! To make OAuth authentication work you need to extend [\OpenAPIServer\Auth\AbstractAuthenticator](./lib/Auth/AbstractAuthenticator.php) class by [\OpenAPIServer\Auth\OAuthAuthenticator](./src/Auth/OAuthAuthenticator.php) class. + +Scope list: +* `write:pets` - modify pets in your account +* `read:pets` - read your pets + +### Advanced middleware configuration +Ref to used Slim Token Middleware [dyorg/slim-token-authentication](https://github.com/dyorg/slim-token-authentication/tree/1.x#readme) diff --git a/samples/server/petstore/php-slim/composer.json b/samples/server/petstore/php-slim/composer.json index 9c1a1d936c..91d25bb9cb 100644 --- a/samples/server/petstore/php-slim/composer.json +++ b/samples/server/petstore/php-slim/composer.json @@ -1,9 +1,15 @@ { "minimum-stability": "RC", + "repositories": [ + { + "type": "github", + "url": "https://github.com/ybelenko/slim-token-authentication" + } + ], "require": { "php": "^7.0", "slim/slim": "3.*", - "tuupola/slim-basic-auth": "^2.0 || ^3.0" + "dyorg/slim-token-authentication": "dev-per_route_apply" }, "require-dev": { "phpunit/phpunit": "^6.0 || ^7.0", diff --git a/samples/server/petstore/php-slim/index.php b/samples/server/petstore/php-slim/index.php index 7a69dc9481..35e9a27a61 100644 --- a/samples/server/petstore/php-slim/index.php +++ b/samples/server/petstore/php-slim/index.php @@ -1,13 +1,110 @@ '1.1', + + /** + * Size of each chunk read from the Response body when sending to the browser. + * Default: 4096 + */ + // 'responseChunkSize' => 4096, + + /** + * If false, then no output buffering is enabled. If 'append' or 'prepend', then + * any echo or print statements are captured and are either appended or prepended + * to the Response returned from the route callable. + * Default: 'append' + */ + // 'outputBuffering' => 'append', + + /** + * When true, the route is calculated before any middleware is executed. This + * means that you can inspect route parameters in middleware if you need to. + * Default: false + */ + // 'determineRouteBeforeAppMiddleware' => false, + + /** + * When true, additional information about exceptions are displayed by the default + * error handler. + * Default: false + */ + // 'displayErrorDetails' => false, + + /** + * When true, Slim will add a Content-Length header to the response. If you are using + * a runtime analytics tool, such as New Relic, then this should be disabled. + * Default: true + */ + // 'addContentLengthHeader' => true, + + /** + * Filename for caching the FastRoute routes. Must be set to to a valid filename within + * a writeable directory. If the file does not exist, then it is created with the correct + * cache information on first run. + * Set to false to disable the FastRoute cache system. + * Default: false + */ + // 'routerCacheFile' => false, +]; + +/** + * Token Middleware 1.x Options + * Options `header`, `regex`, `parameter`, `cookie`, `attribute`, `path`, `except`, `authenticator` + * are handled by SlimRouter class. These options are ignored by app and they omitted from current + * example. + * Ref: https://github.com/dyorg/slim-token-authentication/tree/1.x + */ +$config['tokenAuthenticationOptions'] = [ + /** + * Tokens are essentially passwords. You should treat them as such and you should always + * use HTTPS. If the middleware detects insecure usage over HTTP it will return unathorized + * with a message Required HTTPS for token authentication. This rule is relaxed for requests + * on localhost. To allow insecure usage you must enable it manually by setting secure to + * false. + * Default: true + */ + // 'secure' => true, + + /** + * Alternatively you can list your development host to have relaxed security. + * Default: ['localhost', '127.0.0.1'] + */ + // 'relaxed' => ['localhost', '127.0.0.1'], + + /** + * By default on ocurred a fail on authentication, is sent a response on json format with a + * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status + * `401 Unauthorized`. You can customize it by setting a callable function on error option. + * Default: null + */ + // 'error' => null, +]; + +$router = new SlimRouter($config); $app = $router->getSlimApp(); $app->run(); diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractAnotherFakeApi.php b/samples/server/petstore/php-slim/lib/Api/AbstractAnotherFakeApi.php index 901b4a6c07..d4d083a60c 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractAnotherFakeApi.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractAnotherFakeApi.php @@ -2,12 +2,11 @@ /** * AbstractAnotherFakeApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractAnotherFakeApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractAnotherFakeApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -60,17 +61,18 @@ abstract class AbstractAnotherFakeApi * Notes: To test special tags and operation ID starting with number * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function call123TestSpecialTags($request, $response, $args) + public function call123TestSpecialTags(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing call123TestSpecialTags as a PATCH method in OpenAPIServer\Api\AnotherFakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractFakeApi.php b/samples/server/petstore/php-slim/lib/Api/AbstractFakeApi.php index 244431feec..2c9380e542 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractFakeApi.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractFakeApi.php @@ -2,12 +2,11 @@ /** * AbstractFakeApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractFakeApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractFakeApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -59,17 +60,18 @@ abstract class AbstractFakeApi * Notes: Test serialization of outer boolean types * Output-Formats: [*_/_*] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function fakeOuterBooleanSerialize($request, $response, $args) + public function fakeOuterBooleanSerialize(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing fakeOuterBooleanSerialize as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -79,17 +81,18 @@ abstract class AbstractFakeApi * Notes: Test serialization of object with outer number type * Output-Formats: [*_/_*] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function fakeOuterCompositeSerialize($request, $response, $args) + public function fakeOuterCompositeSerialize(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing fakeOuterCompositeSerialize as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -99,17 +102,18 @@ abstract class AbstractFakeApi * Notes: Test serialization of outer number types * Output-Formats: [*_/_*] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function fakeOuterNumberSerialize($request, $response, $args) + public function fakeOuterNumberSerialize(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing fakeOuterNumberSerialize as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -119,17 +123,18 @@ abstract class AbstractFakeApi * Notes: Test serialization of outer string types * Output-Formats: [*_/_*] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function fakeOuterStringSerialize($request, $response, $args) + public function fakeOuterStringSerialize(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing fakeOuterStringSerialize as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -138,17 +143,18 @@ abstract class AbstractFakeApi * PUT testBodyWithFileSchema * Notes: For this test, the body for this request much reference a schema named `File`. * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testBodyWithFileSchema($request, $response, $args) + public function testBodyWithFileSchema(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing testBodyWithFileSchema as a PUT method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -156,19 +162,20 @@ abstract class AbstractFakeApi /** * PUT testBodyWithQueryParams * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testBodyWithQueryParams($request, $response, $args) + public function testBodyWithQueryParams(ServerRequestInterface $request, ResponseInterface $response, array $args) { $queryParams = $request->getQueryParams(); $query = $request->getQueryParam('query'); $body = $request->getParsedBody(); $message = "How about implementing testBodyWithQueryParams as a PUT method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -179,17 +186,18 @@ abstract class AbstractFakeApi * Notes: To test \"client\" model * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testClientModel($request, $response, $args) + public function testClientModel(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing testClientModel as a PATCH method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -199,13 +207,14 @@ abstract class AbstractFakeApi * Summary: Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 * Notes: Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testEndpointParameters($request, $response, $args) + public function testEndpointParameters(ServerRequestInterface $request, ResponseInterface $response, array $args) { $integer = $request->getParsedBodyParam('integer'); $int32 = $request->getParsedBodyParam('int32'); @@ -222,7 +231,7 @@ abstract class AbstractFakeApi $password = $request->getParsedBodyParam('password'); $callback = $request->getParsedBodyParam('callback'); $message = "How about implementing testEndpointParameters as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -232,13 +241,14 @@ abstract class AbstractFakeApi * Summary: To test enum parameters * Notes: To test enum parameters * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testEnumParameters($request, $response, $args) + public function testEnumParameters(ServerRequestInterface $request, ResponseInterface $response, array $args) { $headers = $request->getHeaders(); $enumHeaderStringArray = $request->hasHeader('enum_header_string_array') ? $headers['enum_header_string_array'] : null; @@ -251,7 +261,7 @@ abstract class AbstractFakeApi $enumFormStringArray = $request->getParsedBodyParam('enum_form_string_array'); $enumFormString = $request->getParsedBodyParam('enum_form_string'); $message = "How about implementing testEnumParameters as a GET method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -261,13 +271,14 @@ abstract class AbstractFakeApi * Summary: Fake endpoint to test group parameters (optional) * Notes: Fake endpoint to test group parameters (optional) * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testGroupParameters($request, $response, $args) + public function testGroupParameters(ServerRequestInterface $request, ResponseInterface $response, array $args) { $headers = $request->getHeaders(); $requiredBooleanGroup = $request->hasHeader('required_boolean_group') ? $headers['required_boolean_group'] : null; @@ -278,7 +289,7 @@ abstract class AbstractFakeApi $stringGroup = $request->getQueryParam('string_group'); $int64Group = $request->getQueryParam('int64_group'); $message = "How about implementing testGroupParameters as a DELETE method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -287,17 +298,18 @@ abstract class AbstractFakeApi * POST testInlineAdditionalProperties * Summary: test inline additionalProperties * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testInlineAdditionalProperties($request, $response, $args) + public function testInlineAdditionalProperties(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing testInlineAdditionalProperties as a POST method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -306,18 +318,19 @@ abstract class AbstractFakeApi * GET testJsonFormData * Summary: test json serialization of form data * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testJsonFormData($request, $response, $args) + public function testJsonFormData(ServerRequestInterface $request, ResponseInterface $response, array $args) { $param = $request->getParsedBodyParam('param'); $param2 = $request->getParsedBodyParam('param2'); $message = "How about implementing testJsonFormData as a GET method in OpenAPIServer\Api\FakeApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractFakeClassnameTags123Api.php b/samples/server/petstore/php-slim/lib/Api/AbstractFakeClassnameTags123Api.php index 7d4c971cce..36d4725097 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractFakeClassnameTags123Api.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractFakeClassnameTags123Api.php @@ -2,12 +2,11 @@ /** * AbstractFakeClassnameTags123Api * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractFakeClassnameTags123Api Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractFakeClassnameTags123Api { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -60,17 +61,18 @@ abstract class AbstractFakeClassnameTags123Api * Notes: To test class name in snake case * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function testClassname($request, $response, $args) + public function testClassname(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing testClassname as a PATCH method in OpenAPIServer\Api\FakeClassnameTags123Api class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractPetApi.php b/samples/server/petstore/php-slim/lib/Api/AbstractPetApi.php index 6633119899..a59e0d744b 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractPetApi.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractPetApi.php @@ -2,12 +2,11 @@ /** * AbstractPetApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractPetApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractPetApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -58,17 +59,18 @@ abstract class AbstractPetApi * POST addPet * Summary: Add a new pet to the store * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function addPet($request, $response, $args) + public function addPet(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing addPet as a POST method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -77,19 +79,20 @@ abstract class AbstractPetApi * DELETE deletePet * Summary: Deletes a pet * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function deletePet($request, $response, $args) + public function deletePet(ServerRequestInterface $request, ResponseInterface $response, array $args) { $headers = $request->getHeaders(); $apiKey = $request->hasHeader('api_key') ? $headers['api_key'] : null; $petId = $args['petId']; $message = "How about implementing deletePet as a DELETE method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -100,18 +103,19 @@ abstract class AbstractPetApi * Notes: Multiple status values can be provided with comma separated strings * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function findPetsByStatus($request, $response, $args) + public function findPetsByStatus(ServerRequestInterface $request, ResponseInterface $response, array $args) { $queryParams = $request->getQueryParams(); $status = $request->getQueryParam('status'); $message = "How about implementing findPetsByStatus as a GET method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -122,18 +126,19 @@ abstract class AbstractPetApi * Notes: Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function findPetsByTags($request, $response, $args) + public function findPetsByTags(ServerRequestInterface $request, ResponseInterface $response, array $args) { $queryParams = $request->getQueryParams(); $tags = $request->getQueryParam('tags'); $message = "How about implementing findPetsByTags as a GET method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -144,17 +149,18 @@ abstract class AbstractPetApi * Notes: Returns a single pet * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function getPetById($request, $response, $args) + public function getPetById(ServerRequestInterface $request, ResponseInterface $response, array $args) { $petId = $args['petId']; $message = "How about implementing getPetById as a GET method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -163,17 +169,18 @@ abstract class AbstractPetApi * PUT updatePet * Summary: Update an existing pet * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function updatePet($request, $response, $args) + public function updatePet(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing updatePet as a PUT method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -182,19 +189,20 @@ abstract class AbstractPetApi * POST updatePetWithForm * Summary: Updates a pet in the store with form data * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function updatePetWithForm($request, $response, $args) + public function updatePetWithForm(ServerRequestInterface $request, ResponseInterface $response, array $args) { $petId = $args['petId']; $name = $request->getParsedBodyParam('name'); $status = $request->getParsedBodyParam('status'); $message = "How about implementing updatePetWithForm as a POST method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -204,19 +212,20 @@ abstract class AbstractPetApi * Summary: uploads an image * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function uploadFile($request, $response, $args) + public function uploadFile(ServerRequestInterface $request, ResponseInterface $response, array $args) { $petId = $args['petId']; $additionalMetadata = $request->getParsedBodyParam('additionalMetadata'); $file = (key_exists('file', $request->getUploadedFiles())) ? $request->getUploadedFiles()['file'] : null; $message = "How about implementing uploadFile as a POST method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -226,19 +235,20 @@ abstract class AbstractPetApi * Summary: uploads an image (required) * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function uploadFileWithRequiredFile($request, $response, $args) + public function uploadFileWithRequiredFile(ServerRequestInterface $request, ResponseInterface $response, array $args) { $petId = $args['petId']; $additionalMetadata = $request->getParsedBodyParam('additionalMetadata'); $requiredFile = (key_exists('requiredFile', $request->getUploadedFiles())) ? $request->getUploadedFiles()['requiredFile'] : null; $message = "How about implementing uploadFileWithRequiredFile as a POST method in OpenAPIServer\Api\PetApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractStoreApi.php b/samples/server/petstore/php-slim/lib/Api/AbstractStoreApi.php index 60f217b3ee..41c0b2a1f0 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractStoreApi.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractStoreApi.php @@ -2,12 +2,11 @@ /** * AbstractStoreApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractStoreApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractStoreApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -59,17 +60,18 @@ abstract class AbstractStoreApi * Summary: Delete purchase order by ID * Notes: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function deleteOrder($request, $response, $args) + public function deleteOrder(ServerRequestInterface $request, ResponseInterface $response, array $args) { $orderId = $args['order_id']; $message = "How about implementing deleteOrder as a DELETE method in OpenAPIServer\Api\StoreApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -80,16 +82,17 @@ abstract class AbstractStoreApi * Notes: Returns a map of status codes to quantities * Output-Formats: [application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function getInventory($request, $response, $args) + public function getInventory(ServerRequestInterface $request, ResponseInterface $response, array $args) { $message = "How about implementing getInventory as a GET method in OpenAPIServer\Api\StoreApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -100,17 +103,18 @@ abstract class AbstractStoreApi * Notes: For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function getOrderById($request, $response, $args) + public function getOrderById(ServerRequestInterface $request, ResponseInterface $response, array $args) { $orderId = $args['order_id']; $message = "How about implementing getOrderById as a GET method in OpenAPIServer\Api\StoreApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -120,17 +124,18 @@ abstract class AbstractStoreApi * Summary: Place an order for a pet * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function placeOrder($request, $response, $args) + public function placeOrder(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing placeOrder as a POST method in OpenAPIServer\Api\StoreApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Api/AbstractUserApi.php b/samples/server/petstore/php-slim/lib/Api/AbstractUserApi.php index 0b69096365..8574447317 100644 --- a/samples/server/petstore/php-slim/lib/Api/AbstractUserApi.php +++ b/samples/server/petstore/php-slim/lib/Api/AbstractUserApi.php @@ -2,12 +2,11 @@ /** * AbstractUserApi * - * PHP version 5 + * PHP version 7 * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ /** @@ -25,30 +24,32 @@ */ namespace OpenAPIServer\Api; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Exception; + /** * AbstractUserApi Class Doc Comment * - * PHP version 5 - * - * @category Class - * @package OpenAPIServer\Api - * @author OpenAPI Generator team - * @link https://github.com/openapitools/openapi-generator + * @package OpenAPIServer\Api + * @author OpenAPI Generator team + * @link https://github.com/openapitools/openapi-generator */ abstract class AbstractUserApi { /** - * @var \Interop\Container\ContainerInterface Slim app container instance + * @var ContainerInterface Slim app container instance */ protected $container; /** * Route Controller constructor receives container * - * @param \Interop\Container\ContainerInterface $container Slim app container instance + * @param ContainerInterface $container Slim app container instance */ - public function __construct($container) + public function __construct(ContainerInterface $container) { $this->container = $container; } @@ -59,17 +60,18 @@ abstract class AbstractUserApi * Summary: Create user * Notes: This can only be done by the logged in user. * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function createUser($request, $response, $args) + public function createUser(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing createUser as a POST method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -78,17 +80,18 @@ abstract class AbstractUserApi * POST createUsersWithArrayInput * Summary: Creates list of users with given input array * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function createUsersWithArrayInput($request, $response, $args) + public function createUsersWithArrayInput(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing createUsersWithArrayInput as a POST method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -97,17 +100,18 @@ abstract class AbstractUserApi * POST createUsersWithListInput * Summary: Creates list of users with given input array * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function createUsersWithListInput($request, $response, $args) + public function createUsersWithListInput(ServerRequestInterface $request, ResponseInterface $response, array $args) { $body = $request->getParsedBody(); $message = "How about implementing createUsersWithListInput as a POST method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -117,17 +121,18 @@ abstract class AbstractUserApi * Summary: Delete user * Notes: This can only be done by the logged in user. * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function deleteUser($request, $response, $args) + public function deleteUser(ServerRequestInterface $request, ResponseInterface $response, array $args) { $username = $args['username']; $message = "How about implementing deleteUser as a DELETE method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -137,17 +142,18 @@ abstract class AbstractUserApi * Summary: Get user by user name * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function getUserByName($request, $response, $args) + public function getUserByName(ServerRequestInterface $request, ResponseInterface $response, array $args) { $username = $args['username']; $message = "How about implementing getUserByName as a GET method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -157,19 +163,20 @@ abstract class AbstractUserApi * Summary: Logs user into the system * Output-Formats: [application/xml, application/json] * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function loginUser($request, $response, $args) + public function loginUser(ServerRequestInterface $request, ResponseInterface $response, array $args) { $queryParams = $request->getQueryParams(); $username = $request->getQueryParam('username'); $password = $request->getQueryParam('password'); $message = "How about implementing loginUser as a GET method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -178,16 +185,17 @@ abstract class AbstractUserApi * GET logoutUser * Summary: Logs out current logged in user session * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function logoutUser($request, $response, $args) + public function logoutUser(ServerRequestInterface $request, ResponseInterface $response, array $args) { $message = "How about implementing logoutUser as a GET method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } @@ -197,18 +205,19 @@ abstract class AbstractUserApi * Summary: Updated user * Notes: This can only be done by the logged in user. * - * @param \Psr\Http\Message\ServerRequestInterface $request Request - * @param \Psr\Http\Message\ResponseInterface $response Response - * @param array|null $args Path arguments + * @param ServerRequestInterface $request Request + * @param ResponseInterface $response Response + * @param array|null $args Path arguments * - * @return \Psr\Http\Message\ResponseInterface + * @return ResponseInterface + * @throws Exception to force implementation class to override this method */ - public function updateUser($request, $response, $args) + public function updateUser(ServerRequestInterface $request, ResponseInterface $response, array $args) { $username = $args['username']; $body = $request->getParsedBody(); $message = "How about implementing updateUser as a PUT method in OpenAPIServer\Api\UserApi class?"; - throw new \Exception($message); + throw new Exception($message); return $response->write($message)->withStatus(501); } diff --git a/samples/server/petstore/php-slim/lib/Auth/AbstractAuthenticator.php b/samples/server/petstore/php-slim/lib/Auth/AbstractAuthenticator.php new file mode 100644 index 0000000000..115b4b72f4 --- /dev/null +++ b/samples/server/petstore/php-slim/lib/Auth/AbstractAuthenticator.php @@ -0,0 +1,108 @@ +container = $container; + $this->requiredScope = $requiredScope; + } + + /** + * Makes the api key validation of your application + * + * Just an example of implementation. Override this method to fit your needs + * + * @param ServerRequestInterface $request HTTP request + * @param TokenSearch $tokenSearch Middleware instance which contains api key in token + * + * @return bool Must return either true or false + * @throws UnauthorizedExceptionInterface when cannot parse token + */ + public function __invoke(ServerRequestInterface &$request, TokenSearch $tokenSearch) + { + /** + * Try find authorization token via header, parameters, cookie or attribute + * If token not found, return response with status 401 (unauthorized) + */ + $token = $tokenSearch->getToken($request); + + /** + * Verify if token is valid on database + * If token isn't valid, expired or has insufficient scope must throw an UnauthorizedExceptionInterface + */ + $user = $this->getUserByToken($token); + + /** + * Set authenticated user at attributes + */ + $request = $request->withAttribute('authenticated_user', $user); + + return true; + } +} diff --git a/samples/server/petstore/php-slim/lib/Model/AdditionalPropertiesClass.php b/samples/server/petstore/php-slim/lib/Model/AdditionalPropertiesClass.php index ee96953acb..511b77635d 100644 --- a/samples/server/petstore/php-slim/lib/Model/AdditionalPropertiesClass.php +++ b/samples/server/petstore/php-slim/lib/Model/AdditionalPropertiesClass.php @@ -1,11 +1,26 @@ 'FakeApi', 'operationId' => 'testEndpointParameters', 'authMethods' => [ + // http security schema named 'http_basic_test' [ 'type' => 'http', 'isBasic' => true, + 'isApiKey' => false, + 'isOAuth' => false, ], ], ], @@ -206,6 +207,17 @@ class SlimRouter 'userClassname' => 'FakeClassnameTags123Api', 'operationId' => 'testClassname', 'authMethods' => [ + // apiKey security schema named 'api_key_query' + [ + 'type' => 'apiKey', + 'isBasic' => false, + 'isApiKey' => true, + 'isOAuth' => false, + 'keyParamName' => 'api_key_query', + 'isKeyInHeader' => false, + 'isKeyInQuery' => true, + 'isKeyInCookie' => false, + ], ], ], [ @@ -217,6 +229,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'addPet', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -228,6 +251,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'findPetsByStatus', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -239,6 +273,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'findPetsByTags', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -250,6 +295,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'updatePet', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -261,6 +317,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'deletePet', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -272,6 +339,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'getPetById', 'authMethods' => [ + // apiKey security schema named 'api_key' + [ + 'type' => 'apiKey', + 'isBasic' => false, + 'isApiKey' => true, + 'isOAuth' => false, + 'keyParamName' => 'api_key', + 'isKeyInHeader' => true, + 'isKeyInQuery' => false, + 'isKeyInCookie' => false, + ], ], ], [ @@ -283,6 +361,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'updatePetWithForm', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -294,6 +383,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'uploadFile', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -305,6 +405,17 @@ class SlimRouter 'userClassname' => 'PetApi', 'operationId' => 'uploadFileWithRequiredFile', 'authMethods' => [ + // oauth2 security schema named 'petstore_auth' + [ + 'type' => 'oauth2', + 'isBasic' => false, + 'isApiKey' => false, + 'isOAuth' => true, + 'scopes' => [ + 'write:pets', // modify pets in your account + 'read:pets', // read your pets + ], + ], ], ], [ @@ -316,6 +427,17 @@ class SlimRouter 'userClassname' => 'StoreApi', 'operationId' => 'getInventory', 'authMethods' => [ + // apiKey security schema named 'api_key' + [ + 'type' => 'apiKey', + 'isBasic' => false, + 'isApiKey' => true, + 'isOAuth' => false, + 'keyParamName' => 'api_key', + 'isKeyInHeader' => true, + 'isKeyInQuery' => false, + 'isKeyInCookie' => false, + ], ], ], [ @@ -445,25 +567,32 @@ class SlimRouter * Class constructor * * @param ContainerInterface|array $container Either a ContainerInterface or an associative array of app settings - * @throws InvalidArgumentException when no container is provided that implements ContainerInterface + * + * @throws InvalidArgumentException When no container is provided that implements ContainerInterface + * @throws Exception When implementation class doesn't exists */ public function __construct($container = []) { $this->slimApp = new App($container); - $basicAuth = new HttpBasicAuthentication([ - "secure" => false, - "authenticator" => function ($arguments) { - $user = $arguments["user"]; - $password = $arguments["password"]; - return false; - } - ]); + $authPackage = 'OpenAPIServer\Auth'; + $basicAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\BasicAuthenticator?"; + throw new Exception($message); + }; + $apiKeyAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\ApiKeyAuthenticator?"; + throw new Exception($message); + }; + $oAuthAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) { + $message = "How about extending AbstractAuthenticator class by {$authPackage}\OAuthAuthenticator?"; + throw new Exception($message); + }; foreach ($this->operations as $operation) { $callback = function ($request, $response, $arguments) use ($operation) { $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?"; - throw new \Exception($message); + throw new Exception($message); return $response->withStatus(501)->write($message); }; $middlewares = []; @@ -472,10 +601,55 @@ class SlimRouter $callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}"; } - foreach ($operation['authMethods'] as $authMethod) { - if ($authMethod['type'] === 'http') { - $middlewares[] = $basicAuth; + switch ($authMethod['type']) { + case 'http': + $authenticatorClassname = "\\{$authPackage}\\BasicAuthenticator"; + if (class_exists($authenticatorClassname)) { + $basicAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $basicAuthenticator, + 'regex' => '/Basic\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + case 'apiKey': + $authenticatorClassname = "\\{$authPackage}\\ApiKeyAuthenticator"; + if (class_exists($authenticatorClassname)) { + $apiKeyAuthenticator = new $authenticatorClassname($container); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $apiKeyAuthenticator, + 'regex' => '/^(.*)$/i', + 'header' => $authMethod['isKeyInHeader'] ? $authMethod['keyParamName'] : null, + 'parameter' => $authMethod['isKeyInQuery'] ? $authMethod['keyParamName'] : null, + 'cookie' => $authMethod['isKeyInCookie'] ? $authMethod['keyParamName'] : null, + 'argument' => null, + ])); + break; + case 'oauth2': + $authenticatorClassname = "\\{$authPackage}\\OAuthAuthenticator"; + if (class_exists($authenticatorClassname)) { + $oAuthAuthenticator = new $authenticatorClassname($container, $authMethod['scopes']); + } + + $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([ + 'authenticator' => $oAuthAuthenticator, + 'regex' => '/Bearer\s+(.*)$/i', + 'header' => 'Authorization', + 'parameter' => null, + 'cookie' => null, + 'argument' => null, + ])); + break; + default: + throw new Exception('Unknown authorization schema type'); } } @@ -488,6 +662,22 @@ class SlimRouter } } + /** + * Merges user defined options with dynamic params + * + * @param array $options Params which need to merge into user options + * + * @return array Merged array + */ + private function getTokenAuthenticationOptions(array $options) + { + if (is_array($this->slimApp->getContainer()['tokenAuthenticationOptions']) === false) { + return $options; + } + + return array_merge($this->slimApp->getContainer()['tokenAuthenticationOptions'], $options); + } + /** * Add route with multiple methods * @@ -496,11 +686,11 @@ class SlimRouter * @param callable|string $callable The route callback routine * @param array|null $middlewares List of middlewares * - * @return Slim\Interfaces\RouteInterface + * @return RouteInterface * - * @throws InvalidArgumentException if the route pattern isn't a string + * @throws InvalidArgumentException If the route pattern isn't a string */ - public function addRoute($methods, $pattern, $callable, $middlewares = []) + public function addRoute(array $methods, string $pattern, $callable, $middlewares = []) { $route = $this->slimApp->map($methods, $pattern, $callable); foreach ($middlewares as $middleware) { @@ -511,6 +701,7 @@ class SlimRouter /** * Returns Slim Framework instance + * * @return App */ public function getSlimApp()