Skip to content

Commit 4f60a0e

Browse files
committed
Add authentication
Move authentication behavior to its proper place
1 parent ab4224f commit 4f60a0e

14 files changed

+741
-0
lines changed

composer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
"Http\\Message\\": "src/"
2525
}
2626
},
27+
"autoload-dev": {
28+
"psr-4": {
29+
"spec\\Http\\Message\\": "spec/"
30+
}
31+
},
2732
"scripts": {
2833
"test": "vendor/bin/phpspec run",
2934
"test-ci": "vendor/bin/phpspec run -c phpspec.yml.ci"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
trait AuthenticationBehavior
6+
{
7+
function it_is_an_authentication()
8+
{
9+
$this->shouldImplement('Http\Message\Authentication');
10+
}
11+
}

spec/Authentication/BasicAuthSpec.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use PhpSpec\ObjectBehavior;
7+
8+
class BasicAuthSpec extends ObjectBehavior
9+
{
10+
use AuthenticationBehavior;
11+
12+
function let()
13+
{
14+
$this->beConstructedWith('john.doe', 'secret');
15+
}
16+
17+
function it_is_initializable()
18+
{
19+
$this->shouldHaveType('Http\Message\Authentication\BasicAuth');
20+
}
21+
22+
function it_has_a_username()
23+
{
24+
$this->getUsername()->shouldReturn('john.doe');
25+
}
26+
27+
function it_accepts_a_username()
28+
{
29+
$this->setUsername('jane.doe');
30+
31+
$this->getUsername()->shouldReturn('jane.doe');
32+
}
33+
34+
function it_has_a_password()
35+
{
36+
$this->getPassword()->shouldReturn('secret');
37+
}
38+
39+
function it_accepts_a_password()
40+
{
41+
$this->setPassword('very_secret');
42+
43+
$this->getPassword()->shouldReturn('very_secret');
44+
}
45+
46+
function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest)
47+
{
48+
$request->withHeader('Authorization', 'Basic '.base64_encode('john.doe:secret'))->willReturn($newRequest);
49+
50+
$this->authenticate($request)->shouldReturn($newRequest);
51+
}
52+
}

spec/Authentication/BearerSpec.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use PhpSpec\ObjectBehavior;
7+
8+
class BearerSpec extends ObjectBehavior
9+
{
10+
use AuthenticationBehavior;
11+
12+
function let()
13+
{
14+
$this->beConstructedWith('token');
15+
}
16+
17+
function it_is_initializable()
18+
{
19+
$this->shouldHaveType('Http\Message\Authentication\Bearer');
20+
}
21+
22+
function it_has_a_token()
23+
{
24+
$this->getToken()->shouldReturn('token');
25+
}
26+
27+
function it_accepts_a_token()
28+
{
29+
$this->setToken('another_token');
30+
31+
$this->getToken()->shouldReturn('another_token');
32+
}
33+
34+
function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest)
35+
{
36+
$request->withHeader('Authorization', 'Bearer token')->willReturn($newRequest);
37+
38+
$this->authenticate($request)->shouldReturn($newRequest);
39+
}
40+
}

spec/Authentication/ChainSpec.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
use Http\Message\Authentication;
6+
use Psr\Http\Message\RequestInterface;
7+
use PhpSpec\ObjectBehavior;
8+
9+
class ChainSpec extends ObjectBehavior
10+
{
11+
use AuthenticationBehavior;
12+
13+
function it_is_initializable()
14+
{
15+
$this->shouldHaveType('Http\Message\Authentication\Chain');
16+
}
17+
18+
function it_accepts_an_authentication_chain_in_the_constructor(Authentication $auth1, Authentication $auth2)
19+
{
20+
$chain = [$auth1, $auth2];
21+
22+
$this->beConstructedWith($chain);
23+
24+
$this->getAuthenticationChain()->shouldReturn($chain);
25+
}
26+
27+
function it_sets_the_authentication_chain(Authentication $auth1, Authentication $auth2)
28+
{
29+
// This SHOULD be replaced
30+
$this->beConstructedWith([$auth1]);
31+
32+
$this->setAuthenticationChain([$auth2]);
33+
34+
$this->getAuthenticationChain()->shouldReturn([$auth2]);
35+
}
36+
37+
function it_adds_an_authentication_method(Authentication $auth1, Authentication $auth2)
38+
{
39+
// This SHOULD NOT be replaced
40+
$this->beConstructedWith([$auth1]);
41+
42+
$this->addAuthentication($auth2);
43+
44+
$this->getAuthenticationChain()->shouldReturn([$auth1, $auth2]);
45+
}
46+
47+
function it_clears_the_authentication_chain(Authentication $auth1, Authentication $auth2)
48+
{
49+
// This SHOULD be replaced
50+
$this->beConstructedWith([$auth1]);
51+
52+
$this->clearAuthenticationChain();
53+
54+
$this->addAuthentication($auth2);
55+
56+
$this->getAuthenticationChain()->shouldReturn([$auth2]);
57+
}
58+
59+
function it_authenticates_a_request(
60+
Authentication $auth1,
61+
Authentication $auth2,
62+
RequestInterface $originalRequest,
63+
RequestInterface $request1,
64+
RequestInterface $request2
65+
) {
66+
$originalRequest->withHeader('AuthMethod1', 'AuthValue')->willReturn($request1);
67+
$request1->withHeader('AuthMethod2', 'AuthValue')->willReturn($request2);
68+
69+
$auth1->authenticate($originalRequest)->will(function ($args) {
70+
return $args[0]->withHeader('AuthMethod1', 'AuthValue');
71+
});
72+
73+
$auth2->authenticate($request1)->will(function ($args) {
74+
return $args[0]->withHeader('AuthMethod2', 'AuthValue');
75+
});
76+
77+
$this->beConstructedWith([$auth1, $auth2]);
78+
79+
$this->authenticate($originalRequest)->shouldReturn($request2);
80+
}
81+
}

