Skip to content

Commit ce37402

Browse files
authored
Merge pull request #928 from driesvints/redirect-rule
[7.0] Allow multiple redirects when creating clients
2 parents 910548b + e4a24fb commit ce37402

File tree

4 files changed

+136
-15
lines changed

4 files changed

+136
-15
lines changed

src/Http/Controllers/ClientController.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Http\Request;
66
use Illuminate\Http\Response;
77
use Laravel\Passport\ClientRepository;
8+
use Laravel\Passport\Http\Rules\RedirectRule;
89
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
910

1011
class ClientController
@@ -23,18 +24,29 @@ class ClientController
2324
*/
2425
protected $validation;
2526

27+
/**
28+
* The redirect validation rule.
29+
*
30+
* @var \Laravel\Passport\Http\Rules\RedirectRule
31+
*/
32+
protected $redirectRule;
33+
2634
/**
2735
* Create a client controller instance.
2836
*
2937
* @param \Laravel\Passport\ClientRepository $clients
3038
* @param \Illuminate\Contracts\Validation\Factory $validation
39+
* @param \Laravel\Passport\Http\Rules\RedirectRule $redirectRule
3140
* @return void
3241
*/
33-
public function __construct(ClientRepository $clients,
34-
ValidationFactory $validation)
35-
{
42+
public function __construct(
43+
ClientRepository $clients,
44+
ValidationFactory $validation,
45+
RedirectRule $redirectRule
46+
) {
3647
$this->clients = $clients;
3748
$this->validation = $validation;
49+
$this->redirectRule = $redirectRule;
3850
}
3951

4052
/**
@@ -60,7 +72,7 @@ public function store(Request $request)
6072
{
6173
$this->validation->make($request->all(), [
6274
'name' => 'required|max:255',
63-
'redirect' => 'required|url',
75+
'redirect' => ['required', $this->redirectRule],
6476
])->validate();
6577

6678
return $this->clients->create(
@@ -85,7 +97,7 @@ public function update(Request $request, $clientId)
8597

8698
$this->validation->make($request->all(), [
8799
'name' => 'required|max:255',
88-
'redirect' => 'required|url',
100+
'redirect' => ['required', $this->redirectRule],
89101
])->validate();
90102

91103
return $this->clients->update(

src/Http/Rules/RedirectRule.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Laravel\Passport\Http\Rules;
4+
5+
use Illuminate\Contracts\Validation\Rule;
6+
use Illuminate\Contracts\Validation\Factory;
7+
8+
class RedirectRule implements Rule
9+
{
10+
/**
11+
* @var \Illuminate\Contracts\Validation\Factory
12+
*/
13+
private $validator;
14+
15+
public function __construct(Factory $validator)
16+
{
17+
$this->validator = $validator;
18+
}
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
public function passes($attribute, $value)
24+
{
25+
foreach (explode(',', $value) as $redirect) {
26+
$validator = $this->validator->make(['redirect' => $redirect], ['redirect' => 'url']);
27+
28+
if ($validator->fails()) {
29+
return false;
30+
}
31+
}
32+
33+
return true;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function message()
40+
{
41+
return 'One or more redirects have an invalid url format.';
42+
}
43+
}

tests/ClientControllerTest.php

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
namespace Laravel\Passport\Tests;
44

5-
use Laravel\Passport\Client;
6-
use Laravel\Passport\Http\Controllers\ClientController;
75
use Mockery as m;
86
use Illuminate\Http\Request;
7+
use Laravel\Passport\Client;
98
use PHPUnit\Framework\TestCase;
9+
use Laravel\Passport\Http\Rules\RedirectRule;
10+
use Laravel\Passport\Http\Controllers\ClientController;
1011

1112
class ClientControllerTest extends TestCase
1213
{
@@ -25,7 +26,9 @@ public function test_all_the_clients_for_the_current_user_can_be_retrieved()
2526
$request->shouldReceive('user')->andReturn(new ClientControllerFakeUser);
2627

2728
$controller = new ClientController(
28-
$clients, m::mock('Illuminate\Contracts\Validation\Factory')
29+
$clients,
30+
m::mock('Illuminate\Contracts\Validation\Factory'),
31+
m::mock(RedirectRule::class)
2932
);
3033

3134
$this->assertEquals($client, $controller->forUser($request));
@@ -45,17 +48,21 @@ public function test_clients_can_be_stored()
4548
->with(1, 'client name', 'http://localhost')
4649
->andReturn($client = new Client);
4750

51+
$redirectRule = m::mock(RedirectRule::class);
52+
4853
$validator = m::mock('Illuminate\Contracts\Validation\Factory');
4954
$validator->shouldReceive('make')->once()->with([
5055
'name' => 'client name',
5156
'redirect' => 'http://localhost',
5257
], [
5358
'name' => 'required|max:255',
54-
'redirect' => 'required|url',
59+
'redirect' => ['required', $redirectRule],
5560
])->andReturn($validator);
5661
$validator->shouldReceive('validate')->once();
5762

58-
$controller = new ClientController($clients, $validator);
63+
$controller = new ClientController(
64+
$clients, $validator, $redirectRule
65+
);
5966

6067
$this->assertEquals($client, $controller->store($request));
6168
}
@@ -79,17 +86,21 @@ public function test_clients_can_be_updated()
7986
m::type('Laravel\Passport\Client'), 'client name', 'http://localhost'
8087
)->andReturn('response');
8188

