Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb2bec43

Browse files
[HttpFoundation] Add temporary URI signed
1 parentcda729e commitb2bec43

File tree

3 files changed

+158
-5
lines changed

3 files changed

+158
-5
lines changed

‎src/Symfony/Component/HttpFoundation/CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
7.1
5+
---
6+
7+
* Add optional`$expirationParameter` argument to`UriSigner::__construct()`
8+
* Add optional`$expiration` argument to`UriSigner::sign()`
9+
410
7.0
511
---
612

‎src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php‎

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,38 @@ public function testSign()
2424
$this->assertStringContainsString('?_hash=',$signer->sign('http://example.com/foo'));
2525
$this->assertStringContainsString('?_hash=',$signer->sign('http://example.com/foo?foo=bar'));
2626
$this->assertStringContainsString('&foo=',$signer->sign('http://example.com/foo?foo=bar'));
27+
28+
$this->assertStringContainsString('?_expiration=',$signer->sign('http://example.com/foo',1));
29+
$this->assertStringContainsString('&_hash=',$signer->sign('http://example.com/foo',1));
30+
$this->assertStringContainsString('?_expiration=',$signer->sign('http://example.com/foo?foo=bar',1));
31+
$this->assertStringContainsString('&_hash=',$signer->sign('http://example.com/foo?foo=bar',1));
32+
$this->assertStringContainsString('&foo=',$signer->sign('http://example.com/foo?foo=bar',1));
2733
}
2834

2935
publicfunctiontestCheck()
3036
{
3137
$signer =newUriSigner('foobar');
3238

39+
$this->assertFalse($signer->check('http://example.com/foo'));
3340
$this->assertFalse($signer->check('http://example.com/foo?_hash=foo'));
3441
$this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo'));
3542
$this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo&bar=foo'));
3643

44+
$this->assertFalse($signer->check('http://example.com/foo?_expiration=4070908800'));
45+
$this->assertFalse($signer->check('http://example.com/foo?_expiration=4070908800?_hash=foo'));
46+
$this->assertFalse($signer->check('http://example.com/foo?_expiration=4070908800&foo=bar&_hash=foo'));
47+
$this->assertFalse($signer->check('http://example.com/foo?_expiration=4070908800&foo=bar&_hash=foo&bar=foo'));
48+
3749
$this->assertTrue($signer->check($signer->sign('http://example.com/foo')));
3850
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar')));
3951
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer')));
4052

53+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo',new \DateTimeImmutable('2099-01-01 00:00:00'))));
54+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar',new \DateTimeImmutable('2099-01-01 00:00:00'))));
55+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer',new \DateTimeImmutable('2099-01-01 00:00:00'))));
56+
4157
$this->assertSame($signer->sign('http://example.com/foo?foo=bar&bar=foo'),$signer->sign('http://example.com/foo?bar=foo&foo=bar'));
58+
$this->assertSame($signer->sign('http://example.com/foo?foo=bar&bar=foo',1),$signer->sign('http://example.com/foo?bar=foo&foo=bar',1));
4259
}
4360

4461
publicfunctiontestCheckWithDifferentArgSeparator()
@@ -51,6 +68,12 @@ public function testCheckWithDifferentArgSeparator()
5168
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
5269
);
5370
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
71+
72+
$this->assertSame(
73+
'http://example.com/foo?_expiration=4070908800&_hash=xfui5FoP0vbD9Cp7pI0tHnqR1Fmj2UARqkIUw7SZVfQ%3D&baz=bay&foo=bar',
74+
$signer->sign('http://example.com/foo?foo=bar&baz=bay',new \DateTimeImmutable('2099-01-01 00:00:00'))
75+
);
76+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay',new \DateTimeImmutable('2099-01-01 00:00:00'))));
5477
}
5578

5679
publicfunctiontestCheckWithRequest()
@@ -60,17 +83,27 @@ public function testCheckWithRequest()
6083
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo'))));
6184
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo?foo=bar'))));
6285
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo?foo=bar&0=integer'))));
86+
87+
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo',new \DateTimeImmutable('2099-01-01 00:00:00')))));
88+
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo?foo=bar',new \DateTimeImmutable('2099-01-01 00:00:00')))));
89+
$this->assertTrue($signer->checkRequest(Request::create($signer->sign('http://example.com/foo?foo=bar&0=integer',new \DateTimeImmutable('2099-01-01 00:00:00')))));
6390
}
6491

