Completed
Pull Request — master (#22)
by Samuel
05:09 queued 02:14
created

MultiAuthenticate::handle()   C

Complexity

Conditions 7
Paths 23

Size

Total Lines 37
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 37
ccs 17
cts 17
cp 1
rs 6.7272
cc 7
eloc 18
nc 23
nop 3
crap 7
1
<?php
2
3
namespace SMartins\PassportMultiauth\Http\Middleware;
4
5
use Closure;
6
use Illuminate\Http\Request;
7
use League\OAuth2\Server\ResourceServer;
8
use Illuminate\Auth\AuthenticationException;
9
use Illuminate\Auth\Middleware\Authenticate;
10
use Illuminate\Contracts\Auth\Factory as Auth;
11
use Illuminate\Contracts\Auth\Authenticatable;
12
use SMartins\PassportMultiauth\Provider as Token;
13
use SMartins\PassportMultiauth\PassportMultiauth;
14
use SMartins\PassportMultiauth\ProviderRepository;
15
use SMartins\PassportMultiauth\Guards\GuardChecker;
16
use League\OAuth2\Server\Exception\OAuthServerException;
17
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
18
19
class MultiAuthenticate extends Authenticate
20
{
21
    /**
22
     * @var \League\OAuth2\Server\ResourceServer
23
     */
24
    protected $server;
25
26
    /**
27
     * @var \SMartins\PassportMultiauth\ProviderRepository
28
     */
29
    protected $providers;
30
31
    /**
32
     * The authentication factory instance.
33
     *
34
     * @var \Illuminate\Contracts\Auth\Factory
35
     */
36
    protected $auth;
37
38 12
    public function __construct(ResourceServer $server, ProviderRepository $providers, Auth $auth)
39
    {
40 12
        $this->server = $server;
41 12
        $this->providers = $providers;
42 12
        $this->auth = $auth;
43 12
    }
44
45
    /**
46
     * Handle an incoming request. Authenticates the guard from access token
47
     * used on request.
48
     *
49
     * @param \Illuminate\Http\Request $request
50
     * @param \Closure                 $next
51
     * @param string[]                 ...$guards
52
     *
53
     * @return mixed
54
     */
55 12
    public function handle($request, Closure $next, ...$guards)
56
    {
57
        // If don't has any guard follow the flow
58 12
        if (empty($guards)) {
59 1
            return $next($request);
60
        }
61
62 11
        $psrRequest = (new DiactorosFactory())->createRequest($request);
63
64
        try {
65 11
            $psrRequest = $this->server->validateAuthenticatedRequest($psrRequest);
66
67 4
            if (! $tokenId = $psrRequest->getAttribute('oauth_access_token_id')) {
68 1
                throw new AuthenticationException('Unauthenticated', $guards);
69
            }
70
71 3
            if (! $accessToken = $this->providers->findForToken($tokenId)) {
72 1
                throw new AuthenticationException('Unauthenticated', $guards);
73
            }
74
75 2
            $this->authenticateTokenGuard($accessToken, $guards);
76
77 1
            return $next($request);
78 10
        } catch (OAuthServerException $e) {
79
            // @todo It's the best place to this code???
80 7
            if ($user = PassportMultiauth::userActing()) {
81 6
                if (! $this->canBeAuthenticated($user, $request)) {
82 2
                    throw new AuthenticationException('Unauthenticated', $guards);
83
                }
84
85 4
                return $next($request);
86
            }
87
88
            // @todo Check if it's the best way to handle with OAuthServerException
89 1
            throw new AuthenticationException('Unauthenticated', $guards);
90
        }
91
    }
92
93
    /**
94
     * Check if user acting has the required guards and scopes on request.
95
     *
96
     * @param  \Illuminate\Foundation\Auth\User $user
97
     * @param  \Illuminate\Http\Request $request
98
     * @return bool
99
     */
100 6
    public function canBeAuthenticated(Authenticatable $user, Request $request)
101
    {
102 6
        $guards = GuardChecker::getAuthGuards($request);
103
104 6
        $userGuard = PassportMultiauth::getUserGuard($user);
105
106 6
        return in_array($userGuard, $guards);
107
    }
108
109
    /**
110
     * Authenticate correct guard based on token.
111
     *
112
     * @param \SMartins\PassportMultiauth\Provider $token
113
     * @param  array $guards
114
     * @return void
115
     */
116 2
    public function authenticateTokenGuard(Token $token, $guards)
117
    {
118 2
        $providers = GuardChecker::getGuardsProviders($guards);
119
120
        // use only guard associated to access token provider
121 2
        $authGuards = $providers->has($token->provider) ? [$providers->get($token->provider)] : [];
122
123 2
        $this->authenticate($authGuards);
124 1
    }
125
}
126