Completed
Push — feature/evo-2472-whoami ( 843346...066c1c )
by
unknown
83:53 queued 67:03
created

SecurityAuthenticator   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 84.78%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 13
c 2
b 0
f 0
lcom 2
cbo 9
dl 0
loc 171
ccs 39
cts 46
cp 0.8478
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
A createToken() 0 11 1
C authenticateToken() 0 49 8
A supportsToken() 0 4 2
A onAuthenticationFailure() 0 7 1
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 Psr\Log\LoggerInterface as Logger;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\HttpFoundation\Response;
15
use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface as SimplePreAuthInterface;
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\User\UserProviderInterface;
20
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
21
22
/**
23
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
24
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
25
 * @link     http://swisscom.ch
26
 */
27
final class SecurityAuthenticator implements
28
    SimplePreAuthInterface,
29
    AuthenticationFailureHandlerInterface
30
{
31
32
    /**
33
     * Authentication can be required to use any service
34
     * @var bool,
35
     */
36
    protected $securityRequired;
37
38
    /**
39
     * Authentication can use a test user if no user found
40
     * @var bool,
41
     */
42
    protected $securityTestUsername;
43
44
    /**
45
     * Authentication can allow not identified users to get information
46
     * @var bool,
47
     */
48
    protected $allowAnonymous;
49
50
    /**
51
     * @var AuthenticationProvider
52
     */
53
    protected $userProvider;
54
55
    /**
56
     * @var StrategyInterface
57
     */
58
    protected $extractionStrategy;
59
60
    /**
61
     * @var Logger
62
     */
63
    protected $logger;
64
65
66
    /**
67
     * @param boolean                $securityRequired     user provider to use
68
     * @param string                 $securityTestUsername user for testing
69
     * @param boolean                $allowAnonymous       user provider to use
70
     * @param AuthenticationProvider $userProvider         user provider to use
71
     * @param StrategyInterface      $extractionStrategy   auth strategy to use
72
     * @param Logger                 $logger               logger to user for logging errors
73
     */
74 15
    public function __construct(
75
        $securityRequired,
76
        $securityTestUsername,
77
        $allowAnonymous,
78
        AuthenticationProvider $userProvider,
79
        StrategyInterface $extractionStrategy,
80
        Logger $logger
81
    ) {
82
83 15
        $this->securityRequired     = $securityRequired;
84 15
        $this->securityTestUsername = $securityTestUsername;
85 15
        $this->allowAnonymous       = $allowAnonymous;
86 15
        $this->userProvider         = $userProvider;
87 15
        $this->extractionStrategy   = $extractionStrategy;
88
89 15
        $this->logger = $logger;
90 15
    }
91
92
    /**
93
     * @param Request $request     request to authenticate
94
     * @param string  $providerKey provider key to auth with
95
     *
96
     * @return \Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken
97
     */
98 7
    public function createToken(Request $request, $providerKey)
99
    {
100
        // look for an apikey query parameter
101 7
        $apiKey = $this->extractionStrategy->apply($request);
102
103 7
        return new PreAuthenticatedToken(
104 7
            'anon.',
105 7
            $apiKey,
106
            $providerKey
107 7
        );
108
    }
109
110
    /**
111
     * Tries to authenticate the provided token
112
     *
113
     * @param TokenInterface        $token        token to authenticate
114
     * @param UserProviderInterface $userProvider provider to auth against
115
     * @param string                $providerKey  key to auth with
116
     *
117
     * @return \Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken
118
     */
119 4
    public function authenticateToken(
120
        TokenInterface $token,
121
        UserProviderInterface $userProvider,
122
        $providerKey
123
    ) {
124 4
        $username = $token->getCredentials();
125
        $securityUser = false;
126
127 4
        // If no username in Strategy, check if required.
128
        if ($this->securityRequired && !$username) {
129
            $this->logger->warning('Authentication key is required.');
130
            throw new AuthenticationException(
131
                sprintf('Authentication key is required.')
132
            );
133
        }
134
135 4
        /** @var SecurityUser $securityUser */
136
        if ($user = $this->userProvider->loadUserByUsername($username)){
137 4
            $securityUser = new SecurityUser($user, ['ROLE_GRAVITON_USER']);
0 ignored issues
show
Documentation introduced by
array('ROLE_GRAVITON_USER') is of type array<integer,string,{"0":"string"}>, but the function expects a array<integer,object<Sym...curity\Core\Role\Role>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
138
        }
139
        // Check for test user
140
        elseif ( $this->securityTestUsername) {
141
            $this->logger->info('Authentication, loading test user: '.$this->securityTestUsername);
142 4
            if ($user = $this->userProvider->loadUserByUsername($this->securityTestUsername)){
143 2
                $securityUser = new SecurityUser($user, ['ROLE_GRAVITON_USER']);
0 ignored issues
show
Documentation introduced by
array('ROLE_GRAVITON_USER') is of type array<integer,string,{"0":"string"}>, but the function expects a array<integer,object<Sym...curity\Core\Role\Role>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
144 2
            }
145 2
        }
146
147 4
        // Check if allow Anonymous
148 1
        if (!$securityUser){
149 1
            if ($this->allowAnonymous) {
150 1
                $this->logger->info('Authentication, loading anonymous user.');
151 1
                $securityUser = new SecurityUser(new AnonymousUser(), ['ROLE_GRAVITON_ANONYMOUS']);
0 ignored issues
show
Documentation introduced by
array('ROLE_GRAVITON_ANONYMOUS') is of type array<integer,string,{"0":"string"}>, but the function expects a array<integer,object<Sym...curity\Core\Role\Role>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
152
            } else {
153
                $this->logger->warning(sprintf('Authentication key "%s" could not be resolved.', $username));
154 3
                throw new AuthenticationException(
155 3
                    sprintf('Authentication key "%s" could not be resolved.', $username)
156 3
                );
157 3
            }
158 3
        }
159
160
        return new PreAuthenticatedToken(
161
            $securityUser,
162
            $username,
163
            $providerKey,
164
            $securityUser->getRoles()
165
        );
166
167
    }
168 3
169
    /**
170 3
     * @param TokenInterface $token       token to check
171
     * @param string         $providerKey provider to check against
172
     *
173
     * @return bool
174
     */
175
    public function supportsToken(TokenInterface $token, $providerKey)
176
    {
177
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
178
    }
179
180
    /**
181
     * This is called when an interactive authentication attempt fails. This is
182
     * called by authentication listeners inheriting from
183 1
     * AbstractAuthenticationListener.
184
     *
185 1
     * @param Request                 $request   original request
186 1
     * @param AuthenticationException $exception exception from auth attempt
187
     *
188 1
     * @return Response|null
189
     */
190
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
191
    {
192
        return new Response(
193
            $exception->getMessageKey(),
194
            Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED
195
        );
196
    }
197
}
198