Completed
Pull Request — develop (#523)
by Bastian
14:39 queued 10:07
created

SecurityAuthenticator::authenticateToken()   C

Complexity

Conditions 10
Paths 21

Size

Total Lines 56
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 21.6071

Importance

Changes 0
Metric Value
dl 0
loc 56
ccs 21
cts 41
cp 0.5122
rs 6.7741
c 0
b 0
f 0
cc 10
eloc 36
nc 21
nop 3
crap 21.6071

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\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\User\UserProviderInterface;
21
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
22
23
/**
24
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
25
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
26
 * @link     http://swisscom.ch
27
 */
28
final class SecurityAuthenticator implements
29
    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...
30
    AuthenticationFailureHandlerInterface
31
{
32
33
    /**
34
     * Authentication can be required to use any service
35
     * @var bool,
36
     */
37
    protected $securityRequired;
38
39
    /**
40
     * Authentication can use a test user if no user found
41
     * @var bool,
42
     */
43
    protected $securityTestUsername;
44
45
    /**
46
     * Authentication can allow not identified users to get information
47
     * @var bool,
48
     */
49
    protected $allowAnonymous;
50
51
    /**
52
     * @var AuthenticationProvider
53
     */
54
    protected $userProvider;
55
56
    /**
57
     * @var StrategyInterface
58
     */
59
    protected $extractionStrategy;
60
61
    /**
62
     * @var Logger
63
     */
64
    protected $logger;
65
66
67
    /**
68
     * @param boolean                $securityRequired     user provider to use
69
     * @param string                 $securityTestUsername user for testing
70
     * @param boolean                $allowAnonymous       user provider to use
71
     * @param AuthenticationProvider $userProvider         user provider to use
72
     * @param StrategyInterface      $extractionStrategy   auth strategy to use
73
     * @param Logger                 $logger               logger to user for logging errors
74
     */
75 20
    public function __construct(
76
        $securityRequired,
77
        $securityTestUsername,
78
        $allowAnonymous,
79
        AuthenticationProvider $userProvider,
80
        StrategyInterface $extractionStrategy,
81
        Logger $logger
82
    ) {
83
84 20
        $this->securityRequired     = $securityRequired;
85 20
        $this->securityTestUsername = $securityTestUsername;
86 20
        $this->allowAnonymous       = $allowAnonymous;
87 20
        $this->userProvider         = $userProvider;
88 20
        $this->extractionStrategy   = $extractionStrategy;
89
90 20
        $this->logger = $logger;
91 20
    }
92
93
    /**
94
     * @param Request $request     request to authenticate
95
     * @param string  $providerKey provider key to auth with
96
     *
97
     * @return \Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken
98
     */
99 10
    public function createToken(Request $request, $providerKey)
100
    {
101
        // look for an apikey query parameter
102 10
        $apiKey = $this->extractionStrategy->apply($request);
103
104 10
        return new PreAuthenticatedToken(
105 10
            'anon.',
106 5
            $apiKey,
107
            $providerKey
108 5
        );
109
    }
110
111
    /**
112
     * Tries to authenticate the provided token
113
     *
114
     * @param TokenInterface        $token        token to authenticate
115
     * @param UserProviderInterface $userProvider provider to auth against
116
     * @param string                $providerKey  key to auth with
117
     *
118
     * @return \Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken
119
     */
120 4
    public function authenticateToken(
0 ignored issues
show
Coding Style introduced by
authenticateToken uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
121
        TokenInterface $token,
122
        UserProviderInterface $userProvider,
123
        $providerKey
124
    ) {
125 4
        $username = $token->getCredentials();
126 4
        $securityUser = false;
127
128
        // If no username in Strategy, check if required.
129 4
        if ($this->securityRequired && !$username) {
130
            $this->logger->warning('Authentication key is required.');
131
            throw new AuthenticationException(
132
                sprintf('Authentication key is required.')
133
            );
134
        }
135
136
        /** @var SecurityUser $securityUser */
137 4
        if ($user = $this->userProvider->loadUserByUsername($username)) {
138 2
            $securityUser = new SecurityUser($user, [SecurityUser::ROLE_USER, SecurityUser::ROLE_CONSULTANT]);
139 3
        } elseif ($this->securityTestUsername) {
140
            $this->logger->info('Authentication, loading test user: '.$this->securityTestUsername);
141
            if ($user = $this->userProvider->loadUserByUsername($this->securityTestUsername)) {
142
                $securityUser = new SecurityUser($user, [SecurityUser::ROLE_USER]);
143
            }
144 2
        } elseif ($username == 'graviton_subnet_user') {
145
            $this->logger->info('Authentication, loading graviton subnet user IP address: '. $_SERVER['REMOTE_ADDR']);
146
            $securityUser = new SecurityUser(
147
                new SubnetUser($username .'::'. $_SERVER['REMOTE_ADDR']),
148
                [SecurityUser::ROLE_SUBNET]
149
            );
150
        }
151
152
        // Check if allow Anonymous
153 4
        if (!$securityUser) {
154 2
            if ($this->allowAnonymous) {
155
                $this->logger->info('Authentication, loading anonymous user.');
156
                $securityUser = new SecurityUser(new AnonymousUser(), [SecurityUser::ROLE_ANONYMOUS]);
157
            } else {
158 2
                if (empty($username)) {
159
                    $username = 'anonymous';
160
                }
161
162 2
                $this->logger->warning(sprintf('Authentication key "%s" could not be resolved.', $username));
163 2
                throw new AuthenticationException(
164 2
                    sprintf('Authentication key "%s" could not be resolved.', $username)
165 1
                );
166
            }
167
        }
168
169 2
        return new PreAuthenticatedToken(
170 1
            $securityUser,
171 1
            $username,
172 1
            $providerKey,
173 2
            $securityUser->getRoles()
174 1
        );
175
    }
176
177
    /**
178
     * @param TokenInterface $token       token to check
179
     * @param string         $providerKey provider to check against
180
     *
181
     * @return bool
182
     */
183 2
    public function supportsToken(TokenInterface $token, $providerKey)
184
    {
185 2
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
186
    }
187
188
    /**
189
     * This is called when an interactive authentication attempt fails. This is
190
     * called by authentication listeners inheriting from
191
     * AbstractAuthenticationListener.
192
     *
193
     * @param Request                 $request   original request
194
     * @param AuthenticationException $exception exception from auth attempt
195
     *
196
     * @return Response|null
197
     */
198 2
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
199
    {
200 2
        return new Response(
201 2
            $exception->getMessageKey(),
202 1
            Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED
203 1
        );
204
    }
205
}
206