6592
publicfunctiontestCheckWithDifferentParameter()
6693
{
67-
$signer =newUriSigner('foobar','qux');
94+
$signer =newUriSigner('foobar','qux','abc');
6895

6996
$this->assertSame(
7097
'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D',
7198
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
7299
);
73100
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
101+
102+
$this->assertSame(
103+
'http://example.com/foo?abc=4070908800&baz=bay&foo=bar&qux=hdhUhBVPpzKJdz5ZjC%2FkLvtOYdGKOvKVOczmmMIZK0A%3D',
104+
$signer->sign('http://example.com/foo?foo=bar&baz=bay',new \DateTimeImmutable('2099-01-01 00:00:00'))
105+
);
106+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay',new \DateTimeImmutable('2099-01-01 00:00:00'))));
74107
}
75108

76109
publicfunctiontestSignerWorksWithFragments()
@@ -81,6 +114,79 @@ public function testSignerWorksWithFragments()
81114
'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o%3D&bar=foo&foo=bar#foobar',
82115
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')
83116
);
117+
84118
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')));
119+
120+
$this->assertSame(
121+
'http://example.com/foo?_expiration=4070908800&_hash=qHl626U5d7LMsVtBxPt9GNzysdSxyOQ1fHA59Y1ib0Y%3D&bar=foo&foo=bar#foobar',
122+
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar',new \DateTimeImmutable('2099-01-01 00:00:00'))
123+
);
124+
125+
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar',new \DateTimeImmutable('2099-01-01 00:00:00'))));
126+
}
127+
128+
publicfunctiontestSignWithUriExpiration()
129+
{
130+
$signer =newUriSigner('foobar');
131+
132+
$this->assertSame($signer->sign('http://example.com/foo?foo=bar&bar=foo',new \DateTimeImmutable('2099-01-01 00:00:00')),$signer->sign('http://example.com/foo?bar=foo&foo=bar',4070908800));
133+
}
134+
135+
publicfunctiontestSignWithoutExpirationAndWithReservedHashParameter()
136+
{
137+
$signer =newUriSigner('foobar');
138+
139+
$this->expectException(\LogicException::class);
140+
141+
$signer->sign('http://example.com/foo?_hash=bar');
142+
}
143+
144+
publicfunctiontestSignWithoutExpirationAndWithReservedParameter()
145+
{
146+
$signer =newUriSigner('foobar');
147+
148+
$this->expectException(\LogicException::class);
149+
150+
$signer->sign('http://example.com/foo?_expiration=4070908800');
151+
}
152+
153+
publicfunctiontestSignWithExpirationAndWithReservedHashParameter()
154+
{
155+
$signer =newUriSigner('foobar');
156+
157+
$this->expectException(\LogicException::class);
158+
159+
$signer->sign('http://example.com/foo?_hash=bar',new \DateTimeImmutable('2099-01-01 00:00:00'));
160+
}
161+
162+
publicfunctiontestSignWithExpirationAndWithReservedParameter()
163+
{
164+
$signer =newUriSigner('foobar');
165+
166+
$this->expectException(\LogicException::class);
167+
168+
$signer->sign('http://example.com/foo?_expiration=4070908800',new \DateTimeImmutable('2099-01-01 00:00:00'));
169+
}
170+
171+
publicfunctiontestCheckWithUriExpiration()
172+
{
173+
$signer =newUriSigner('foobar');
174+
175+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo',new \DateTimeImmutable('2000-01-01 00:00:00'))));
176+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar',new \DateTimeImmutable('2000-01-01 00:00:00'))));
177+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer',new \DateTimeImmutable('2000-01-01 00:00:00'))));
178+
179+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo',1577836800)));// 2000-01-01
180+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar',1577836800)));// 2000-01-01
181+
$this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer',1577836800)));// 2000-01-01
182+
183+
$relativeUriFromNow1 =$signer->sign('http://example.com/foo',new \DateInterval('PT3S'));
184+
$relativeUriFromNow2 =$signer->sign('http://example.com/foo?foo=bar',new \DateInterval('PT3S'));
185+
$relativeUriFromNow3 =$signer->sign('http://example.com/foo?foo=bar&0=integer',new \DateInterval('PT3S'));
186+
sleep(10);
187+
188+
$this->assertFalse($signer->check($relativeUriFromNow1));
189+
$this->assertFalse($signer->check($relativeUriFromNow2));
190+
$this->assertFalse($signer->check($relativeUriFromNow3));
85191
}
86192
}

