Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
4.17% covered (danger)
4.17%
2 / 48
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
OAuthMiddleware
4.17% covered (danger)
4.17%
2 / 48
16.67% covered (danger)
16.67%
1 / 6
303.16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 __invoke
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 handleLogin
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 handleLogout
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 handleRefreshToken
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getAuthUrl
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace BO\Slim\Middleware;
4
5use Psr\Http\Message\ServerRequestInterface;
6use Psr\Http\Message\ResponseInterface;
7use Psr\Http\Server\RequestHandlerInterface;
8use BO\Slim\Factory\ResponseFactory;
9use BO\Zmsclient\Auth;
10use Slim\Psr7\Factory\StreamFactory;
11
12/**
13 * @SuppressWarnings(PHPMD)
14 */
15
16class OAuthMiddleware
17{
18    /**
19     * List of authentification types to init specific instance
20     *
21     * @var array
22     */
23    public static $authInstances = [
24        'keycloak' => '\BO\Slim\Middleware\OAuth\KeycloakInstance'
25    ];
26
27    /**
28     * List of request pathes with assigned handler in oidc instance
29     *
30     * @var array
31     */
32    protected $handlerList = [
33        'login' => 'handleLogin',
34        'logout' => 'handleLogout',
35        'refresh' => 'handleRefreshToken'
36    ];
37
38    protected $handlerCall = '';
39
40    protected $authentificationHandler = '';
41
42    public function __construct($handler = 'login')
43    {
44        $this->authentificationHandler = $handler;
45        $this->handlerCall = $this->handlerList[$handler];
46    }
47
48    /**
49     * Set the authorizsationType attribute to request and init authorization method
50     *
51     * @param ServerRequestInterface $request PSR7 request
52     * @param RequestHandlerInterface $next Next middleware
53     *
54     * @return ResponseInterface
55     */
56    public function __invoke(
57        ServerRequestInterface $request,
58        RequestHandlerInterface $next
59    ) {
60        $response = (new ResponseFactory())->createResponse(200, '');
61        $request = $request->withAttribute('authentificationHandler', $this->authentificationHandler);
62        $queryParams = $request->getQueryParams();
63        $oidcProviderName = isset($queryParams['provider'])
64            ? $queryParams['provider'] : Auth::getOidcProvider();
65
66        if ($oidcProviderName && isset(static::$authInstances[$oidcProviderName])) {
67            $oidcInstance = static::$authInstances[$oidcProviderName];
68            $instance = new $oidcInstance();
69            $response = $this->{$this->handlerCall}($request, $response, $instance, $next);
70        } else {
71            \App::$log->error('Unknown OIDC provider requested', [
72                'event' => 'oauth_unknown_provider',
73                'provider' => $oidcProviderName ?: 'none',
74                'available_providers' => array_keys(static::$authInstances),
75                'handler' => $this->authentificationHandler,
76                'timestamp' => date('c'),
77                'request_uri' => $request->getUri()->getPath(),
78                'session_id' => session_id()
79            ]);
80            $stream = (new StreamFactory())->createStream();
81            $stream->write(json_encode(['error' => 'Unknown OIDC provider']));
82            return $response->withStatus(400)->withHeader('Content-Type', 'application/json')
83                ->withBody($stream);
84        }
85        return $response;
86    }
87
88    private function handleLogin(ServerRequestInterface $request, ResponseInterface $response, $instance, $next)
89    {
90        if (! $request->getParam("code") && '' == Auth::getKey()) {
91            return $response->withRedirect($this->getAuthUrl($request, $instance), 301);
92        } elseif ($request->getParam("state") !== Auth::getKey()) {
93            Auth::removeKey();
94            Auth::removeOidcProvider();
95            return $response->withRedirect($this->getAuthUrl($request, $instance), 301);
96        }
97        if ('login' == $request->getAttribute('authentificationHandler')) {
98            $instance->doLogin($request, $response);
99            $response = $next->handle($request);
100            return $response;
101        }
102        return $response;
103    }
104
105    private function handleLogout(ServerRequestInterface $request, ResponseInterface $response, $instance)
106    {
107        if (
108            'logout' == $request->getAttribute('authentificationHandler') &&
109            ! $request->getParam('state')
110        ) {
111            return $instance->doLogout($response);
112        }
113        return $response;
114    }
115
116    private function handleRefreshToken(ServerRequestInterface $request, ResponseInterface $response, $instance)
117    {
118        if (
119            'refresh' == $request->getAttribute('authentificationHandler') &&
120            ! $instance->writeNewAccessTokenIfExpired()
121        ) {
122            return $instance->doLogout($response);
123        }
124        return $response;
125    }
126
127    private function getAuthUrl(ServerRequestInterface $request, $instance)
128    {
129        $authUrl = $instance->getProvider()->getAuthorizationUrl();
130        Auth::setOidcProvider($request->getParam('provider'));
131        Auth::setKey($instance->getProvider()->getState(), time() + \App::SESSION_DURATION);
132        return $authUrl;
133    }
134}