1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Http\Middleware;
7
8use App\Libraries\SessionVerification;
9use Closure;
10use Illuminate\Auth\AuthenticationException;
11use Laravel\Passport\ClientRepository;
12use League\OAuth2\Server\Exception\OAuthServerException;
13use League\OAuth2\Server\ResourceServer;
14use Nyholm\Psr7\Factory\Psr17Factory;
15use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
16
17class AuthApi
18{
19 const REQUEST_OAUTH_TOKEN_KEY = 'oauth_token';
20
21 protected $clients;
22 protected $server;
23
24 public function __construct(ResourceServer $server, ClientRepository $clients)
25 {
26 $this->clients = $clients;
27 $this->server = $server;
28 }
29
30 public function handle($request, Closure $next)
31 {
32 // FIXME:
33 // default session guard is used. This really works by coincidence with cookies disabled
34 // since session user resolution will fail, but it'll still keep repeatedly attempting to resolve it.
35
36 if ($request->bearerToken() !== null) {
37 $psr = $this->validateRequest($request);
38 $token = $this->validTokenFromRequest($psr);
39 $request->attributes->set(static::REQUEST_OAUTH_TOKEN_KEY, $token);
40 } else {
41 if (!RequireScopes::noTokenRequired($request)) {
42 throw new AuthenticationException();
43 }
44 }
45
46 return $next($request);
47 }
48
49 private function validateRequest($request)
50 {
51 $psr17Factory = new Psr17Factory();
52
53 $psr = (new PsrHttpFactory(
54 $psr17Factory,
55 $psr17Factory,
56 $psr17Factory,
57 $psr17Factory,
58 ))->createRequest($request);
59
60 try {
61 return $this->server->validateAuthenticatedRequest($psr);
62 } catch (OAuthServerException $e) {
63 throw new AuthenticationException();
64 }
65 }
66
67 private function validTokenFromRequest($psr)
68 {
69 $psrClientId = $psr->getAttribute('oauth_client_id');
70 $psrUserId = get_int($psr->getAttribute('oauth_user_id'));
71 $psrTokenId = $psr->getAttribute('oauth_access_token_id');
72
73 $client = $this->clients->findActive($psrClientId);
74 if ($client === null) {
75 throw new AuthenticationException('invalid client');
76 }
77
78 $token = $client->tokens()->validAt(now())->find($psrTokenId);
79 if ($token === null) {
80 throw new AuthenticationException('invalid token');
81 }
82
83 $token->setRelation('client', $client);
84 $token->validate();
85
86 $user = $token->getResourceOwner();
87
88 if ($token->isClientCredentials()) {
89 if ($psrUserId !== null) {
90 throw new AuthenticationException();
91 }
92 } else {
93 if ($user === null || $user->getKey() !== $psrUserId) {
94 throw new AuthenticationException();
95 }
96 }
97
98 if ($user !== null) {
99 \Auth::setUser($user);
100 $user->withAccessToken($token);
101
102 if ($token->isVerified()) {
103 $user->markSessionVerified();
104 } else {
105 SessionVerification\Helper::issue($token, $user, true);
106 }
107 }
108
109 return $token;
110 }
111}