Completed
Push — master ( 4e92df...3d6026 )
by Robbie
12s
created

testRemoveRegistrationSuccessIndicatesIfTheBackupMethodIsRegistered()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 32
rs 9.6333
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\MFA\Tests\Controller;
4
5
use SilverStripe\Admin\AdminRootController;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\HTTPRequest;
8
use SilverStripe\Core\Config\Config;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\Dev\FunctionalTest;
11
use SilverStripe\MFA\Controller\AdminRegistrationController;
12
use SilverStripe\MFA\Model\RegisteredMethod;
13
use SilverStripe\MFA\Service\MethodRegistry;
14
use SilverStripe\MFA\Service\RegisteredMethodManager;
15
use SilverStripe\MFA\State\AvailableMethodDetails;
16
use SilverStripe\MFA\Store\SessionStore;
17
use SilverStripe\MFA\Tests\Stub\BasicMath\Method as BasicMathMethod;
18
use SilverStripe\Security\Member;
19
use SilverStripe\Security\SecurityToken;
20
21
class AdminRegistrationControllerTest extends FunctionalTest
22
{
23
    protected static $fixture_file = 'AdminRegistrationControllerTest.yml';
24
25
    protected function setUp()
26
    {
27
        parent::setUp();
28
29
        MethodRegistry::config()->set('methods', [
30
            BasicMathMethod::class,
31
        ]);
32
    }
33
34
    public function testStartRegistrationAssertsValidMethod()
35
    {
36
        $this->logInAs($this->objFromFixture(Member::class, 'sally_smith'));
37
38
        $result = $this->get(Controller::join_links(AdminRootController::admin_url(), 'mfa', 'register/foo'));
39
40
        $this->assertSame(400, $result->getStatusCode());
41
        $this->assertContains('No such method is available', $result->getBody());
42
    }
43
44
    public function testStartRegistrationReturns200Response()
45
    {
46
        $this->logInAs($this->objFromFixture(Member::class, 'sally_smith'));
47
        $method = new BasicMathMethod();
48
49
        $result = $this->get(
50
            Controller::join_links(
51
                AdminRootController::admin_url(),
52
                'mfa',
53
                'register',
54
                $method->getURLSegment()
55
            )
56
        );
57
58
        $this->assertSame(200, $result->getStatusCode());
59
    }
60
61
    public function testFinishRegistrationGracefullyHandlesInvalidSessions()
62
    {
63
        $this->logInAs($this->objFromFixture(Member::class, 'sally_smith'));
64
        $method = new BasicMathMethod();
65
66
        $result = $this->post(
67
            Controller::join_links(
68
                AdminRootController::admin_url(),
69
                'mfa',
70
                'register',
71
                $method->getURLSegment()
72
            ),
73
            ['dummy' => 'data']
74
        );
75
76
        $this->assertSame(400, $result->getStatusCode());
77
        $this->assertContains('Invalid session', $result->getBody());
78
    }
79
80
    public function testFinishRegistrationAssertsValidMethod()
81
    {
82
        /** @var Member $member */
83
        $member = $this->objFromFixture(Member::class, 'sally_smith');
84
        $this->logInAs($member);
85
        $method = new BasicMathMethod();
86
87
        $store = new SessionStore($member);
88
        $store->setMethod($method->getURLSegment());
89
        $this->session()->set(SessionStore::SESSION_KEY, $store);
90
91
        $result = $this->post(
92
            Controller::join_links(
93
                AdminRootController::admin_url(),
94
                'mfa',
95
                'register',
96
                'foo'
97
            ),
98
            ['dummy' => 'data']
99
        );
100
101
        $this->assertSame(400, $result->getStatusCode());
102
        $this->assertContains('No such method is available', $result->getBody());
103
    }
104
105
    public function testFinishRegistrationCompletesWhenValid()
106
    {
107
        /** @var Member $member */
108
        $member = $this->objFromFixture(Member::class, 'sally_smith');
109
        $this->logInAs($member);
110
        $method = new BasicMathMethod();
111
112
        $store = new SessionStore($member);
113
        $store->setMethod($method->getURLSegment());
114
        $this->session()->set(SessionStore::SESSION_KEY, $store);
115
116
        $result = $this->post(
117
            Controller::join_links(
118
                AdminRootController::admin_url(),
119
                'mfa',
120
                'register',
121
                $method->getURLSegment()
122
            ),
123
            ['dummy' => 'data'],
124
            null,
125
            $this->session(),
126
            json_encode(['number' => 7])
127
        );
128
129
        $this->assertSame(201, $result->getStatusCode());
130
    }
131
132
    public function testRemoveRegistrationChecksCSRF()
133
    {
134
        SecurityToken::enable();
135
136
        $controller = new AdminRegistrationController();
137
        $request = new HTTPRequest('GET', '');
138
        $response = $controller->removeRegisteredMethod($request);
139
140
        $this->assertSame(400, $response->getStatusCode());
141
        $this->assertContains('Request timed out', $response->getBody());
142
143
        $token = SecurityToken::inst();
144
        $request = new HTTPRequest('GET', '', [$token->getName() => $token->getValue()]);
145
146
        $response = $controller->removeRegisteredMethod($request);
147
148
        $this->assertNotContains('Request timed out', $response->getBody());
149
    }
150
151
    public function testRemoveRegistrationRequiresMethod()
152
    {
153
        $this->logInWithPermission();
154
155
        // Prep a mock for deleting methods
156
        $registeredMethodManager = $this->scaffoldRegisteredMethodManagerMock();
157
158
        $controller = new AdminRegistrationController();
159
160
        // Method not even provided
161
        $request = new HTTPRequest('GET', '');
162
        $response = $controller->removeRegisteredMethod($request);
163
164
        $this->assertSame(400, $response->getStatusCode());
165
        $this->assertContains('No such method is available', $response->getBody());
166
167
        // Method provided but non-existing
168
        $request = new HTTPRequest('GET', '');
169
        $request->setRouteParams(['Method' => 'fake123']);
170
        $response = $controller->removeRegisteredMethod($request);
171
172
        $this->assertSame(400, $response->getStatusCode());
173
        $this->assertContains('No such method is available', $response->getBody());
174
175
        // Existing method
176
        $request = new HTTPRequest('GET', '');
177
        $basicMathMethod = new BasicMathMethod();
178
        $request->setRouteParams(['Method' => $basicMathMethod->getURLSegment()]);
179
        $registeredMethodManager->expects($this->once())->method('deleteFromMember')->willReturn(true);
180
        $response = $controller->removeRegisteredMethod($request);
181
182
        $this->assertSame(200, $response->getStatusCode());
183
        $this->assertTrue(json_decode($response->getBody())->success);
184
    }
185
186
    public function testRemoveRegistrationSuccessIsReflectedInResponse()
187
    {
188
        $this->logInWithPermission();
189
190
        // Prep a mock for deleting methods
191
        $registeredMethodManager = $this->scaffoldRegisteredMethodManagerMock();
192
193
        $controller = new AdminRegistrationController();
194
195
        $request = new HTTPRequest('GET', '');
196
        $basicMathMethod = new BasicMathMethod();
197
        $request->setRouteParams(['Method' => $basicMathMethod->getURLSegment()]);
198
199
        $registeredMethodManager->expects($this->exactly(2))->method('deleteFromMember')->willReturn(true, false);
200
201
        $response = $controller->removeRegisteredMethod($request);
202
203
        $this->assertSame(200, $response->getStatusCode());
204
        $this->assertTrue(json_decode($response->getBody())->success);
205
206
        $response = $controller->removeRegisteredMethod($request);
207
208
        $this->assertSame(400, $response->getStatusCode());
209
        $this->assertContains('Could not delete the specified method from the user', $response->getBody());
210
    }
211
212
    public function testRemoveRegistrationSuccessResponseIncludesTheNowAvailableMethod()
213
    {
214
        $this->logInWithPermission();
215
216
        // Prep a mock for deleting methods
217
        $registeredMethodManager = $this->scaffoldRegisteredMethodManagerMock();
218
219
        $controller = new AdminRegistrationController();
220
221
        $request = new HTTPRequest('GET', '');
222
        $basicMathMethod = new BasicMathMethod();
223
        $request->setRouteParams(['Method' => $basicMathMethod->getURLSegment()]);
224
        $registeredMethodManager->expects($this->once())->method('deleteFromMember')->willReturn(true);
225
226
        $expectedAvailableMethod = new AvailableMethodDetails($basicMathMethod);
227
228
        $response = $controller->removeRegisteredMethod($request);
229
230
        $this->assertSame(
231
            $expectedAvailableMethod->jsonSerialize(),
232
            json_decode($response->getBody(), true)['availableMethod']
233
        );
234
    }
235
236
    public function testRemoveRegistrationSuccessIndicatesIfTheBackupMethodIsRegistered()
237
    {
238
        $this->logInWithPermission();
239
240
        // Prep a mock for deleting methods
241
        $registeredMethodManager = $this->scaffoldRegisteredMethodManagerMock();
242
243
        $controller = new AdminRegistrationController();
244
245
        $request = new HTTPRequest('GET', '');
246
        $basicMathMethod = new BasicMathMethod();
247
        $request->setRouteParams(['Method' => $basicMathMethod->getURLSegment()]);
248
        $registeredMethodManager->expects($this->any())->method('deleteFromMember')->willReturn(true);
249
250
        // Test when there's no backup method registered
251
        Config::modify()->set(MethodRegistry::class, 'default_backup_method', null);
252
        $response = $controller->removeRegisteredMethod($request);
253
        $this->assertFalse(json_decode($response->getBody())->hasBackupMethod);
254
255
        // Make "basic math" the backup method as it's the only available method
256
        Config::modify()->set(MethodRegistry::class, 'default_backup_method', BasicMathMethod::class);
257
258
        // Mock checking for the registered backup method when it's not registered (first) and then when it is (second)
259
        $registeredMethodManager
260
            ->expects($this->exactly(2))
261
            ->method('getFromMember')
262
            ->willReturn(null, new RegisteredMethod());
263
264
        $response = $controller->removeRegisteredMethod($request);
265
        $this->assertFalse(json_decode($response->getBody())->hasBackupMethod);
266
        $response = $controller->removeRegisteredMethod($request);
267
        $this->assertTrue(json_decode($response->getBody())->hasBackupMethod);
268
    }
269
270
    protected function scaffoldRegisteredMethodManagerMock()
271
    {
272
        $mock = $this->createMock(RegisteredMethodManager::class);
273
        Injector::inst()->registerService($mock, RegisteredMethodManager::class);
274
275
        return $mock;
276
    }
277
}
278