aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/JsonApi/Middlewares/Authentication.php
blob: bbcfef1f0238d5e9a2481d362fd39ca155733f32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php

namespace JsonApi\Middlewares;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;

class Authentication
{
    // der Schlüssel des Request-Attributs, in dem der Stud.IP-Nutzer
    // gefunden werden kann:

    // $user = $request->getAttribute(Authentication::USER_KEY);
    const USER_KEY = 'studip-user';

    /**
     * Der Konstruktor.
     *
     * @param \Closure $authenticator eine Closure, die den Nutzernamen und
     *                                das Passwort als Argumente erhält und
     *                                damit entweder einen Stud.IP-User-Objekt
     *                                oder null zurückgibt
     * @param array    $excluded_strategies
     */
    public function __construct(
        // a callable accepting two arguments username and password and
        // returning either null or a Stud.IP user object
        private readonly \Closure $authenticator,
        private readonly array $excluded_strategies = []
    ) {
    }

    /**
     * Hier muss die Autorisierung implementiert werden.
     *
     * @param Request        $request das Request-Objekt
     * @param RequestHandler $handler der PSR-15 Request Handler
     *
     * @return ResponseInterface das neue Response-Objekt
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function __invoke(Request $request, RequestHandler $handler)
    {
        $guards = $this->getGuards($request);

        foreach ($guards as $guard) {
            if ($guard->check()) {
                $request = $this->provideUser($request, $guard->user());

                return $handler->handle($request);
            }
        }

        return $this->generateChallenges($guards);
    }

    // according to RFC 2616
    private function generateChallenges(array $guards): Response
    {
        $response = new Response(401);

        foreach ($guards as $guard) {
            $response = $guard->addChallenge($response);
        }

        return $response;
    }

    /**
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    private function provideUser(Request $request, \User $user): Request
    {
        if (
            !isset($GLOBALS['user'])
            || 'nobody' === $GLOBALS['user']->id
        ) {
            $GLOBALS['user'] = new \Seminar_User($user);
            $GLOBALS['auth'] = new \Seminar_Auth();
            $GLOBALS['auth']->auth = [
                'uid' => $user->id,
                'uname' => $user->username,
                'perm' => $user->perms,
            ];
            $GLOBALS['perm'] = new \Seminar_Perm();
            $GLOBALS['MAIL_VALIDATE_BOX'] = false;
            if (isset($GLOBALS['sess'])) {
                $GLOBALS['sess']->delete();
            }
            setTempLanguage($user->id);
        }

        return $request->withAttribute(self::USER_KEY, $user);
    }

    /**
     * @param Request $request
     *
     * @return array
     */
    protected function getGuards(Request $request): array
    {
        $guards = [
            'session' => new Auth\SessionStrategy(),
            'basic'   => new Auth\HttpBasicAuthStrategy($request, $this->authenticator),
            'oauth2'  => new Auth\OAuth2Strategy($request, $this->authenticator),
        ];

        foreach ($this->excluded_strategies as $strategy) {
            unset($guards[$strategy]);
        }

        return $guards;
    }
}