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 ResponseInterface $response     PSR7 response
53     * @param callable $next                  Next middleware
54     *
55     * @return ResponseInterface
56     */
57    public function __invoke(
58        ServerRequestInterface $request,
59        RequestHandlerInterface $next
60    ) {
61        $response = (new ResponseFactory())->createResponse(200, '');
62        $request = $request->withAttribute('authentificationHandler', $this->authentificationHandler);
63        $queryParams = $request->getQueryParams();
64        $oidcProviderName = isset($queryParams['provider'])
65            ? $queryParams['provider'] : Auth::getOidcProvider();
66
67        if ($oidcProviderName && isset(static::$authInstances[$oidcProviderName])) {
68            $oidcInstance = static::$authInstances[$oidcProviderName];
69            $instance = new $oidcInstance();
70            $response = $this->{$this->handlerCall}($request, $response, $instance, $next);
71        } else {
72            \App::$log->error('Unknown OIDC provider requested', [
73                'event' => 'oauth_unknown_provider',
74                'provider' => $oidcProviderName ?: 'none',
75                'available_providers' => array_keys(static::$authInstances),
76                'handler' => $this->authentificationHandler,
77                'timestamp' => date('c'),
78                'request_uri' => $request->getUri()->getPath(),
79                'session_id' => session_id()
80            ]);
81            $stream = (new StreamFactory())->createStream();
82            $stream->write(json_encode(['error' => 'Unknown OIDC provider']));
83            return $response->withStatus(400)->withHeader('Content-Type', 'application/json')
84                ->withBody($stream);
85        }
86        return $response;
87    }
88
89    private function handleLogin(ServerRequestInterface $request, ResponseInterface $response, $instance, $next)
90    {
91        if (! $request->getParam("code") && '' == Auth::getKey()) {
92            return $response->withRedirect($this->getAuthUrl($request, $instance), 301);
93        } elseif ($request->getParam("state") !== Auth::getKey()) {
94            Auth::removeKey();
95            Auth::removeOidcProvider();
96            return $response->withRedirect($this->getAuthUrl($request, $instance), 301);
97        }
98        if ('login' == $request->getAttribute('authentificationHandler')) {
99            $instance->doLogin($request, $response);
100            $response = $next->handle($request);
101            return $response;
102        }
103        return $response;
104    }
105
106    private function handleLogout(ServerRequestInterface $request, ResponseInterface $response, $instance)
107    {
108        if (
109            'logout' == $request->getAttribute('authentificationHandler') &&
110            ! $request->getParam('state')
111        ) {
112            return $instance->doLogout($response);
113        }
114        return $response;
115    }
116
117    private function handleRefreshToken(ServerRequestInterface $request, ResponseInterface $response, $instance)
118    {
119        if (
120            'refresh' == $request->getAttribute('authentificationHandler') &&
121            ! $instance->writeNewAccessTokenIfExpired()
122        ) {
123            return $instance->doLogout($response);
124        }
125        return $response;
126    }
127
128    private function getAuthUrl(ServerRequestInterface $request, $instance)
129    {
130        $authUrl = $instance->getProvider()->getAuthorizationUrl();
131        Auth::setOidcProvider($request->getParam('provider'));
132        Auth::setKey($instance->getProvider()->getState(), time() + \App::SESSION_DURATION);
133        return $authUrl;
134    }
135}