From d58549472ca1c0a11453edf569c22b08fface0d7 Mon Sep 17 00:00:00 2001 From: Adrien ERAUD Date: Tue, 18 Feb 2025 11:49:46 +0100 Subject: [PATCH] Use Graby's http headers configuration for the authentication request --- src/SiteConfig/GrabySiteConfigBuilder.php | 1 + src/SiteConfig/LoginFormAuthenticator.php | 16 ++++- src/SiteConfig/SiteConfig.php | 19 ++++++ .../SiteConfig/LoginFormAuthenticatorTest.php | 58 +++++++++++++++++++ tests/SiteConfig/SiteConfigTest.php | 3 + 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/SiteConfig/GrabySiteConfigBuilder.php b/src/SiteConfig/GrabySiteConfigBuilder.php index 5c501f92c..dfe433408 100644 --- a/src/SiteConfig/GrabySiteConfigBuilder.php +++ b/src/SiteConfig/GrabySiteConfigBuilder.php @@ -85,6 +85,7 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder 'notLoggedInXpath' => $config->not_logged_in_xpath ?: null, 'username' => $credentials['username'], 'password' => $credentials['password'], + 'httpHeaders' => $config->http_header, ]; $config = new SiteConfig($parameters); diff --git a/src/SiteConfig/LoginFormAuthenticator.php b/src/SiteConfig/LoginFormAuthenticator.php index 393d3d8cf..6a6eff8f1 100644 --- a/src/SiteConfig/LoginFormAuthenticator.php +++ b/src/SiteConfig/LoginFormAuthenticator.php @@ -30,7 +30,7 @@ class LoginFormAuthenticator $siteConfig->getPasswordField() => $siteConfig->getPassword(), ] + $this->getExtraFields($siteConfig); - $this->browser->request('POST', $siteConfig->getLoginUri(), $postFields); + $this->browser->request('POST', $siteConfig->getLoginUri(), $postFields, [], $this->getHttpHeaders($siteConfig)); return $this; } @@ -73,6 +73,20 @@ class LoginFormAuthenticator return \count($loggedIn) > 0; } + /** + * Processes http_header(*) config, prepending HTTP_ string to the header's name. + * See : https://github.com/symfony/browser-kit/blob/5.4/AbstractBrowser.php#L349. + */ + protected function getHttpHeaders(SiteConfig $siteConfig): array + { + $headers = []; + foreach ($siteConfig->getHttpHeaders() as $headerName => $headerValue) { + $headers["HTTP_$headerName"] = $headerValue; + } + + return $headers; + } + /** * Returns extra fields from the configuration. * Evaluates any field value that is an expression language string. diff --git a/src/SiteConfig/SiteConfig.php b/src/SiteConfig/SiteConfig.php index 4e6c8912e..f2254291e 100644 --- a/src/SiteConfig/SiteConfig.php +++ b/src/SiteConfig/SiteConfig.php @@ -70,6 +70,13 @@ class SiteConfig */ protected $password; + /** + * Associative array of HTTP headers to send with the form. + * + * @var array + */ + protected $httpHeaders = []; + /** * SiteConfig constructor. Sets the properties by name given a hash. * @@ -260,4 +267,16 @@ class SiteConfig return $this; } + + public function getHttpHeaders(): array + { + return $this->httpHeaders; + } + + public function setHttpHeaders(array $httpHeaders): self + { + $this->httpHeaders = $httpHeaders; + + return $this; + } } diff --git a/tests/SiteConfig/LoginFormAuthenticatorTest.php b/tests/SiteConfig/LoginFormAuthenticatorTest.php index d7e1725ce..6b87cd605 100644 --- a/tests/SiteConfig/LoginFormAuthenticatorTest.php +++ b/tests/SiteConfig/LoginFormAuthenticatorTest.php @@ -183,4 +183,62 @@ class LoginFormAuthenticatorTest extends TestCase $this->assertTrue($loginRequired); } + + public function testLoginPostWithUserAgentHeaderWithData() + { + $siteConfig = new SiteConfig([ + 'host' => 'nextinpact.com', + 'loginUri' => 'https://compte.nextinpact.com/Account/Login', + 'usernameField' => 'UserName', + 'passwordField' => 'Password', + 'username' => 'johndoe', + 'password' => 'unkn0wn', + 'httpHeaders' => [ + 'user-agent' => 'Wallabag (Guzzle/5)', + ], + ]); + + $browserResponse = new MockResponse('', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]); + $browserClient = new MockHttpClient([$browserResponse]); + $browser = $this->getMockBuilder(HttpBrowser::class) + ->setConstructorArgs([$browserClient]) + ->getMock(); + $browser->expects($this->any()) + ->method('request') + ->with( + $this->equalTo('POST'), + $this->equalTo('https://compte.nextinpact.com/Account/Login'), + $this->equalTo([ + 'UserName' => 'johndoe', + 'Password' => 'unkn0wn', + ]), + $this->equalTo([]), + $this->equalTo([ + 'HTTP_user-agent' => 'Wallabag (Guzzle/5)', + ]), + ) + ; + + $requestHtmlFunctionResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $requestHtmlFunctionResponse->expects($this->any()) + ->method('getContent') + ->willReturn(file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html')) + ; + $requestHtmlFunctionClient = $this->getMockBuilder(HttpClientInterface::class)->getMock(); + $requestHtmlFunctionClient->expects($this->any()) + ->method('request') + ->with( + $this->equalTo('GET'), + $this->equalTo('https://nextinpact.com/'), + ) + ->willReturn($requestHtmlFunctionResponse) + ; + $authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient); + + $auth = new LoginFormAuthenticator($browser, $authenticatorProvider); + + $res = $auth->login($siteConfig); + + $this->assertInstanceOf(LoginFormAuthenticator::class, $res); + } } diff --git a/tests/SiteConfig/SiteConfigTest.php b/tests/SiteConfig/SiteConfigTest.php index 7a887ff01..af4496ba7 100644 --- a/tests/SiteConfig/SiteConfigTest.php +++ b/tests/SiteConfig/SiteConfigTest.php @@ -37,6 +37,9 @@ class SiteConfigTest extends TestCase ], 'username' => 'johndoe', 'password' => 'unkn0wn', + 'httpHeaders' => [ + 'user-agent' => 'Wallabag (Guzzle/5)', + ], ]); $this->assertInstanceOf(SiteConfig::class, $config);