Passed
Push — master ( cd4631...f63432 )
by Peter
02:15
created

Api::getUserByClientId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 10
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Admin\Http\Middleware;
6
7
use AbterPhp\Admin\Domain\Entities\User;
8
use AbterPhp\Admin\Orm\UserRepo;
9
use AbterPhp\Admin\Service\Login as LoginService;
10
use AbterPhp\Framework\Config\Provider as ConfigProvider;
11
use AbterPhp\Framework\Psr7\RequestConverter;
12
use AbterPhp\Framework\Psr7\ResponseConverter;
13
use AbterPhp\Framework\Psr7\ResponseFactory;
14
use Closure;
15
use Exception;
16
use League\OAuth2\Server\Exception\OAuthServerException;
17
use League\OAuth2\Server\ResourceServer;
18
use Nyholm\Psr7\ServerRequest;
19
use Opulence\Http\Requests\Request;
20
use Opulence\Http\Responses\Response;
21
use Opulence\Orm\OrmException;
22
use Opulence\Routing\Middleware\IMiddleware;
23
use Psr\Log\LoggerInterface;
24
25
class Api implements IMiddleware
26
{
27
    /** @var ResourceServer */
28
    protected $server;
29
30
    /** @var RequestConverter */
31
    protected $requestConverter;
32
33
    /** @var ResponseFactory */
34
    protected $responseFactory;
35
36
    /** @var ResponseConverter */
37
    protected $responseConverter;
38
39
    /** @var UserRepo */
40
    protected $userRepo;
41
42
    /** @var LoggerInterface */
43
    protected $logger;
44
45
    /** @var string */
46
    protected $problemBaseUrl;
47
48
    /**
49
     * @param LoginService $loginService The session used by the application
50
     */
51
    public function __construct(
52
        ResourceServer $server,
53
        RequestConverter $requestConverter,
54
        ResponseFactory $responseFactory,
55
        ResponseConverter $responseConverter,
56
        UserRepo $userRepo,
57
        LoggerInterface $logger,
58
        ConfigProvider $configProvider
59
    ) {
60
        $this->server = $server;
61
62
        $this->requestConverter  = $requestConverter;
63
        $this->responseFactory   = $responseFactory;
64
        $this->responseConverter = $responseConverter;
65
        $this->userRepo          = $userRepo;
66
        $this->logger            = $logger;
67
        $this->problemBaseUrl    = $configProvider->getProblemBaseUrl();
68
    }
69
70
    // TODO: Check error response formats
71
    // $next consists of the next middleware in the pipeline
72
    public function handle(Request $request, Closure $next): Response
73
    {
74
        $psr7Request = $this->requestConverter->toPsr($request);
75
76
        try {
77
            $psr7Request = $this->server->validateAuthenticatedRequest($psr7Request);
78
        } catch (OAuthServerException $e) {
79
            return $this->createResponse($e);
80
        } catch (Exception $e) {
81
            return $this->createResponse(new OAuthServerException($e->getMessage(), 0, 'unknown_error', 500));
82
        }
83
84
        try {
85
            $user = $this->getUserByClientId($psr7Request);
86
        } catch (OrmException $e) {
87
            return $this->createResponse(new OAuthServerException($e->getMessage(), 0, 'unknown_error', 500));
88
        }
89
90
        // This is a workaround as Opulence request doesn't have a straight-forward way of storing internal data
91
        $headers = $request->getHeaders();
92
93
        $headers['xxx-user-id']       = $user->getId();
94
        $headers['xxx-user-username'] = $user->getUsername();
95
96
        return $next($request);
97
    }
98
99
    /**
100
     * @param OAuthServerException $e
101
     *
102
     * @return Response
103
     */
104
    protected function createResponse(OAuthServerException $e): Response
105
    {
106
        $status  = $e->getHttpStatusCode();
107
        $content = [
108
            'type'   => sprintf('%srequest-authentication-failure', $this->problemBaseUrl),
109
            'title'  => 'Access Denied',
110
            'status' => $status,
111
            'detail' => $e->getMessage(),
112
        ];
113
114
        $response = new Response();
115
        $response->setStatusCode($status);
116
        $response->setContent(json_encode($content));
117
118
        return $response;
119
    }
120
121
    /**
122
     * @param ServerRequest $psr7Request
123
     *
124
     * @return User
125
     */
126
    protected function getUserByClientId(ServerRequest $psr7Request): User
127
    {
128
        $userId = $psr7Request->getAttribute('oauth_user_id');
129
        if ($userId) {
130
            return $this->userRepo->getById($userId);
131
        }
132
133
        $clientId = $psr7Request->getAttribute('oauth_client_id');
134
135
        return $this->userRepo->getByClientId($clientId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->userRepo->getByClientId($clientId) could return the type null which is incompatible with the type-hinted return AbterPhp\Admin\Domain\Entities\User. Consider adding an additional type-check to rule them out.
Loading history...
Bug introduced by
It seems like $clientId can also be of type null; however, parameter $clientId of AbterPhp\Admin\Orm\UserRepo::getByClientId() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

135
        return $this->userRepo->getByClientId(/** @scrutinizer ignore-type */ $clientId);
Loading history...
136
    }
137
}
138