Completed
Push — master ( 89ab1e...58e1a0 )
by
unknown
16:20
created

SecurityAuthenticator::authenticateToken()   C

Complexity

Conditions 11
Paths 33

Size

Total Lines 53
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 13.2061

Importance

Changes 0
Metric Value
dl 0
loc 53
ccs 28
cts 38
cp 0.7368
rs 6.2926
c 0
b 0
f 0
cc 11
eloc 35
nc 33
nop 3
crap 13.2061

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Token\PreAuthenticatedToken;
17
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18
use Symfony\Component\Security\Core\Exception\AuthenticationException;
19
use Symfony\Component\Security\Core\Role\RoleInterface;
20
use Symfony\Component\Security\Core\User\UserProviderInterface;
21
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
22
use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface;
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,
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 ($username) {
142 4
            if (in_array(SecurityUser::ROLE_SUBNET, $roles)) {
143
                $this->logger->info('Authentication, subnet user IP address: ' . $token->getAttribute('ipAddress'));
144
                $user = new SubnetUser($username);
145 4
            } elseif ($user = $this->userProvider->loadUserByUsername($username)) {
146 2
                $roles[] = SecurityUser::ROLE_CONSULTANT;
147 1
            }
148 2
        }
149
150
        // If no user, try to fetch the test user, else check if anonymous is enabled
151 4
        if (!$user) {
152 2
            if ($this->testUsername && $user = $this->userProvider->loadUserByUsername($this->testUsername)) {
153
                $this->logger->info('Authentication, test user: ' . $this->testUsername);
154
                $roles[] = SecurityUser::ROLE_TEST;
155 2
            } elseif ($this->allowAnonymous) {
156
                $this->logger->info('Authentication, loading anonymous user.');
157
                $user = new AnonymousUser();
158
                $roles[] = SecurityUser::ROLE_ANONYMOUS;
159
            }
160 1
        }
161
162
        /** @var SecurityUser $securityUser */
163 4
        if ($user) {
164 2
            $securityUser = new SecurityUser($user, $roles);
165 1
        } else {
166 2
            $this->logger->warning(sprintf('Authentication key "%s" could not be resolved.', $username));
167 2
            throw new AuthenticationException(
168 2
                sprintf('Authentication key "%s" could not be resolved.', $username)
169 1
            );
170
        }
171
172 2
        return new PreAuthenticatedToken(
173 1
            $securityUser,
174 1
            $username,
175 1
            $providerKey,
176 2
            $securityUser->getRoles()
177 1
        );
178
    }
179
180
    /**
181
     * Convert object role to string role.
182
     *
183
     * @param RoleInterface $role Object role
184
     * @return null|string
185
     */
186
    private function objectRolesToArray(RoleInterface $role)
187
    {
188
        return $role->getRole();
189
    }
190
191
    /**
192
     * @param TokenInterface $token       token to check
193
     * @param string         $providerKey provider to check against
194
     *
195
     * @return bool
196
     */
197 2
    public function supportsToken(TokenInterface $token, $providerKey)
198
    {
199 2
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
200
    }
201
202
    /**
203
     * This is called when an interactive authentication attempt fails. This is
204
     * called by authentication listeners inheriting from
205
     * AbstractAuthenticationListener.
206
     *
207
     * @param Request                 $request   original request
208
     * @param AuthenticationException $exception exception from auth attempt
209
     *
210
     * @return Response|null
211
     */
212 2
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
213
    {
214 2
        return new Response(
215 2
            $exception->getMessageKey(),
216 1
            Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED
217 1
        );
218
    }
219
}
220