Completed
Push — feature/EVO-6305_worker_auth_r... ( 7840fb )
by
unknown
13:24
created

SecurityAuthenticator::objectRolesToArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * auth interface for authing against an airlock key of some sorts
4
 */
5
6
namespace Graviton\SecurityBundle\Authentication;
7
8
use Graviton\SecurityBundle\Authentication\Strategies\StrategyInterface;
9
use Graviton\SecurityBundle\Authentication\Provider\AuthenticationProvider;
10
use Graviton\SecurityBundle\Entities\AnonymousUser;
11
use Graviton\SecurityBundle\Entities\SecurityUser;
12
use Graviton\SecurityBundle\Entities\SubnetUser;
13
use Psr\Log\LoggerInterface as Logger;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\Response;
16
use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
17
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
18
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
19
use Symfony\Component\Security\Core\Exception\AuthenticationException;
20
use Symfony\Component\Security\Core\Role\RoleInterface;
21
use Symfony\Component\Security\Core\User\UserProviderInterface;
22
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
23
24
/**
25
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
26
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
27
 * @link     http://swisscom.ch
28
 */
29
final class SecurityAuthenticator implements
30
    SimplePreAuthenticatorInterface,
0 ignored issues
show
Deprecated Code introduced by
The interface Symfony\Component\Securi...eAuthenticatorInterface has been deprecated with message: Since version 2.8, to be removed in 3.0. Use the same interface from Security\Http\Authentication instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
31
    AuthenticationFailureHandlerInterface
32
{
33
34
    /**
35
     * Authentication can be required to use any service
36
     * @var bool,
37
     */
38
    protected $securityRequired;
39
40
    /**
41
     * Authentication can use a test user if no user found
42
     * @var bool,
43
     */
44
    protected $testUsername;
45
46
    /**
47
     * Authentication can allow not identified users to get information
48
     * @var bool,
49
     */
50
    protected $allowAnonymous;
51
52
    /**
53
     * @var AuthenticationProvider
54
     */
55
    protected $userProvider;
56
57
    /**
58
     * @var StrategyInterface
59
     */
60
    protected $extractionStrategy;
61
62
    /**
63
     * @var Logger
64
     */
65
    protected $logger;
66
67
68
    /**
69
     * @param boolean                $securityRequired     user provider to use
70
     * @param string                 $securityTestUsername user for testing
71
     * @param boolean                $allowAnonymous       user provider to use
72
     * @param AuthenticationProvider $userProvider         user provider to use
73
     * @param StrategyInterface      $extractionStrategy   auth strategy to use
74
     * @param Logger                 $logger               logger to user for logging errors
75
     */
76 20
    public function __construct(
77
        $securityRequired,
78
        $securityTestUsername,
79
        $allowAnonymous,
80
        AuthenticationProvider $userProvider,
81
        StrategyInterface $extractionStrategy,
82
        Logger $logger
83
    ) {
84
85 20
        $this->securityRequired   = $securityRequired;
86 20
        $this->testUsername       = $securityTestUsername;
87 20
        $this->allowAnonymous     = $allowAnonymous;
88 20
        $this->userProvider       = $userProvider;
89 20
        $this->extractionStrategy = $extractionStrategy;
90
91 20
        $this->logger = $logger;
92 20
    }
93
94
    /**
95
     * @param Request $request     request to authenticate
96
     * @param string  $providerKey provider key to auth with
97
     *
98
     * @return PreAuthenticatedToken
99
     */
100 10
    public function createToken(Request $request, $providerKey)
101
    {
102
        // look for an apikey query parameter
103 10
        $apiKey = $this->extractionStrategy->apply($request);
104
105 10
        $token = new PreAuthenticatedToken(
106 10
            'anon.',
107 5
            $apiKey,
108 5
            $providerKey,
109 10
            $this->extractionStrategy->getRoles()
110 5
        );
111
112 10
        $token->setAttribute('ipAddress', $request->getClientIp());
113
114 10
        return $token;
115
    }
116
117
    /**
118
     * Tries to authenticate the provided token
119
     *
120
     * @param TokenInterface        $token        token to authenticate
121
     * @param UserProviderInterface $userProvider provider to auth against
122
     * @param string                $providerKey  key to auth with
123
     *
124
     * @return PreAuthenticatedToken
125
     */
126 4
    public function authenticateToken(
127
        TokenInterface $token,
128
        UserProviderInterface $userProvider,
129
        $providerKey
130
    ) {
131 4
        $username = $token->getCredentials();
132 4
        $roles    = array_map(array($this, 'objectRolesToArray'), $token->getRoles());
133 4
        $user     = false;
134
135
        // If no username in Strategy, check if required.
136 4
        if ($this->securityRequired && !$username) {
137
            $this->logger->warning('Authentication key is required.');
138
            throw new AuthenticationException('Authentication key is required.');
139
        }
140
141 4
        if (in_array(SecurityUser::ROLE_SUBNET, $roles)) {
142
            $this->logger->info('Authentication, loaded subnet user IP address: '. $token->getAttribute('ipAddress'));
143
            $user = new SubnetUser($username);
144 4
        } elseif ($username && $user = $this->userProvider->loadUserByUsername($username)) {
145 2
            $roles[] = SecurityUser::ROLE_CONSULTANT;
146 1
        }
147
148
        // If no user, try to fetch the test user, else check if anonymous is enabled
149 4
        if (!$user) {
150 2
            if ($this->testUsername && $user = $this->userProvider->loadUserByUsername($this->testUsername)) {
151
                $this->logger->info('Authentication, test user: ' . $this->testUsername);
152
                $roles[] = SecurityUser::ROLE_TEST;
153 2
            } elseif ($this->allowAnonymous) {
154
                $this->logger->info('Authentication, loading anonymous user.');
155
                $user = new AnonymousUser();
156
                $roles[] = SecurityUser::ROLE_ANONYMOUS;
157
            }
158 1
        }
159
160
        /** @var SecurityUser $securityUser */
161 4
        if ($user) {
162 2
            $securityUser = new SecurityUser($user, $roles);
163 1
        } else {
164 2
            $this->logger->warning(sprintf('Authentication key "%s" could not be resolved.', $username));
165 2
            throw new AuthenticationException(
166 2
                sprintf('Authentication key "%s" could not be resolved.', $username)
167 1
            );
168
        }
169
170 2
        return new PreAuthenticatedToken(
171 1
            $securityUser,
172 1
            $username,
173 1
            $providerKey,
174 2
            $securityUser->getRoles()
175 1
        );
176
    }
177
178
    /**
179
     * Convert object role to string role.
180
     *
181
     * @param RoleInterface $role Object role
182
     * @return null|string
183
     */
184
    private function objectRolesToArray(RoleInterface $role)
185
    {
186
        return $role->getRole();
187
    }
188
189
    /**
190
     * @param TokenInterface $token       token to check
191
     * @param string         $providerKey provider to check against
192
     *
193
     * @return bool
194
     */
195 2
    public function supportsToken(TokenInterface $token, $providerKey)
196
    {
197 2
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
198
    }
199
200
    /**
201
     * This is called when an interactive authentication attempt fails. This is
202
     * called by authentication listeners inheriting from
203
     * AbstractAuthenticationListener.
204
     *
205
     * @param Request                 $request   original request
206
     * @param AuthenticationException $exception exception from auth attempt
207
     *
208
     * @return Response|null
209
     */
210 2
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
211
    {
212 2
        return new Response(
213 2
            $exception->getMessageKey(),
214 1
            Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED
215 1
        );
216
    }
217
}
218