1<?php
2
3namespace Elastica\Transport;
4
5use Aws\Credentials\CredentialProvider;
6use Aws\Credentials\Credentials;
7use Aws\Signature\SignatureV4;
8use Elastica\Connection;
9use GuzzleHttp;
10use GuzzleHttp\Client;
11use GuzzleHttp\HandlerStack;
12use GuzzleHttp\Middleware;
13use Psr\Http\Message\RequestInterface;
14
15class AwsAuthV4 extends Guzzle
16{
17    protected function _getGuzzleClient(bool $persistent = true): Client
18    {
19        if (!$persistent || !self::$_guzzleClientConnection) {
20            $stack = HandlerStack::create(GuzzleHttp\choose_handler());
21            $stack->push($this->getSigningMiddleware(), 'sign');
22
23            self::$_guzzleClientConnection = new Client([
24                'handler' => $stack,
25            ]);
26        }
27
28        return self::$_guzzleClientConnection;
29    }
30
31    protected function _getBaseUrl(Connection $connection): string
32    {
33        $this->initializePortAndScheme();
34
35        return parent::_getBaseUrl($connection);
36    }
37
38    private function getSigningMiddleware()
39    {
40        $region = $this->getConnection()->hasParam('aws_region')
41            ? $this->getConnection()->getParam('aws_region')
42            : \getenv('AWS_REGION');
43        $signer = new SignatureV4('es', $region);
44        $credProvider = $this->getCredentialProvider();
45
46        return Middleware::mapRequest(function (RequestInterface $req) use (
47            $signer,
48            $credProvider
49        ) {
50            return $signer->signRequest($req, $credProvider()->wait());
51        });
52    }
53
54    private function getCredentialProvider()
55    {
56        $connection = $this->getConnection();
57        if ($connection->hasParam('aws_secret_access_key')) {
58            return CredentialProvider::fromCredentials(new Credentials(
59                $connection->getParam('aws_access_key_id'),
60                $connection->getParam('aws_secret_access_key'),
61                $connection->hasParam('aws_session_token')
62                    ? $connection->getParam('aws_session_token')
63                    : null
64            ));
65        }
66
67        return CredentialProvider::defaultProvider();
68    }
69
70    private function initializePortAndScheme()
71    {
72        $connection = $this->getConnection();
73        if (true === $this->isSslRequired($connection)) {
74            $this->_scheme = 'https';
75            $connection->setPort(443);
76        } else {
77            $this->_scheme = 'http';
78            $connection->setPort(80);
79        }
80    }
81
82    /**
83     * @param Connection $conn
84     * @param bool       $default
85     *
86     * @return bool
87     */
88    private function isSslRequired(Connection $conn, bool $default = false): bool
89    {
90        return $conn->hasParam('ssl')
91            ? (bool) $conn->getParam('ssl')
92            : $default;
93    }
94}
95