SamlSpAuthenticationProvider::authenticate()   B
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 23
ccs 13
cts 13
cp 1
rs 8.5907
cc 5
eloc 14
nc 6
nop 1
crap 5
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