Issues (50)

src/Audit/UserProvider.php (3 issues)

1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published
7
 * by the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Audit;
20
21
use DH\Auditor\Provider\Doctrine\Configuration;
22
use DH\Auditor\User\User;
23
use DH\Auditor\User\UserInterface as AuditorUserInterface;
24
use DH\Auditor\User\UserProviderInterface;
25
use Doctrine\Common\EventSubscriber;
26
use Doctrine\ORM\Event\PostFlushEventArgs;
27
use Doctrine\ORM\Events;
28
use Exception;
29
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
30
use Symfony\Component\Security\Core\Security;
31
use Symfony\Component\Security\Core\User\UserInterface;
32
33
class UserProvider implements UserProviderInterface, EventSubscriber
34
{
35
    public const CLI_USER_IDENTIFER = '$cli';
36
    public const INTERNAL_USER_IDENTIFIER = '$internal';
37
38
    /**
39
     * @var string|null
40
     */
41
    private $username;
42
43
    /**
44
     * @var string|null
45
     */
46
    private $identifier;
47
48
    /**
49
     * @var Security
50
     */
51
    private $security;
52
53
    /**
54
     * @var Configuration
55
     */
56
    private $configuration;
57
58
    public function __construct(Security $security, Configuration $configuration)
59
    {
60
        $this->security = $security;
61
        $this->configuration = $configuration;
62
    }
63
64
    public function setManualUsername(?string $username, ?string $identifier): void
65
    {
66
        $this->username = $username;
67
        $this->identifier = $identifier;
68
    }
69
70
    public function postFlush(PostFlushEventArgs $args): void
0 ignored issues
show
The parameter $args is not used and could be removed. ( Ignorable by Annotation )

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

70
    public function postFlush(/** @scrutinizer ignore-unused */ PostFlushEventArgs $args): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
71
    {
72
        //Reset manual set username and identifier after flush
73
        $this->username = null;
74
        $this->identifier = null;
75
    }
76
77
    public function __invoke(): ?AuditorUserInterface
78
    {
79
        $tokenUser = $this->getTokenUser();
80
        $impersonatorUser = $this->getImpersonatorUser();
81
82
        $identifier = null;
83
        $username = null;
84
85
        if (null !== $tokenUser && $tokenUser instanceof UserInterface) {
86
            //Use full name of the user if possible
87
            if ($tokenUser instanceof \App\Entity\User) {
88
                $identifier = $tokenUser->getUsername();
89
                $username = (string) $tokenUser;
90
            } else {
91
                if (method_exists($tokenUser, 'getId')) {
92
                    $identifier = $tokenUser->getId();
93
                }
94
95
                $username = $tokenUser->getUsername();
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\Securi...nterface::getUsername() has been deprecated: since Symfony 5.3, use getUserIdentifier() instead ( Ignorable by Annotation )

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

95
                $username = /** @scrutinizer ignore-deprecated */ $tokenUser->getUsername();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
96
            }
97
        }
98
99
        if (null !== $impersonatorUser && $impersonatorUser instanceof UserInterface) {
100
            $username .= sprintf('[impersonator %s]', $impersonatorUser->getUsername());
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\Securi...nterface::getUsername() has been deprecated: since Symfony 5.3, use getUserIdentifier() instead ( Ignorable by Annotation )

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

100
            $username .= sprintf('[impersonator %s]', /** @scrutinizer ignore-deprecated */ $impersonatorUser->getUsername());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
101
        }
102
103
        //Check if a username and identifier were manually provided
104
        if (!empty($this->username) && !empty($this->identifier)) {
105
            $username = $this->username;
106
            $identifier = $this->identifier;
107
        } elseif ($this->is_cli()) { //Check if we are on command line, then use the username of the user
108
            $identifier = self::CLI_USER_IDENTIFER;
109
            $username = 'CLI';
110
            if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
111
                $username = sprintf('CLI [%s]', posix_getpwuid(posix_geteuid())['name']);
112
            }
113
        }
114
115
        if (null === $identifier && null === $username) {
116
            return null;
117
        }
118
119
        return new User($identifier, $username);
120
    }
121
122
    private function is_cli(): bool
123
    {
124
        if (defined('STDIN')) {
125
            return true;
126
        }
127
128
        if ('cli' === php_sapi_name()) {
129
            return true;
130
        }
131
132
        if (array_key_exists('SHELL', $_ENV)) {
133
            return true;
134
        }
135
136
        if (empty($_SERVER['REMOTE_ADDR']) and !isset($_SERVER['HTTP_USER_AGENT']) and count($_SERVER['argv']) > 0) {
137
            return true;
138
        }
139
140
        if (!array_key_exists('REQUEST_METHOD', $_SERVER)) {
141
            return true;
142
        }
143
144
        return false;
145
    }
146
147
    /**
148
     * @return UserInterface|null
149
     */
150
    private function getTokenUser()
151
    {
152
        try {
153
            $token = $this->security->getToken();
154
        } catch (Exception $e) {
155
            $token = null;
156
        }
157
158
        if (null === $token) {
159
            return null;
160
        }
161
162
        $tokenUser = $token->getUser();
163
        if ($tokenUser instanceof UserInterface) {
164
            return $tokenUser;
165
        }
166
167
        return null;
168
    }
169
170
    /**
171
     * @return string|UserInterface|null
172
     */
173
    private function getImpersonatorUser()
174
    {
175
        $token = $this->security->getToken();
176
177
        // Symfony >= 5
178
        if (class_exists(SwitchUserToken::class) && $token instanceof SwitchUserToken) {
179
            return $token->getOriginalToken()
180
                ->getUser();
181
        }
182
183
        return null;
184
    }
185
186
    public function getSubscribedEvents()
187
    {
188
        return [
189
            Events::postFlush,
190
        ];
191
    }
192
}
193