Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authentication #3

Merged
merged 1 commit into from
Dec 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"Http\\Message\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"spec\\Http\\Message\\": "spec/"
}
},
"scripts": {
"test": "vendor/bin/phpspec run",
"test-ci": "vendor/bin/phpspec run -c phpspec.yml.ci"
Expand Down
11 changes: 11 additions & 0 deletions spec/Authentication/AuthenticationBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace spec\Http\Message\Authentication;

trait AuthenticationBehavior
{
function it_is_an_authentication()
{
$this->shouldImplement('Http\Message\Authentication');
}
}
52 changes: 52 additions & 0 deletions spec/Authentication/BasicAuthSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace spec\Http\Message\Authentication;

use Psr\Http\Message\RequestInterface;
use PhpSpec\ObjectBehavior;

class BasicAuthSpec extends ObjectBehavior
{
use AuthenticationBehavior;

function let()
{
$this->beConstructedWith('john.doe', 'secret');
}

function it_is_initializable()
{
$this->shouldHaveType('Http\Message\Authentication\BasicAuth');
}

function it_has_a_username()
{
$this->getUsername()->shouldReturn('john.doe');
}

function it_accepts_a_username()
{
$this->setUsername('jane.doe');

$this->getUsername()->shouldReturn('jane.doe');
}

function it_has_a_password()
{
$this->getPassword()->shouldReturn('secret');
}

function it_accepts_a_password()
{
$this->setPassword('very_secret');

$this->getPassword()->shouldReturn('very_secret');
}

function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest)
{
$request->withHeader('Authorization', 'Basic '.base64_encode('john.doe:secret'))->willReturn($newRequest);

$this->authenticate($request)->shouldReturn($newRequest);
}
}
40 changes: 40 additions & 0 deletions spec/Authentication/BearerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace spec\Http\Message\Authentication;

use Psr\Http\Message\RequestInterface;
use PhpSpec\ObjectBehavior;

class BearerSpec extends ObjectBehavior
{
use AuthenticationBehavior;

function let()
{
$this->beConstructedWith('token');
}

function it_is_initializable()
{
$this->shouldHaveType('Http\Message\Authentication\Bearer');
}

function it_has_a_token()
{
$this->getToken()->shouldReturn('token');
}

function it_accepts_a_token()
{
$this->setToken('another_token');

$this->getToken()->shouldReturn('another_token');
}

function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest)
{
$request->withHeader('Authorization', 'Bearer token')->willReturn($newRequest);

$this->authenticate($request)->shouldReturn($newRequest);
}
}
81 changes: 81 additions & 0 deletions spec/Authentication/ChainSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace spec\Http\Message\Authentication;

use Http\Message\Authentication;
use Psr\Http\Message\RequestInterface;
use PhpSpec\ObjectBehavior;

class ChainSpec extends ObjectBehavior
{
use AuthenticationBehavior;

function it_is_initializable()
{
$this->shouldHaveType('Http\Message\Authentication\Chain');
}

function it_accepts_an_authentication_chain_in_the_constructor(Authentication $auth1, Authentication $auth2)
{
$chain = [$auth1, $auth2];

$this->beConstructedWith($chain);

$this->getAuthenticationChain()->shouldReturn($chain);
}

function it_sets_the_authentication_chain(Authentication $auth1, Authentication $auth2)
{
// This SHOULD be replaced
$this->beConstructedWith([$auth1]);

$this->setAuthenticationChain([$auth2]);

$this->getAuthenticationChain()->shouldReturn([$auth2]);
}

function it_adds_an_authentication_method(Authentication $auth1, Authentication $auth2)
{
// This SHOULD NOT be replaced
$this->beConstructedWith([$auth1]);

$this->addAuthentication($auth2);

$this->getAuthenticationChain()->shouldReturn([$auth1, $auth2]);
}

function it_clears_the_authentication_chain(Authentication $auth1, Authentication $auth2)
{
// This SHOULD be replaced
$this->beConstructedWith([$auth1]);

$this->clearAuthenticationChain();

$this->addAuthentication($auth2);

$this->getAuthenticationChain()->shouldReturn([$auth2]);
}

function it_authenticates_a_request(
Authentication $auth1,
Authentication $auth2,
RequestInterface $originalRequest,
RequestInterface $request1,
RequestInterface $request2
) {
$originalRequest->withHeader('AuthMethod1', 'AuthValue')->willReturn($request1);
$request1->withHeader('AuthMethod2', 'AuthValue')->willReturn($request2);

$auth1->authenticate($originalRequest)->will(function ($args) {
return $args[0]->withHeader('AuthMethod1', 'AuthValue');
});

$auth2->authenticate($request1)->will(function ($args) {
return $args[0]->withHeader('AuthMethod2', 'AuthValue');
});

$this->beConstructedWith([$auth1, $auth2]);

$this->authenticate($originalRequest)->shouldReturn($request2);
}
}
75 changes: 75 additions & 0 deletions spec/Authentication/MatchingSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace spec\Http\Message\Authentication;

