SamlSpAuthenticationProvider   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 98.36%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 29
c 5
b 0
f 0
lcom 1
cbo 9
dl 0
loc 157
ccs 60
cts 61
cp 0.9836
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 17 5
B authenticate() 0 23 5
A getUser() 0 12 3
A supports() 0 4 2
A createAuthenticatedToken() 0 15 4
B getProviderUser() 0 20 6
A getDefaultUser() 0 6 4
1
<?php
2
3
namespace AerialShip\SamlSPBundle\Security\Core\Authentication\Provider;
4
5
use AerialShip\SamlSPBundle\Bridge\SamlSpInfo;
6
use AerialShip\SamlSPBundle\Security\Core\Authentication\Token\SamlSpToken;
7
use AerialShip\SamlSPBundle\Security\Core\User\UserManagerInterface;
8
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
9
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
10
use Symfony\Component\Security\Core\Exception\AuthenticationException;
11
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
12
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
13
use Symfony\Component\Security\Core\User\User;
14
use Symfony\Component\Security\Core\User\UserCheckerInterface;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
17
class SamlSpAuthenticationProvider implements AuthenticationProviderInterface
18
{
19
    /** @var string */
20
    protected $providerKey;
21
22
    /** @var null|UserManagerInterface */
23
    protected $userProvider;
24
25
    /** @var null|\Symfony\Component\Security\Core\User\UserCheckerInterface */
26
    protected $userChecker;
27
28
    /** @var  bool */
29
    protected $createIfNotExists;
30
31
32
33 17
    public function __construct(
34
        $providerKey,
35
        UserManagerInterface $userProvider = null,
36
        UserCheckerInterface $userChecker = null,
37
        $createIfNotExists = false
38
    ) {
39 17
        if (null !== $userProvider && null === $userChecker) {
40 1
            throw new \InvalidArgumentException('$userChecker cannot be null, if $userProvider is not null');
41
        }
42 16
        if (null == $userProvider && $createIfNotExists) {
43 1
            throw new \InvalidArgumentException('$createIfNotExists cannot be true, if $userProvider is null');
44
        }
45 15
        $this->providerKey = $providerKey;
46 15
        $this->userProvider = $userProvider;
47 15
        $this->userChecker = $userChecker;
48 15
        $this->createIfNotExists = (bool)$createIfNotExists;
49 15
    }
50
51
52
    /**
53
     * Attempts to authenticate a TokenInterface object.
54
     * @param TokenInterface $token The TokenInterface instance to authenticate
55
     * @return TokenInterface An authenticated TokenInterface instance, never null
56
     * @throws AuthenticationException if the authentication fails
57
     */
58 10
    public function authenticate(TokenInterface $token)
59
    {
60 10
        if (false == $this->supports($token)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
61 1
            return null;
62
        }
63
64
        try {
65 9
            $user = $this->getUser($token);
0 ignored issues
show
Compatibility introduced by
$token of type object<Symfony\Component...n\Token\TokenInterface> is not a sub-type of object<AerialShip\SamlSP...tion\Token\SamlSpToken>. It seems like you assume a concrete implementation of the interface Symfony\Component\Securi...on\Token\TokenInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
66
67
            /** @var $token SamlSpToken */
68 5
            return $this->createAuthenticatedToken(
69 5
                $token->getSamlSpInfo(),
70 5
                $token->getAttributes(),
71 5
                $user instanceof UserInterface ? $user->getRoles() : array(),
72
                $user
73 5
            );
74
75 4
        } catch (AuthenticationException $ex) {
76 1
            throw $ex;
77 3
        } catch (\Exception $ex) {
78 3
            throw new AuthenticationServiceException($ex->getMessage(), (int) $ex->getCode(), $ex);
79
        }
80
    }
81
82
83
    /**
84
     * @param SamlSpToken $token
85
     * @return mixed|UserInterface
86
     */
87 9
    protected function getUser(SamlSpToken $token)
88
    {
89 9
        if ($token->getUser() instanceof UserInterface) {
90 2
            $result = $token->getUser();
91 9
        } else if ($this->userProvider) {
92 6
            $result = $this->getProviderUser($token);
93 2
        } else {
94 1
            $result = $this->getDefaultUser($token);
95
        }
96
97 5
        return $result;
98
    }
99
100
101
    /**
102
     * Checks whether this provider supports the given token.
103
     * @param \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token
104
     * @return bool   true if the implementation supports the Token, false otherwise
105
     */
106 12
    public function supports(TokenInterface $token)
107
    {
108 12
        return $token instanceof SamlSpToken && $this->providerKey === $token->getProviderKey();
109
    }
110
111
112
    /**
113
     * @param \AerialShip\SamlSPBundle\Bridge\SamlSpInfo $samlInfo
114
     * @param array $attributes
115
     * @param array $roles
116
     * @param mixed $user
117
     * @return SamlSpToken
118
     */
119 5
    protected function createAuthenticatedToken(SamlSpInfo $samlInfo, array $attributes, array $roles, $user)
120
    {
121 5
        if ($user instanceof UserInterface && $this->userChecker) {
122 4
            $this->userChecker->checkPostAuth($user);
123 4
        }
124 5
        $newToken = new SamlSpToken($this->providerKey, $roles);
125 5
        $newToken->setUser($user);
126 5
        $newToken->setAttributes($attributes);
127 5
        $newToken->setSamlSpInfo($samlInfo);
128 5
        $newToken->setAuthenticated(true);
129 5
        if (!in_array('ROLE_USER', $roles)) {
130 4
            $roles[] = 'ROLE_USER';
131 4
        }
132 5
        return $newToken;
133
    }
134
135
    /**
136
     * @param SamlSpToken $token
137
     * @return UserInterface
138
     * @throws \Exception
139
     * @throws \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
140
     * @throws \RuntimeException
141
     */
142 6
    private function getProviderUser(SamlSpToken $token)
143
    {
144 6
        if (!$token || !$token->getSamlSpInfo()) {
145
            throw new \RuntimeException('Token does not contain SamlSpInfo');
146
        }
147
        try {
148 6
            $user = $this->userProvider->loadUserBySamlInfo($token->getSamlSpInfo());
149 6
        } catch (UsernameNotFoundException $ex) {
150 3
            if (false == $this->createIfNotExists) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
151 1
                throw $ex;
152
            }
153 2
            $user = $this->userProvider->createUserFromSamlInfo($token->getSamlSpInfo());
154
        }
155
156 4
        if (false == $user instanceof UserInterface) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
157 2
            throw new \RuntimeException('User provider did not return an implementation of user interface.');
158
        }
159
160 2
        return $user;
161
    }
162
163
    /**
164
     * @param \AerialShip\SamlSPBundle\Security\Core\Authentication\Token\SamlSpToken $token
165
     * @return UserInterface
166
     */
167 1
    private function getDefaultUser(SamlSpToken $token)
168
    {
169 1
        $nameID = $token && $token->getSamlSpInfo()->getNameID() && $token->getSamlSpInfo()->getNameID()->getValue() ? $token->getSamlSpInfo()->getNameID()->getValue() : 'anon.';
170 1
        $result = new User($nameID, '', array('ROLE_USER'));
171 1
        return $result;
172
    }
173
}
174