-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathDigestAuthenticationTest.php
116 lines (98 loc) · 3.34 KB
/
DigestAuthenticationTest.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
declare(strict_types = 1);
namespace Middlewares\Tests;
use Middlewares\DigestAuthentication;
use Middlewares\Utils\Dispatcher;
use Middlewares\Utils\Factory;
use PHPUnit\Framework\TestCase;
class DigestAuthenticationTest extends TestCase
{
public function testError(): void
{
$response = Dispatcher::run([
// @phpstan-ignore-next-line
(new DigestAuthentication(['user' => 'pass']))->realm('My realm')->nonce('xxx'),
]);
$this->assertSame(401, $response->getStatusCode());
$this->assertSame(
sprintf('Digest realm="My realm",qop="auth",nonce="xxx",opaque="%s"', md5('My realm')),
$response->getHeaderLine('WWW-Authenticate')
);
}
public function testUserDoesNotExists(): void
{
$response = Dispatcher::run(
[
// @phpstan-ignore-next-line
(new DigestAuthentication(['user' => 'pass']))->realm('My realm')->nonce('xxx'),
],
Factory::createServerRequest('GET', '/')
->withHeader('Authorization', $this->authHeader('invalid-user', 'pass', 'My realm', 'xxx'))
);
$this->assertSame(401, $response->getStatusCode());
}
public function testInvalidPassword(): void
{
$response = Dispatcher::run(
[
// @phpstan-ignore-next-line
(new DigestAuthentication(['user' => 'pass']))->realm('My realm')->nonce('xxx'),
],
Factory::createServerRequest('GET', '/')
->withHeader('Authorization', $this->authHeader('user', 'invalid-pass', 'My realm', 'xxx'))
);
$this->assertSame(401, $response->getStatusCode());
}
public function testSuccess(): void
{
$nonce = uniqid();
$request = Factory::createServerRequest('GET', '/')
->withHeader('Authorization', $this->authHeader('user', 'pass', 'My realm', $nonce));
$response = Dispatcher::run([
(new DigestAuthentication(['user' => 'pass']))
->nonce($nonce)
->realm('My realm')
->attribute('auth-username'),
function ($request) {
echo $request->getAttribute('auth-username');
},
], $request);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('user', (string) $response->getBody());
}
/**
* @see https://tools.ietf.org/html/rfc2069#page-10
*/
private function authHeader(
string $username,
string $password,
string $realm,
string $nonce,
string $method = 'GET',
string $uri = '/'
): string {
$nc = '00000001';
$cnonce = uniqid();
$qop = 'auth';
$opaque = md5($realm);
$A1 = md5("{$username}:{$realm}:{$password}");
$A2 = md5("{$method}:{$uri}");
$response = md5("{$A1}:{$nonce}:{$nc}:{$cnonce}:{$qop}:{$A2}");
$chunks = compact(
'uri',
'username',
'realm',
'nonce',
'response',
'qop',
'nc',
'opaque',
'cnonce'
);
$header = [];
foreach ($chunks as $name => $value) {
$header[] = "{$name}=\"{$value}\"";
}
return 'Digest '.implode(', ', $header);
}
}