89+
$redirectRule = m::mock(RedirectRule::class);
90+
8291
$validator = m::mock('Illuminate\Contracts\Validation\Factory');
8392
$validator->shouldReceive('make')->once()->with([
8493
'name' => 'client name',
8594
'redirect' => 'http://localhost',
8695
], [
8796
'name' => 'required|max:255',
88-
'redirect' => 'required|url',
97+
'redirect' => ['required', $redirectRule],
8998
])->andReturn($validator);
9099
$validator->shouldReceive('validate')->once();
91100

92-
$controller = new ClientController($clients, $validator);
101+
$controller = new ClientController(
102+
$clients, $validator, $redirectRule
103+
);
93104

94105
$this->assertEquals('response', $controller->update($request, 1));
95106
}
@@ -112,7 +123,9 @@ public function test_404_response_if_client_doesnt_belong_to_user()
112123

113124
$validator = m::mock('Illuminate\Contracts\Validation\Factory');
114125

115-
$controller = new ClientController($clients, $validator);
126+
$controller = new ClientController(
127+
$clients, $validator, m::mock(RedirectRule::class)
128+
);
116129

117130
$this->assertEquals(404, $controller->update($request, 1)->status());
118131
}
@@ -138,7 +151,9 @@ public function test_clients_can_be_deleted()
138151

139152
$validator = m::mock('Illuminate\Contracts\Validation\Factory');
140153

141-
$controller = new ClientController($clients, $validator);
154+
$controller = new ClientController(
155+
$clients, $validator, m::mock(RedirectRule::class)
156+
);
142157

143158
$controller->destroy($request, 1);
144159
}
@@ -161,7 +176,9 @@ public function test_404_response_if_client_doesnt_belong_to_user_on_delete()
161176

162177
$validator = m::mock('Illuminate\Contracts\Validation\Factory');
163178

164-
$controller = new ClientController($clients, $validator);
179+
$controller = new ClientController(
180+
$clients, $validator, m::mock(RedirectRule::class)
181+
);
165182

166183
$this->assertEquals(404, $controller->destroy($request, 1)->status());
167184
}

tests/RedirectRuleTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Laravel\Passport\Tests;
4+
5+
use Illuminate\Contracts\Validation\Factory;
6+
use Illuminate\Contracts\Validation\Validator;
7+
use Mockery as m;
8+
use PHPUnit\Framework\TestCase;
9+
use Laravel\Passport\Http\Rules\RedirectRule;
10+
11+
class RedirectRuleTest extends TestCase
12+
{
13+
public function tearDown()
14+
{
15+
m::close();
16+
}
17+
18+
public function test_it_passes_with_a_single_valid_url()
19+
{
20+
$rule = $this->rule($fails = false);
21+
22+
$this->assertTrue($rule->passes('redirect', 'https://example.com'));
23+
}
24+
25+
public function test_it_passes_with_multiple_valid_urls()
26+
{
27+
$rule = $this->rule($fails = false);
28+
29+
$this->assertTrue($rule->passes('redirect', 'https://example.com,https://example2.com'));
30+
}
31+
32+
public function test_it_fails_with_a_single_invalid_url()
33+
{
34+
$rule = $this->rule($fails = true);
35+
36+
$this->assertFalse($rule->passes('redirect', 'https://example.com,invalid'));
37+
}
38+
39+
private function rule(bool $fails): RedirectRule
40+
{
41+
$validator = m::mock(Validator::class);
42+
$validator->shouldReceive('fails')->andReturn($fails);
43+
44+
$factory = m::mock(Factory::class);
45+
$factory->shouldReceive('make')->andReturn($validator);
46+
47+
return new RedirectRule($factory);
48+
}
49+
}

0 commit comments

Comments
 (0)