From 12125f4cc728312734865426dcab60452ca166b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20S=C3=A1gi-Kaz=C3=A1r?= Date: Fri, 4 Mar 2016 22:17:22 +0100 Subject: [PATCH] Add auto BasicAuth credential detection based on URL, closes php-http/plugins#47 --- .../Authentication/AuthenticationBehavior.php | 11 --- spec/Authentication/AutoBasicAuthSpec.php | 84 +++++++++++++++++++ spec/Authentication/BasicAuthSpec.php | 7 +- spec/Authentication/BearerSpec.php | 7 +- spec/Authentication/ChainSpec.php | 7 +- spec/Authentication/MatchingSpec.php | 13 +-- spec/Authentication/QueryParamSpec.php | 7 +- .../Authentication/RequestConditionalSpec.php | 7 +- spec/Authentication/WsseSpec.php | 7 +- src/Authentication/AutoBasicAuth.php | 48 +++++++++++ 10 files changed, 169 insertions(+), 29 deletions(-) delete mode 100644 spec/Authentication/AuthenticationBehavior.php create mode 100644 spec/Authentication/AutoBasicAuthSpec.php create mode 100644 src/Authentication/AutoBasicAuth.php diff --git a/spec/Authentication/AuthenticationBehavior.php b/spec/Authentication/AuthenticationBehavior.php deleted file mode 100644 index 6cf8632..0000000 --- a/spec/Authentication/AuthenticationBehavior.php +++ /dev/null @@ -1,11 +0,0 @@ -shouldImplement('Http\Message\Authentication'); - } -} diff --git a/spec/Authentication/AutoBasicAuthSpec.php b/spec/Authentication/AutoBasicAuthSpec.php new file mode 100644 index 0000000..33130ed --- /dev/null +++ b/spec/Authentication/AutoBasicAuthSpec.php @@ -0,0 +1,84 @@ +shouldHaveType('Http\Message\Authentication\AutoBasicAuth'); + } + + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + + function it_authenticates_a_request( + RequestInterface $request, + UriInterface $uri, + UriInterface $uriWithoutUserInfo, + RequestInterface $requestWithoutUserInfo, + RequestInterface $authenticatedRequest + ) { + $request->getUri()->willReturn($uri); + $uri->getUserInfo()->willReturn('username:password'); + $uri->withUserInfo('', null)->willReturn($uriWithoutUserInfo); + $request->withUri($uriWithoutUserInfo)->willReturn($requestWithoutUserInfo); + $requestWithoutUserInfo + ->withHeader('Authorization', 'Basic '.base64_encode('username:password')) + ->willReturn($authenticatedRequest) + ; + + $this->authenticate($request)->shouldReturn($authenticatedRequest); + } + + function it_authenticates_a_request_without_password( + RequestInterface $request, + UriInterface $uri, + UriInterface $uriWithoutUserInfo, + RequestInterface $requestWithoutUserInfo, + RequestInterface $authenticatedRequest + ) { + $request->getUri()->willReturn($uri); + $uri->getUserInfo()->willReturn('username'); + $uri->withUserInfo('', null)->willReturn($uriWithoutUserInfo); + $request->withUri($uriWithoutUserInfo)->willReturn($requestWithoutUserInfo); + $requestWithoutUserInfo + ->withHeader('Authorization', 'Basic '.base64_encode('username')) + ->willReturn($authenticatedRequest) + ; + + $this->authenticate($request)->shouldReturn($authenticatedRequest); + } + + function it_does_not_authenticate_a_request(RequestInterface $request, UriInterface $uri) + { + $request->getUri()->willReturn($uri); + $uri->getUserInfo()->willReturn(''); + + $this->authenticate($request)->shouldReturn($request); + } + + function it_authenticates_a_request_without_user_info_removal( + RequestInterface $request, + UriInterface $uri, + RequestInterface $authenticatedRequest + ) { + $this->beConstructedWith(false); + + $request->getUri()->willReturn($uri); + $uri->getUserInfo()->willReturn('username:password'); + $request + ->withHeader('Authorization', 'Basic '.base64_encode('username:password')) + ->willReturn($authenticatedRequest) + ; + + $this->authenticate($request)->shouldReturn($authenticatedRequest); + } +} diff --git a/spec/Authentication/BasicAuthSpec.php b/spec/Authentication/BasicAuthSpec.php index 55d77a4..e70d097 100644 --- a/spec/Authentication/BasicAuthSpec.php +++ b/spec/Authentication/BasicAuthSpec.php @@ -7,8 +7,6 @@ class BasicAuthSpec extends ObjectBehavior { - use AuthenticationBehavior; - function let() { $this->beConstructedWith('john.doe', 'secret'); @@ -19,6 +17,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\BasicAuth'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest) { $request->withHeader('Authorization', 'Basic '.base64_encode('john.doe:secret'))->willReturn($newRequest); diff --git a/spec/Authentication/BearerSpec.php b/spec/Authentication/BearerSpec.php index ef1e571..aaca72a 100644 --- a/spec/Authentication/BearerSpec.php +++ b/spec/Authentication/BearerSpec.php @@ -7,8 +7,6 @@ class BearerSpec extends ObjectBehavior { - use AuthenticationBehavior; - function let() { $this->beConstructedWith('token'); @@ -19,6 +17,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\Bearer'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request(RequestInterface $request, RequestInterface $newRequest) { $request->withHeader('Authorization', 'Bearer token')->willReturn($newRequest); diff --git a/spec/Authentication/ChainSpec.php b/spec/Authentication/ChainSpec.php index 9c74a94..61e752b 100644 --- a/spec/Authentication/ChainSpec.php +++ b/spec/Authentication/ChainSpec.php @@ -8,13 +8,16 @@ class ChainSpec extends ObjectBehavior { - use AuthenticationBehavior; - function it_is_initializable() { $this->shouldHaveType('Http\Message\Authentication\Chain'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_throws_an_exception_when_non_authentication_is_passed() { $this->beConstructedWith(['authentication']); diff --git a/spec/Authentication/MatchingSpec.php b/spec/Authentication/MatchingSpec.php index e717b2f..58f458b 100644 --- a/spec/Authentication/MatchingSpec.php +++ b/spec/Authentication/MatchingSpec.php @@ -8,15 +8,11 @@ class MatchingSpec extends ObjectBehavior { - use AuthenticationBehavior; - - private $matcher; - function let(Authentication $authentication) { - $this->matcher = function($request) { return true; }; + $matcher = function($request) { return true; }; - $this->beConstructedWith($authentication, $this->matcher); + $this->beConstructedWith($authentication, $matcher); } function it_is_initializable() @@ -24,6 +20,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\Matching'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request(Authentication $authentication, RequestInterface $request, RequestInterface $newRequest) { $authentication->authenticate($request)->willReturn($newRequest); diff --git a/spec/Authentication/QueryParamSpec.php b/spec/Authentication/QueryParamSpec.php index 9f4d4b2..5e8b92e 100644 --- a/spec/Authentication/QueryParamSpec.php +++ b/spec/Authentication/QueryParamSpec.php @@ -8,8 +8,6 @@ class QueryParamSpec extends ObjectBehavior { - use AuthenticationBehavior; - function let() { $this->beConstructedWith([ @@ -23,6 +21,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\QueryParam'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request( RequestInterface $request, UriInterface $uri, diff --git a/spec/Authentication/RequestConditionalSpec.php b/spec/Authentication/RequestConditionalSpec.php index 7209b7e..5946736 100644 --- a/spec/Authentication/RequestConditionalSpec.php +++ b/spec/Authentication/RequestConditionalSpec.php @@ -9,8 +9,6 @@ class RequestConditionalSpec extends ObjectBehavior { - use AuthenticationBehavior; - function let(RequestMatcher $requestMatcher, Authentication $authentication) { $this->beConstructedWith($requestMatcher, $authentication); @@ -21,6 +19,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\RequestConditional'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request( Authentication $authentication, RequestMatcher $requestMatcher, diff --git a/spec/Authentication/WsseSpec.php b/spec/Authentication/WsseSpec.php index 049764e..926e9da 100644 --- a/spec/Authentication/WsseSpec.php +++ b/spec/Authentication/WsseSpec.php @@ -8,8 +8,6 @@ class WsseSpec extends ObjectBehavior { - use AuthenticationBehavior; - function let() { $this->beConstructedWith('john.doe', 'secret'); @@ -20,6 +18,11 @@ function it_is_initializable() $this->shouldHaveType('Http\Message\Authentication\Wsse'); } + function it_is_an_authentication() + { + $this->shouldImplement('Http\Message\Authentication'); + } + function it_authenticates_a_request( RequestInterface $request, RequestInterface $newRequest, diff --git a/src/Authentication/AutoBasicAuth.php b/src/Authentication/AutoBasicAuth.php new file mode 100644 index 0000000..7b6a429 --- /dev/null +++ b/src/Authentication/AutoBasicAuth.php @@ -0,0 +1,48 @@ + + */ +final class AutoBasicAuth implements Authentication +{ + /** + * Whether user info should be removed from the URI. + * + * @var bool + */ + private $shouldRemoveUserInfo; + + /** + * @param bool|true $shouldRremoveUserInfo + */ + public function __construct($shouldRremoveUserInfo = true) + { + $this->shouldRemoveUserInfo = (bool) $shouldRremoveUserInfo; + } + + /** + * {@inheritdoc} + */ + public function authenticate(RequestInterface $request) + { + $uri = $request->getUri(); + $userInfo = $uri->getUserInfo(); + + if (!empty($userInfo)) { + if ($this->shouldRemoveUserInfo) { + $request = $request->withUri($uri->withUserInfo('')); + } + + $request = $request->withHeader('Authorization', sprintf('Basic %s', base64_encode($userInfo))); + } + + return $request; + } +}