Passed
Push — master ( 88c28f...afe883 )
by Maurício
07:32
created

test/classes/TwoFactorTest.php (11 issues)

1
<?php
2
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
/**
4
 * tests for TwoFactor class
5
 *
6
 * @package PhpMyAdmin-test
7
 */
8
declare(strict_types=1);
9
10
namespace PhpMyAdmin\Tests;
11
12
use PhpMyAdmin\TwoFactor;
13
use Samyoul\U2F\U2FServer\RegistrationRequest;
14
use Samyoul\U2F\U2FServer\SignRequest;
15
16
/**
17
 * Tests behaviour of TwoFactor class
18
 *
19
 * @package PhpMyAdmin-test
20
 */
21
class TwoFactorTest extends PmaTestCase
22
{
23
    /**
24
     * @return void
25
     */
26
    protected function setUp(): void
27
    {
28
        $GLOBALS['server'] = 1;
29
        $GLOBALS['db'] = 'db';
30
        $GLOBALS['table'] = 'table';
31
        $GLOBALS['PMA_PHP_SELF'] = 'index.php';
32
        $GLOBALS['cfg']['Server']['DisableIS'] = false;
33
    }
34
35
    /**
36
     * Creates TwoFactor mock with custom configuration
37
     *
38
     * @param string $user   Username
39
     * @param array  $config Two factor authentication configuration
40
     *
41
     * @return TwoFactor
42
     */
43
    public function getTwoFactorMock($user, $config)
44
    {
45
        if (! isset($config['backend'])) {
46
            $config['backend'] = '';
47
        }
48
        if (! isset($config['settings'])) {
49
            $config['settings'] = [];
50
        }
51
        $result = $this->getMockBuilder('PhpMyAdmin\TwoFactor')
52
            ->setMethods(['readConfig'])
53
            ->disableOriginalConstructor()
54
            ->getMock();
55
        $result->method('readConfig')->willReturn($config);
56
        $result->__construct($user);
57
        return $result;
58
    }
59
60
    /**
61
     * @return void
62
     */
63
    public function testNone()
64
    {
65
        $object = $this->getTwoFactorMock('user', ['type' => 'db']);
66
        $backend = $object->backend;
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
67
        $this->assertEquals('', $backend::$id);
68
        // Is always valid
69
        $this->assertTrue($object->check(true));
70
        // Test session persistence
71
        $this->assertTrue($object->check());
72
        $this->assertTrue($object->check());
73
        $this->assertEquals('', $object->render());
74
        $this->assertTrue($object->configure(''));
75
        $this->assertEquals('', $object->setup());
76
    }
77
78
    /**
79
     * @return void
80
     */
81
    public function testSimple()
82
    {
83
        $GLOBALS['cfg']['DBG']['simple2fa'] = true;
84
        $object = $this->getTwoFactorMock('user', ['type' => 'db', 'backend' => 'simple']);
85
        $backend = $object->backend;
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
86
        $this->assertEquals('simple', $backend::$id);
87
        $GLOBALS['cfg']['DBG']['simple2fa'] = false;
88
89
        unset($_POST['2fa_confirm']);
90
        $this->assertFalse($object->check(true));
91
92
        $_POST['2fa_confirm'] = 1;
93
        $this->assertTrue($object->check(true));
94
        unset($_POST['2fa_confirm']);
95
96
        /* Test rendering */
97
        $this->assertNotEquals('', $object->render());
98
        $this->assertEquals('', $object->setup());
99
    }
100
101
    /**
102
     * @return void
103
     */
104
    public function testLoad()
105
    {
106
        $object = new TwoFactor('user');
107
        $backend = $object->backend;
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
108
        $this->assertEquals('', $backend::$id);
109
    }
110
111
    /**
112
     * @return void
113
     */
114
    public function testConfigureSimple()
115
    {
116
        $GLOBALS['cfg']['DBG']['simple2fa'] = true;
117
        $object = new TwoFactor('user');
118
        $this->assertTrue($object->configure('simple'));
119
        $backend = $object->backend;
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
120
        $this->assertEquals('simple', $backend::$id);
121
        $this->assertTrue($object->configure(''));
122
        $backend = $object->backend;
123
        $this->assertEquals('', $backend::$id);
124
        $GLOBALS['cfg']['DBG']['simple2fa'] = false;
125
        $object = new TwoFactor('user');
126
        $this->assertFalse($object->configure('simple'));
127
    }
128
129
    /**
130
     * @return void
131
     */
132
    public function testApplication()
133
    {
134
        $object = new TwoFactor('user');
135
        if (! in_array('application', $object->available)) {
0 ignored issues
show
Bug Best Practice introduced by
The property available does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
136
            $this->markTestSkipped('google2fa not available');
137
        }
138
        /* Without providing code this should fail */
139
        unset($_POST['2fa_code']);
140
        $this->assertFalse($object->configure('application'));
141
142
        /* Invalid code */
143
        $_POST['2fa_code'] = 'invalid';
144
        $this->assertFalse($object->configure('application'));
145
146
        /* Generate valid code */
147
        $google2fa = $object->backend->google2fa;
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
The property google2fa does not seem to exist on PhpMyAdmin\Plugins\TwoFactorPlugin.
Loading history...
148
        $_POST['2fa_code'] = $google2fa->oathHotp(
149
            $object->config['settings']['secret'],
150
            $google2fa->getTimestamp()
151
        );
152
        $this->assertTrue($object->configure('application'));
153
        unset($_POST['2fa_code']);
154
155
        /* Check code */
156
        unset($_POST['2fa_code']);
157
        $this->assertFalse($object->check(true));
158
        $_POST['2fa_code'] = 'invalid';
159
        $this->assertFalse($object->check(true));
160
        $_POST['2fa_code'] = $google2fa->oathHotp(
161
            $object->config['settings']['secret'],
162
            $google2fa->getTimestamp()
163
        );
164
        $this->assertTrue($object->check(true));
165
        unset($_POST['2fa_code']);
166
167
        /* Test rendering */
168
        $this->assertNotEquals('', $object->render());
169
        $this->assertNotEquals('', $object->setup());
170
    }
171
172
    /**
173
     * @return void
174
     */
175
    public function testKey()
176
    {
177
        $object = new TwoFactor('user');
178
        if (! in_array('key', $object->available)) {
0 ignored issues
show
Bug Best Practice introduced by
The property available does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
179
            $this->markTestSkipped('u2f-php-server not available');
180
        }
181
        $_SESSION['registrationRequest'] = null;
182
        /* Without providing code this should fail */
183
        unset($_POST['u2f_registration_response']);
184
        $this->assertFalse($object->configure('key'));
185
186
        /* Invalid code */
187
        $_POST['u2f_registration_response'] = 'invalid';
188
        $this->assertFalse($object->configure('key'));
189
190
        /* Invalid code */
191
        $_POST['u2f_registration_response'] = '[]';
192
        $this->assertFalse($object->configure('key'));
193
194
        /* Without providing code this should fail */
195
        unset($_POST['u2f_authentication_response']);
196
        $this->assertFalse($object->check(true));
197
198
        /* Invalid code */
199
        $_POST['u2f_authentication_response'] = 'invalid';
200
        $this->assertFalse($object->check(true));
201
202
        /* Invalid code */
203
        $_POST['u2f_authentication_response'] = '[]';
204
        $this->assertFalse($object->check(true));
205
206
        /* Test rendering */
207
        $this->assertNotEquals('', $object->render());
208
        $this->assertNotEquals('', $object->setup());
209
    }
210
211
    /**
212
     * Test getting AppId
213
     *
214
     * @return void
215
     */
216
    public function testKeyAppId()
217
    {
218
        $object = new TwoFactor('user');
219
        $GLOBALS['PMA_Config']->set('PmaAbsoluteUri', 'http://demo.example.com');
220
        $this->assertEquals('http://demo.example.com', $object->backend->getAppId(true));
0 ignored issues
show
Bug Best Practice introduced by
The property backend does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
221
        $this->assertEquals('demo.example.com', $object->backend->getAppId(false));
222
        $GLOBALS['PMA_Config']->set('PmaAbsoluteUri', 'https://demo.example.com:123');
223
        $this->assertEquals('https://demo.example.com:123', $object->backend->getAppId(true));
224
        $this->assertEquals('demo.example.com', $object->backend->getAppId(false));
225
        $GLOBALS['PMA_Config']->set('PmaAbsoluteUri', '');
226
        $GLOBALS['PMA_Config']->set('is_https', true);
227
        $_SERVER['HTTP_HOST'] = 'pma.example.com';
228
        $this->assertEquals('https://pma.example.com', $object->backend->getAppId(true));
229
        $this->assertEquals('pma.example.com', $object->backend->getAppId(false));
230
        $GLOBALS['PMA_Config']->set('is_https', false);
231
        $this->assertEquals('http://pma.example.com', $object->backend->getAppId(true));
232
        $this->assertEquals('pma.example.com', $object->backend->getAppId(false));
233
    }
234
235
    /**
236
     * Test based on upstream test data:
237
     * https://github.com/Yubico/php-u2flib-server
238
     *
239
     * @return void
240
     */
241
    public function testKeyAuthentication()
242
    {
243
        $object = new TwoFactor('user');
244
        if (! in_array('key', $object->available)) {
0 ignored issues
show
Bug Best Practice introduced by
The property available does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
245
            $this->markTestSkipped('u2f-php-server not available');
246
        }
247
        $_SESSION['registrationRequest'] = new RegistrationRequest('yKA0x075tjJ-GE7fKTfnzTOSaNUOWQxRd9TWz5aFOg8', 'http://demo.example.com');
248
        unset($_POST['u2f_registration_response']);
249
        $this->assertFalse($object->configure('key'));
250
251
        $_POST['u2f_registration_response'] = '';
252
        $this->assertFalse($object->configure('key'));
253
254
        $_POST['u2f_registration_response'] = '{ "registrationData": "BQQtEmhWVgvbh-8GpjsHbj_d5FB9iNoRL8mNEq34-ANufKWUpVdIj6BSB_m3eMoZ3GqnaDy3RA5eWP8mhTkT1Ht3QAk1GsmaPIQgXgvrBkCQoQtMFvmwYPfW5jpRgoMPFxquHS7MTt8lofZkWAK2caHD-YQQdaRBgd22yWIjPuWnHOcwggLiMIHLAgEBMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMTEll1YmljbyBVMkYgVGVzdCBDQTAeFw0xNDA1MTUxMjU4NTRaFw0xNDA2MTQxMjU4NTRaMB0xGzAZBgNVBAMTEll1YmljbyBVMkYgVGVzdCBFRTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNsK2_Uhx1zOY9ym4eglBg2U5idUGU-dJK8mGr6tmUQflaNxkQo6IOc-kV4T6L44BXrVeqN-dpCPr-KKlLYw650wDQYJKoZIhvcNAQELBQADggIBAJVAa1Bhfa2Eo7TriA_jMA8togoA2SUE7nL6Z99YUQ8LRwKcPkEpSpOsKYWJLaR6gTIoV3EB76hCiBaWN5HV3-CPyTyNsM2JcILsedPGeHMpMuWrbL1Wn9VFkc7B3Y1k3OmcH1480q9RpYIYr-A35zKedgV3AnvmJKAxVhv9GcVx0_CewHMFTryFuFOe78W8nFajutknarupekDXR4tVcmvj_ihJcST0j_Qggeo4_3wKT98CgjmBgjvKCd3Kqg8n9aSDVWyaOZsVOhZj3Fv5rFu895--D4qiPDETozJIyliH-HugoQpqYJaTX10mnmMdCa6aQeW9CEf-5QmbIP0S4uZAf7pKYTNmDQ5z27DVopqaFw00MIVqQkae_zSPX4dsNeeoTTXrwUGqitLaGap5ol81LKD9JdP3nSUYLfq0vLsHNDyNgb306TfbOenRRVsgQS8tJyLcknSKktWD_Qn7E5vjOXprXPrmdp7g5OPvrbz9QkWa1JTRfo2n2AXV02LPFc-UfR9bWCBEIJBxvmbpmqt0MnBTHWnth2b0CU_KJTDCY3kAPLGbOT8A4KiI73pRW-e9SWTaQXskw3Ei_dHRILM_l9OXsqoYHJ4Dd3tbfvmjoNYggSw4j50l3unI9d1qR5xlBFpW5sLr8gKX4bnY4SR2nyNiOQNLyPc0B0nW502aMEUCIQDTGOX-i_QrffJDY8XvKbPwMuBVrOSO-ayvTnWs_WSuDQIgZ7fMAvD_Ezyy5jg6fQeuOkoJi8V2naCtzV-HTly8Nww=", "clientData": "eyAiY2hhbGxlbmdlIjogInlLQTB4MDc1dGpKLUdFN2ZLVGZuelRPU2FOVU9XUXhSZDlUV3o1YUZPZzgiLCAib3JpZ2luIjogImh0dHA6XC9cL2RlbW8uZXhhbXBsZS5jb20iLCAidHlwIjogIm5hdmlnYXRvci5pZC5maW5pc2hFbnJvbGxtZW50IiB9", "errorCode": 0 }';
255
        $this->assertTrue($object->configure('key'));
256
257
        unset($_POST['u2f_authentication_response']);
258
        $this->assertFalse($object->check(true));
259
260
        $_POST['u2f_authentication_response'] = '';
261
        $this->assertFalse($object->check(true));
262
263
        $_SESSION['authenticationRequest'] = [new SignRequest([
264
            'challenge' => 'fEnc9oV79EaBgK5BoNERU5gPKM2XGYWrz4fUjgc0Q7g',
265
            'keyHandle' => 'CTUayZo8hCBeC-sGQJChC0wW-bBg99bmOlGCgw8XGq4dLsxO3yWh9mRYArZxocP5hBB1pEGB3bbJYiM-5acc5w',
266
            'appId' => 'http://demo.example.com',
267
        ]),
268
        ];
269
        $this->assertFalse($object->check(true));
270
        $_POST['u2f_authentication_response'] = '{ "signatureData": "AQAAAAQwRQIhAI6FSrMD3KUUtkpiP0jpIEakql-HNhwWFngyw553pS1CAiAKLjACPOhxzZXuZsVO8im-HStEcYGC50PKhsGp_SUAng==", "clientData": "eyAiY2hhbGxlbmdlIjogImZFbmM5b1Y3OUVhQmdLNUJvTkVSVTVnUEtNMlhHWVdyejRmVWpnYzBRN2ciLCAib3JpZ2luIjogImh0dHA6XC9cL2RlbW8uZXhhbXBsZS5jb20iLCAidHlwIjogIm5hdmlnYXRvci5pZC5nZXRBc3NlcnRpb24iIH0=", "keyHandle": "CTUayZo8hCBeC-sGQJChC0wW-bBg99bmOlGCgw8XGq4dLsxO3yWh9mRYArZxocP5hBB1pEGB3bbJYiM-5acc5w", "errorCode": 0 }';
271
        $this->assertTrue($object->check(true));
272
    }
273
274
    /**
275
     * Test listing of available backends.
276
     *
277
     * @return void
278
     */
279
    public function testBackends()
280
    {
281
        $GLOBALS['cfg']['DBG']['simple2fa'] = true;
282
        $object = new TwoFactor('user');
283
        $backends = $object->getAllBackends();
284
        $this->assertCount(
285
            count($object->available) + 1,
0 ignored issues
show
Bug Best Practice introduced by
The property available does not exist on PhpMyAdmin\TwoFactor. Since you implemented __get, consider adding a @property annotation.
Loading history...
286
            $backends
287
        );
288
        $GLOBALS['cfg']['DBG']['simple2fa'] = false;
289
    }
290
}
291