Completed
Push — master ( 682861...9e510a )
by Ross
36:42
created

Postdispatch::isTwoFactorEnabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * A two factor authentication module that protects both the admin and customer logins
4
 * Copyright (C) 2017  Ross Mitchell
5
 *
6
 * This file is part of Rossmitchell/Twofactor.
7
 *
8
 * Rossmitchell/Twofactor is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
namespace Rossmitchell\Twofactor\Observer\Controller\Frontend;
23
24
use Magento\Framework\App\Action\Action;
25
use Magento\Framework\App\ResponseFactory;
26
use Magento\Framework\Event\Observer;
27
use Magento\Framework\Event\ObserverInterface;
28
use Magento\Framework\UrlInterface;
29
use Rossmitchell\Twofactor\Model\Config\Customer as CustomerAdmin;
30
use Rossmitchell\Twofactor\Model\Customer\Attribute\IsUsingTwoFactor;
31
use Rossmitchell\Twofactor\Model\Customer\Customer;
32
use Rossmitchell\Twofactor\Model\Customer\Session;
33
use Rossmitchell\Twofactor\Model\Urls\Checker;
34
use Rossmitchell\Twofactor\Model\Urls\Fetcher;
35
use Rossmitchell\Twofactor\Model\Verification\IsVerified;
36
use Rossmitchell\Twofactor\Model\TwoFactorUrls;
37
38
/**
39
 * Class Postdispatch
40
 *
41
 * This is call after the page response has been generated, but before it has been sent through to the user. There are a
42
 * couple of benefits to calling the method at this point rather than before the response has been generated. First, it
43
 * gets called as soon as the customer logs in, which should save a redirect, and it also means that everything has
44
 * already been instantiated, so I don't have to worry about the session issues that can crop up when a method is called
45
 * to early.
46
 *
47
 * @TODO: This method is really quite complicate3d and should be refactored into separate classes
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
48
 */
49
class Postdispatch implements ObserverInterface
50
{
51
    /**
52
     * @var ResponseFactory
53
     */
54
    private $responseFactory;
55
    /**
56
     * @var UrlInterface
57
     */
58
    private $url;
59
    /**
60
     * @var Customer
61
     */
62
    private $customerGetter;
63
    /**
64
     * @var IsUsingTwoFactor
65
     */
66
    private $isUsingTwoFactor;
67
    /**
68
     * @var IsVerified
69
     */
70
    private $isVerified;
71
    /**
72
     * @var Session
73
     */
74
    private $customerSession;
75
    /**
76
     * @var CustomerAdmin
77
     */
78
    private $customerAdmin;
79
    /**
80
     * @var Fetcher
81
     */
82
    private $fetcher;
83
    /**
84
     * @var Checker
85
     */
86
    private $checker;
87
88
    /**
89
     * Predispatch constructor.
90
     *
91
     * @param ResponseFactory $responseFactory
92
     * @param UrlInterface $url
93
     * @param Customer $customerGetter
94
     * @param IsVerified $isVerified
95
     * @param Session $customerSession
96
     * @param IsUsingTwoFactor $isUsingTwoFactor
97
     * @param CustomerAdmin $customerAdmin
98
     * @param Fetcher $fetcher
99
     * @param Checker $checker
100
     */
101 42
    public function __construct(
102
        ResponseFactory $responseFactory,
103
        UrlInterface $url,
104
        Customer $customerGetter,
105
        IsVerified $isVerified,
106
        Session $customerSession,
107
        IsUsingTwoFactor $isUsingTwoFactor,
108
        CustomerAdmin $customerAdmin,
109
        Fetcher $fetcher,
110
        Checker $checker
111
    ) {
112 42
        $this->responseFactory  = $responseFactory;
113 42
        $this->url              = $url;
114 42
        $this->customerGetter   = $customerGetter;
115 42
        $this->isUsingTwoFactor = $isUsingTwoFactor;
116 42
        $this->isVerified       = $isVerified;
117 42
        $this->customerSession  = $customerSession;
118 42
        $this->customerAdmin    = $customerAdmin;
119 42
        $this->fetcher = $fetcher;
120 42
        $this->checker = $checker;
121 42
    }
122
123
    /**
124
     * This is the observer method. It *now* listens for the controller_front_send_response_before event, and really
125
     * should be renamed
126
     *
127
     * @TODO: Rename the class so it matches the event
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
128
     *
129
     * @param Observer $observer
130
     *
131
     * @return void
132
     */
133 42
    public function execute(Observer $observer)
134
    {
135 42
        if ($this->customerAdmin->isTwoFactorEnabled() != true) {
136 18
            return;
137
        }
138
139 24
        if ($this->shouldTheCustomerBeRedirected() === false) {
140 18
            return;
141
        }
142
143 6
        if ($this->hasTwoFactorBeenChecked() === true) {
144 2
            return;
145
        }
146
147 4
        $controller = $observer->getEvent()->getData('response');
148 4
        $this->redirectToTwoFactorCheck($controller);
149 4
    }
150
151
    /**
152
     * This checks to see if the customer is on a page that shouldn't be redirected, if we actually have a customer, and
153
     * if so does that customer have two fact enabled. Very similar checks are done in the admin observer and this is
154
     * one of the methods that I want to refactor, once the test coverage is high enough to let me do this with
155
     * confidence
156
     *
157
     * @TODO: Refactor this
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
158
     *
159
     * @return bool
160
     */
161 24
    private function shouldTheCustomerBeRedirected()
162
    {
163 24
        if ($this->areWeOnAnAllowedPage() === true) {
164 10
            return false;
165
        }
166
167 14
        $customer = $this->customerGetter->getCustomer();
168 14
        if ($customer === false) {
169 2
            return false;
170
        }
171 12
        $usingTwoFactor = $this->isUsingTwoFactor->getValue($customer);
172 12
        if ($usingTwoFactor === false) {
173 6
            return false;
174
        }
175
176 6
        return true;
177
    }
178
179
    /**
180
     * Checks if we are on the authentication or verification page. This code is duplicated in the admin observer, other
181
     * than forAdmin flag and can be refactored
182
     *
183
     * @TODO: move this to either the Checker class or somewhere else
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
184
     *
185
     * @return bool
186
     */
187 24 View Code Duplication
    private function areWeOnAnAllowedPage()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
    {
189 24
        $twoFactorUrls = $this->checker;
190 24
        if ($twoFactorUrls->areWeOnTheAuthenticationPage(false) === true) {
191 4
            return true;
192
        }
193
194 20
        if ($twoFactorUrls->areWeOnTheVerificationPage(false) === true) {
195 6
            return true;
196
        }
197
198 14
        return false;
199
    }
200
201
    /**
202
     * Checks the session to see if the verification flag has been set. Can be refactored
203
     *
204
     * @return bool
205
     */
206 6
    private function hasTwoFactorBeenChecked()
207
    {
208 6
        $session = $this->customerSession;
209 6
        $checked = $this->isVerified->isVerified($session);
210
211 6
        return ($checked === true);
212
    }
213
214
    /**
215
     * Redirects the customer to two factor authentication page, i.e. where they need to enter in their code./
216
     *
217
     * @param $response
218
     */
219 4
    private function redirectToTwoFactorCheck($response)
220
    {
221 4
        $twoFactorCheckUrl = $this->fetcher->getAuthenticationUrl(false);
222
223 4
        $response->setRedirect($twoFactorCheckUrl);
224 4
    }
225
}
226