Issues (3627)

Auth/Provider/Oauth2ThreeLegged/HttpFactory.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * @copyright   2019 Mautic Contributors. All rights reserved
7
 * @author      Mautic
8
 *
9
 * @link        http://mautic.org
10
 *
11
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged;
15
16
use GuzzleHttp\Client;
17
use GuzzleHttp\ClientInterface;
18
use GuzzleHttp\HandlerStack;
19
use kamermans\OAuth2\GrantType\AuthorizationCode;
20
use kamermans\OAuth2\GrantType\RefreshToken;
21
use kamermans\OAuth2\OAuth2Middleware;
22
use Mautic\IntegrationsBundle\Auth\Provider\AuthConfigInterface;
23
use Mautic\IntegrationsBundle\Auth\Provider\AuthCredentialsInterface;
24
use Mautic\IntegrationsBundle\Auth\Provider\AuthProviderInterface;
25
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\CodeInterface;
26
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\CredentialsInterface;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Mautic\IntegrationsBundl...ed\CredentialsInterface. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
27
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\RedirectUriInterface;
28
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\ScopeInterface;
29
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigCredentialsSignerInterface;
30
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenFactoryInterface;
31
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenPersistenceInterface;
32
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenSignerInterface;
33
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
34
35
/**
36
 * Factory for building HTTP clients that will sign the requests with Oauth2 headers.
37
 * Based on Guzzle OAuth 2.0 Subscriber - kamermans/guzzle-oauth2-subscriber package.
38
 *
39
 * @see https://github.com/kamermans/guzzle-oauth2-subscriber
40
 */
41
class HttpFactory implements AuthProviderInterface
42
{
43
    public const NAME = 'oauth2_three_legged';
44
45
    /**
46
     * @var CredentialsInterface
47
     */
48
    private $credentials;
49
50
    /**
51
     * @var ConfigCredentialsSignerInterface|ConfigTokenPersistenceInterface|ConfigTokenSignerInterface|ConfigTokenFactoryInterface
52
     */
53
    private $config;
54
55
    /**
56
     * @var Client
57
     */
58
    private $reAuthClient;
59
60
    /**
61
     * Cache of initialized clients.
62
     *
63
     * @var Client[]
64
     */
65
    private $initializedClients = [];
66
67
    public function getAuthType(): string
68
    {
69
        return self::NAME;
70
    }
71
72
    /**
73
     * @param AuthCredentialsInterface|CredentialsInterface                                                                   $credentials
74
     * @param ConfigCredentialsSignerInterface|ConfigTokenPersistenceInterface|ConfigTokenSignerInterface|AuthConfigInterface $config
75
     *
76
     * @throws PluginNotConfiguredException
77
     */
78
    public function getClient(AuthCredentialsInterface $credentials, ?AuthConfigInterface $config = null): ClientInterface
79
    {
80
        if (!$this->credentialsAreConfigured($credentials)) {
81
            throw new PluginNotConfiguredException('Missing credentials');
82
        }
83
84
        // Return cached initialized client if there is one.
85
        if (!empty($this->initializedClients[$credentials->getClientId()])) {
86
            return $this->initializedClients[$credentials->getClientId()];
87
        }
88
89
        $this->credentials = $credentials;
90
        $this->config      = $config;
91
92
        $this->initializedClients[$credentials->getClientId()] = new Client(
93
            [
94
                'handler' => $this->getStackHandler(),
95
                'auth'    => 'oauth',
96
            ]
97
        );
98
99
        return $this->initializedClients[$credentials->getClientId()];
100
    }
101
102
    protected function credentialsAreConfigured(CredentialsInterface $credentials): bool
103
    {
104
        if (empty($credentials->getAuthorizationUrl())) {
105
            return false;
106
        }
107
108
        if (empty($credentials->getTokenUrl())) {
109
            return false;
110
        }
111
112
        if (empty($credentials->getClientId())) {
113
            return false;
114
        }
115
116
        if (empty($credentials->getClientSecret())) {
117
            return false;
118
        }
119
120
        return true;
121
    }
122
123
    private function getStackHandler(): HandlerStack
124
    {
125
        $reAuthConfig          = $this->getReAuthConfig();
126
        $grantType             = new AuthorizationCode($this->getReAuthClient(), $reAuthConfig);
127
        $refreshTokenGrantType = new RefreshToken($this->getReAuthClient(), $reAuthConfig);
128
        $middleware            = new OAuth2Middleware($grantType, $refreshTokenGrantType);
129
130
        $this->configureMiddleware($middleware);
131
132
        $stack = HandlerStack::create();
133
        $stack->push($middleware);
134
135
        return $stack;
136
    }
137
138
    private function getReAuthClient(): ClientInterface
139
    {
140
        if ($this->reAuthClient) {
141
            return $this->reAuthClient;
142
        }
143
144
        $this->reAuthClient = new Client(
145
            [
146
                'base_uri' => $this->credentials->getTokenUrl(),
147
            ]
148
        );
149
150
        return $this->reAuthClient;
151
    }
152
153
    private function getReAuthConfig(): array
154
    {
155
        $config = [
156
            'client_id'     => $this->credentials->getClientId(),
157
            'client_secret' => $this->credentials->getClientSecret(),
158
            'code'          => '',
159
        ];
160
161
        if ($this->credentials instanceof ScopeInterface) {
162
            $config['scope']  = $this->credentials->getScope();
163
        }
164
165
        if ($this->credentials instanceof RedirectUriInterface) {
166
            $config['redirect_uri']  = $this->credentials->getRedirectUri();
167
        }
168
169
        if ($this->credentials instanceof CodeInterface) {
170
            $config['code'] = $this->credentials->getCode();
171
        }
172
173
        return $config;
174
    }
175
176
    private function configureMiddleware(OAuth2Middleware $oauth): void
177
    {
178
        if (!$this->config) {
179
            return;
180
        }
181
182
        if ($this->config instanceof ConfigCredentialsSignerInterface) {
183
            $oauth->setClientCredentialsSigner($this->config->getCredentialsSigner());
184
        }
185
186
        if ($this->config instanceof ConfigTokenPersistenceInterface) {
187
            $oauth->setTokenPersistence($this->config->getTokenPersistence());
188
        }
189
190
        if ($this->config instanceof ConfigTokenSignerInterface) {
191
            $oauth->setAccessTokenSigner($this->config->getTokenSigner());
192
        }
193
194
        if ($this->config instanceof ConfigTokenFactoryInterface) {
195
            $oauth->setTokenFactory($this->config->getTokenFactory());
196
        }
197
    }
198
}
199