Completed
Push — master ( b2bb70...dcbb39 )
by Artem
02:24
created

UserLockout::onFailure()   C

Complexity

Conditions 13
Paths 73

Size

Total Lines 54
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 13

Importance

Changes 0
Metric Value
dl 0
loc 54
ccs 25
cts 25
cp 1
rs 6.7593
c 0
b 0
f 0
cc 13
eloc 26
nc 73
nop 1
crap 13

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
//----------------------------------------------------------------------
4
//
5
//  Copyright (C) 2017 Artem Rodygin
6
//
7
//  You should have received a copy of the MIT License along with
8
//  this file. If not, see <http://opensource.org/licenses/MIT>.
9
//
10
//----------------------------------------------------------------------
11
12
namespace Pignus\EventListener;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use Pignus\Model\LockAccountTrait;
16
use Psr\Log\LoggerInterface;
17
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
18
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
19
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
20
use Symfony\Component\HttpFoundation\RequestStack;
21
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
22
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
23
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
24
use Symfony\Component\Security\Core\User\UserInterface;
25
26
/**
27
 * Locks/unlocks user in accordance with the authentication attempt.
28
 */
29
class UserLockout implements ContainerAwareInterface
30
{
31
    use ContainerAwareTrait;
32
33
    protected $logger;
34
    protected $request_stack;
35
    protected $firewalls;
36
    protected $manager;
37
    protected $auth_failures;
38
    protected $lock_duration;
39
40
    /**
41
     * Dependency Injection constructor.
42
     *
43
     * @param LoggerInterface $logger
44
     * @param RequestStack    $request_stack
45
     * @param FirewallMap     $firewalls,
0 ignored issues
show
Documentation introduced by
There is no parameter named $firewalls,. Did you maybe mean $firewalls?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
46
     * @param ObjectManager   $manager
47
     * @param int             $auth_failures
48
     * @param int             $lock_duration
49
     */
50 6
    public function __construct(
51
        LoggerInterface       $logger,
52
        RequestStack          $request_stack,
53
        FirewallMap           $firewalls,
54
        ObjectManager         $manager,
55
        int                   $auth_failures = null,
56
        int                   $lock_duration = null)
57
    {
58 6
        $this->logger        = $logger;
59 6
        $this->request_stack = $request_stack;
60 6
        $this->firewalls     = $firewalls;
61 6
        $this->manager       = $manager;
62 6
        $this->auth_failures = $auth_failures;
63 6
        $this->lock_duration = $lock_duration;
64 6
    }
65
66
    /**
67
     * Callback for successful authentication event.
68
     *
69
     * @param AuthenticationEvent $event
70
     */
71 2
    public function onSuccess(AuthenticationEvent $event)
72
    {
73 2
        if ($this->auth_failures === null) {
74 1
            return;
75
        }
76
77 1
        $token = $event->getAuthenticationToken();
78
79
        /** @var LockAccountTrait $user */
80 1
        $user = $token->getUser();
81
82 1
        if ($user instanceof UserInterface && in_array(LockAccountTrait::class, class_uses($user), true)) {
83
84 1
            $this->logger->info('Authentication success', [$user->getUsername()]);
85
86 1
            $user->unlockAccount();
0 ignored issues
show
Bug introduced by
The method unlockAccount() does not seem to exist on object<Symfony\Component...ore\User\UserInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
87
88 1
            $this->manager->persist($user);
89 1
            $this->manager->flush();
90
        }
91 1
    }
92
93
    /**
94
     * Callback for failed authentication event.
95
     *
96
     * @param AuthenticationFailureEvent $event
97
     */
98 4
    public function onFailure(AuthenticationFailureEvent $event)
99
    {
100 4
        if ($this->auth_failures === null) {
101 1
            return;
102
        }
103
104
        // Retrieve failed username.
105 3
        $token = $event->getAuthenticationToken();
106
107 3
        $credentials = $token->getCredentials();
108 3
        $username    = $token->getUsername() ?: ($credentials['username'] ?? null);
109
110
        // Retrieve current user provider.
111 3
        $provider = null;
112
113 3
        if ($request = $this->request_stack->getCurrentRequest()) {
114 3
            if ($config = $this->firewalls->getFirewallConfig($request)) {
115 3
                if ($serviceId = $config->getProvider()) {
116 3
                    $provider = $this->container->get($serviceId);
117
                }
118
            }
119
        }
120
121
        // Try to fetch user entity.
122 3
        if ($username !== null && $provider !== null) {
123
124
            try {
125
                /** @var LockAccountTrait $user */
126 3
                $user = $provider->loadUserByUsername($username);
127
            }
128 1
            catch (UsernameNotFoundException $e) {
129 1
                $user = null;
130
            }
131
132 3
            if ($user instanceof UserInterface && in_array(LockAccountTrait::class, class_uses($user), true)) {
133
134 2
                $this->logger->info('Authentication failure', [$username]);
135
136 2
                if ($user->incAuthFailures() >= $this->auth_failures) {
137
138 2
                    if ($this->lock_duration === null) {
139 1
                        $user->lockAccount();
140
                    }
141
                    else {
142 1
                        $interval = sprintf('PT%dM', $this->lock_duration);
143 1
                        $user->lockAccount(date_create()->add(new \DateInterval($interval)));
144
                    }
145
                }
146
147 2
                $this->manager->persist($user);
148 2
                $this->manager->flush();
149
            }
150
        }
151 3
    }
152
}
153