spec/Authentication/MatchingSpec.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
use Http\Message\Authentication;
6+
use Psr\Http\Message\RequestInterface;
7+
use PhpSpec\ObjectBehavior;
8+
9+
class MatchingSpec extends ObjectBehavior
10+
{
11+
use AuthenticationBehavior;
12+
13+
private $matcher;
14+
15+
function let(Authentication $authentication)
16+
{
17+
$this->matcher = function($request) { return true; };
18+
19+
$this->beConstructedWith($authentication, $this->matcher);
20+
}
21+
22+
function it_is_initializable()
23+
{
24+
$this->shouldHaveType('Http\Message\Authentication\Matching');
25+
}
26+
27+
function it_has_an_authentication(Authentication $authentication)
28+
{
29+
$this->getAuthentication()->shouldReturn($authentication);
30+
}
31+
32+
function it_accepts_an_authentication(Authentication $anotherAuthentication)
33+
{
34+
$this->setAuthentication($anotherAuthentication);
35+
36+
$this->getAuthentication()->shouldReturn($anotherAuthentication);
37+
}
38+
39+
function it_has_a_matcher()
40+
{
41+
$this->getMatcher()->shouldReturn($this->matcher);
42+
}
43+
44+
function it_accepts_a_matcher()
45+
{
46+
$matcher = function($request) { return false; };
47+
48+
$this->setMatcher($matcher);
49+
50+
$this->getMatcher()->shouldReturn($matcher);
51+
}
52+
53+
function it_authenticates_a_request(Authentication $authentication, RequestInterface $request, RequestInterface $newRequest)
54+
{
55+
$authentication->authenticate($request)->willReturn($newRequest);
56+
57+
$this->authenticate($request)->shouldReturn($newRequest);
58+
}
59+
60+
function it_does_not_authenticate_a_request(Authentication $authentication, RequestInterface $request)
61+
{
62+
$matcher = function($request) { return false; };
63+
64+
$this->setMatcher($matcher);
65+
66+
$authentication->authenticate($request)->shouldNotBeCalled();
67+
68+
$this->authenticate($request)->shouldReturn($request);
69+
}
70+
71+
function it_creates_a_matcher_from_url(Authentication $authentication)
72+
{
73+
$this->createUrlMatcher($authentication, 'url')->shouldHaveType('Http\Message\Authentication\Matching');
74+
}
75+
}

spec/Authentication/WsseSpec.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace spec\Http\Message\Authentication;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use PhpSpec\ObjectBehavior;
7+
use Prophecy\Argument;
8+
9+
class WsseSpec extends ObjectBehavior
10+
{
11+
use AuthenticationBehavior;
12+
13+
function let()
14+
{
15+
$this->beConstructedWith('john.doe', 'secret');
16+
}
17+
18+
function it_is_initializable()
19+
{
20+
$this->shouldHaveType('Http\Message\Authentication\Wsse');
21+
}
22+
23+
function it_has_a_username()
24+
{
25+
$this->getUsername()->shouldReturn('john.doe');
26+
}
27+
28+
function it_accepts_a_username()
29+
{
30+
$this->setUsername('jane.doe');
31+
32+
$this->getUsername()->shouldReturn('jane.doe');
33+
}
34+
35+
function it_has_a_password()
36+
{
37+
$this->getPassword()->shouldReturn('secret');
38+
}
39+
40+
function it_accepts_a_password()
41+
{
42+
$this->setPassword('very_secret');
43+
44+
$this->getPassword()->shouldReturn('very_secret');
45+
}
46+
47+
function it_authenticates_a_request(
48+
RequestInterface $request,
49+
RequestInterface $newRequest,
50+
RequestInterface $newerRequest
51+
) {
52+
$request->withHeader('Authorization', 'WSSE profile="UsernameToken"')->willReturn($newRequest);
53+
$newRequest->withHeader('X-WSSE', Argument::that(function($arg) {
54+
return preg_match('/UsernameToken Username=".*", PasswordDigest=".*", Nonce=".*", Created=".*"/', $arg);
55+
}))->willReturn($newerRequest);
56+
57+
$this->authenticate($request)->shouldReturn($newerRequest);
58+
}
59+
}

src/Authentication.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Http\Message;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
7+
/**
8+
* Authenticate a PSR-7 Request.
9+
*
10+
* @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
11+
*/
12+
interface Authentication
13+
{
14+
/**
15+
* Authenticates a request.
16+
*
17+
* @param RequestInterface $request
18+
*
19+
* @return RequestInterface
20+
*/
21+
public function authenticate(RequestInterface $request);
22+
}

src/Authentication/BasicAuth.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Http\Message\Authentication;
4+
5+
use Http\Message\Authentication;
6+
use Psr\Http\Message\RequestInterface;
7+
8+
/**
9+
* Authenticate a PSR-7 Request using Basic Auth.
10+
*
11+
* @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
12+
*/
13+
final class BasicAuth implements Authentication
14+
{
15+
use UserPasswordPair;
16+
17+
/**
18+
* @param string $username
19+
* @param string $password
20+
*/
21+
public function __construct($username, $password)
22+
{
23+
$this->username = $username;
24+
$this->password = $password;
25+
}
26+
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public function authenticate(RequestInterface $request)
31+
{
32+
$header = sprintf('Basic %s', base64_encode(sprintf('%s:%s', $this->username, $this->password)));
33+
34+
return $request->withHeader('Authorization', $header);
35+
}
36+
}

0 commit comments

Comments
 (0)