use Http\Message\Authentication;
use Psr\Http\Message\RequestInterface;
use PhpSpec\ObjectBehavior;

class MatchingSpec extends ObjectBehavior
{
use AuthenticationBehavior;

private $matcher;

function let(Authentication $authentication)
{
$this->matcher = function($request) { return true; };

$this->beConstructedWith($authentication, $this->matcher);
}

function it_is_initializable()
{
$this->shouldHaveType('Http\Message\Authentication\Matching');
}

function it_has_an_authentication(Authentication $authentication)
{
$this->getAuthentication()->shouldReturn($authentication);
}

function it_accepts_an_authentication(Authentication $anotherAuthentication)
{
$this->setAuthentication($anotherAuthentication);

$this->getAuthentication()->shouldReturn($anotherAuthentication);
}

function it_has_a_matcher()
{
$this->getMatcher()->shouldReturn($this->matcher);
}

function it_accepts_a_matcher()
{
$matcher = function($request) { return false; };

$this->setMatcher($matcher);

$this->getMatcher()->shouldReturn($matcher);
}

function it_authenticates_a_request(Authentication $authentication, RequestInterface $request, RequestInterface $newRequest)
{
$authentication->authenticate($request)->willReturn($newRequest);

$this->authenticate($request)->shouldReturn($newRequest);
}

function it_does_not_authenticate_a_request(Authentication $authentication, RequestInterface $request)
{
$matcher = function($request) { return false; };

$this->setMatcher($matcher);

$authentication->authenticate($request)->shouldNotBeCalled();

$this->authenticate($request)->shouldReturn($request);
}

function it_creates_a_matcher_from_url(Authentication $authentication)
{
$this->createUrlMatcher($authentication, 'url')->shouldHaveType('Http\Message\Authentication\Matching');
}
}
59 changes: 59 additions & 0 deletions spec/Authentication/WsseSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace spec\Http\Message\Authentication;

use Psr\Http\Message\RequestInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class WsseSpec extends ObjectBehavior
{
use AuthenticationBehavior;

function let()
{
$this->beConstructedWith('john.doe', 'secret');
}

function it_is_initializable()
{
$this->shouldHaveType('Http\Message\Authentication\Wsse');
}

function it_has_a_username()
{
$this->getUsername()->shouldReturn('john.doe');
}

function it_accepts_a_username()
{
$this->setUsername('jane.doe');

$this->getUsername()->shouldReturn('jane.doe');
}

function it_has_a_password()
{
$this->getPassword()->shouldReturn('secret');
}

function it_accepts_a_password()
{
$this->setPassword('very_secret');

$this->getPassword()->shouldReturn('very_secret');
}

function it_authenticates_a_request(
RequestInterface $request,
RequestInterface $newRequest,
RequestInterface $newerRequest
) {
$request->withHeader('Authorization', 'WSSE profile="UsernameToken"')->willReturn($newRequest);
$newRequest->withHeader('X-WSSE', Argument::that(function($arg) {
return preg_match('/UsernameToken Username=".*", PasswordDigest=".*", Nonce=".*", Created=".*"/', $arg);
}))->willReturn($newerRequest);

$this->authenticate($request)->shouldReturn($newerRequest);
}
}
22 changes: 22 additions & 0 deletions src/Authentication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Http\Message;

use Psr\Http\Message\RequestInterface;

/**
* Authenticate a PSR-7 Request.
*
* @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
*/
interface Authentication
{
/**
* Authenticates a request.
*
* @param RequestInterface $request
*
* @return RequestInterface
*/
public function authenticate(RequestInterface $request);
}
36 changes: 36 additions & 0 deletions src/Authentication/BasicAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Http\Message\Authentication;

use Http\Message\Authentication;
use Psr\Http\Message\RequestInterface;

/**
* Authenticate a PSR-7 Request using Basic Auth.
*
* @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
*/
final class BasicAuth implements Authentication
{
use UserPasswordPair;

/**
* @param string $username
* @param string $password
*/
public function __construct($username, $password)
{
$this->username = $username;
$this->password = $password;
}

/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$header = sprintf('Basic %s', base64_encode(sprintf('%s:%s', $this->username, $this->password)));

return $request->withHeader('Authorization', $header);
}
}