Yuriy Belenko fa9bd1f567 [Slim] Add ApiKey and OAuth authentication middleware (#1207)
* [Slim] Add fork of token middleware

This commit will be dropped, when official repo approves submitted PRs.
Right now it's for test purposes only.

* [Slim] Adds token middleware to template

* [Slim] Move auth implementation to external classes

* [Slim] Update readme

* [Slim] Add config example

* [Slim] Remove deprecated package

Considered to use dyorg/slim-token-authentication for all authentication
schemes. User needs to decode and parse Basic token himself, but it's
pretty simple task and there are many code examples in
the web. Most of time solution is two lines of code.

* [Slim] Format phpdoc comments

I've changed PHP version to 7 and updated comments to follow  main
recommendations. Used PHPCodesniffer rules are Generic.Commenting,
Squiz.Commenting, PEAR.Commenting. Of course I applied only reasonable
sniffs from this standards.

@category tag has been deleted as deprecated accordingly to
phpDocumentor offical docs.

Ref: http://docs.phpdoc.org/references/phpdoc/tags/category.html

* [Slim] Refresh samples
2019-01-05 11:32:23 +09:00

211 lines
8.3 KiB
PHP

<?php
/**
* SlimRouter
*
* PHP version 7
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**
* OpenAPI Petstore *_/ ' \" =end -- \\r\\n \\n \\r
*
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ *_/ ' \" =end --
* OpenAPI spec version: 1.0.0 *_/ ' \" =end -- \\r\\n \\n \\r
* Contact: something@something.abc *_/ ' \" =end -- \\r\\n \\n \\r
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace OpenAPIServer;
use Slim\App;
use Slim\Interfaces\RouteInterface;
use Psr\Container\ContainerInterface;
use InvalidArgumentException;
use Dyorg\TokenAuthentication;
use Dyorg\TokenAuthentication\TokenSearch;
use Psr\Http\Message\ServerRequestInterface;
use Exception;
/**
* SlimRouter Class Doc Comment
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
class SlimRouter
{
/** @var App instance */
private $slimApp;
/** @var array[] list of all api operations */
private $operations = [
[
'httpMethod' => 'PUT',
'basePathWithoutHost' => '/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr/v2%20*_/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr',
'path' => '/fake',
'apiPackage' => 'OpenAPIServer\Api',
'classname' => 'AbstractFakeApi',
'userClassname' => 'FakeApi',
'operationId' => 'testCodeInjectEndRnNR',
'authMethods' => [
],
],
];
/**
* 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 Exception When implementation class doesn't exists
*/
public function __construct($container = [])
{
$this->slimApp = new App($container);
$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);
return $response->withStatus(501)->write($message);
};
$middlewares = [];
if (class_exists("\\{$operation['apiPackage']}\\{$operation['userClassname']}")) {
$callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}";
}
foreach ($operation['authMethods'] as $authMethod) {
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');
}
}
$this->addRoute(
[$operation['httpMethod']],
"{$operation['basePathWithoutHost']}{$operation['path']}",
$callback,
$middlewares
)->setName($operation['operationId']);
}
}
/**
* 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
*
* @param string[] $methods Numeric array of HTTP method names
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param array|null $middlewares List of middlewares
*
* @return RouteInterface
*
* @throws InvalidArgumentException If the route pattern isn't a string
*/
public function addRoute(array $methods, string $pattern, $callable, $middlewares = [])
{
$route = $this->slimApp->map($methods, $pattern, $callable);
foreach ($middlewares as $middleware) {
$route->add($middleware);
}
return $route;
}
/**
* Returns Slim Framework instance
*
* @return App
*/
public function getSlimApp()
{
return $this->slimApp;
}
}