‎src/Symfony/Component/HttpFoundation/UriSigner.php‎

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,38 @@ class UriSigner
1818
{
1919
privatestring$secret;
2020
privatestring$parameter;
21+
privatestring$expirationParameter;
2122

2223
/**
23-
* @param string $parameter Query string parameter to use
24+
* @param string $parameter Query string parameter to use
25+
* @param string $expirationParameter Query string parameter to use for expiration
2426
*/
25-
publicfunction__construct(#[\SensitiveParameter]string$secret,string$parameter ='_hash')
27+
publicfunction__construct(#[\SensitiveParameter]string$secret,string$parameter ='_hash',string$expirationParameter ='_expiration')
2628
{
2729
if (!$secret) {
2830
thrownew \InvalidArgumentException('A non-empty secret is required.');
2931
}
3032

3133
$this->secret =$secret;
3234
$this->parameter =$parameter;
35+
$this->expirationParameter =$expirationParameter;
3336
}
3437

3538
/**
3639
* Signs a URI.
3740
*
3841
* The given URI is signed by adding the query string parameter
3942
* which value depends on the URI and the secret.
43+
*
44+
* @param \DateTimeInterface|\DateInterval|int|null $expiration The expiration for the given URI.
45+
* If $expiration is a \DateTimeInterface, it's expected to be the exact date + time.
46+
* If $expiration is a \DateInterval, the interval is added to "now" to get the date + time.
47+
* If $expiration is an int, it's expected to be a timestamp in seconds of the exact date + time.
48+
* If $expiration is null, no expiration.
49+
*
50+
* The expiration is added as a query string parameter.
4051
*/
41-
publicfunctionsign(string$uri):string
52+
publicfunctionsign(string$uri,\DateTimeInterface|\DateInterval|int$expiration =null):string
4253
{
4354
$url =parse_url($uri);
4455
$params = [];
@@ -47,6 +58,14 @@ public function sign(string $uri): string
4758
parse_str($url['query'],$params);
4859
}
4960

61+
if (isset($params[$this->parameter]) ||isset($params[$this->expirationParameter])) {
62+
thrownew \LogicException(sprintf('URI query parameter conflict: parameter name "%s" and "%s" are reserved.',$this->parameter,$this->expirationParameter));
63+
}
64+
65+
if (null !==$expiration) {
66+
$params[$this->expirationParameter] =$this->getExpirationTime($expiration);
67+
}
68+
5069
$uri =$this->buildUrl($url,$params);
5170
$params[$this->parameter] =$this->computeHash($uri);
5271

@@ -55,6 +74,7 @@ public function sign(string $uri): string
5574

5675
/**
5776
* Checks that a URI contains the correct hash.
77+
* Also checks if the URI has not expired (If you used expiration during signing).
5878
*/
5979
publicfunctioncheck(string$uri):bool
6080
{
@@ -72,7 +92,15 @@ public function check(string $uri): bool
7292
$hash =$params[$this->parameter];
7393
unset($params[$this->parameter]);
7494

75-
returnhash_equals($this->computeHash($this->buildUrl($url,$params)),$hash);
95+
if (!hash_equals($this->computeHash($this->buildUrl($url,$params)),$hash)) {
96+
returnfalse;
97+
}
98+
99+
if ($expiration =$params[$this->expirationParameter] ??false) {
100+
returntime() <$expiration;
101+
}
102+
103+
returntrue;
76104
}
77105

78106
publicfunctioncheckRequest(Request$request):bool
@@ -105,4 +133,17 @@ private function buildUrl(array $url, array $params = []): string
105133

106134
return$scheme.$user.$pass.$host.$port.$path.$query.$fragment;
107135
}
136+
137+
privatefunctiongetExpirationTime(\DateTimeInterface|\DateInterval|int$expiration):string
138+
{
139+
if ($expirationinstanceof \DateTimeInterface) {
140+
return$expiration->format('U');
141+
}
142+
143+
if ($expirationinstanceof \DateInterval) {
144+
return \DateTimeImmutable::createFromFormat('U',time())->add($expiration)->format('U');
145+
}
146+
147+
return (string)$expiration;
148+
}
108149
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp