Passed
Pull Request — master (#58)
by
unknown
01:43
created

createApiGatewayClientCredentials()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 4
dl 0
loc 25
rs 9.7666
c 0
b 0
f 0
1
<?php
2
namespace TraderInteractive\Api;
3
4
use TraderInteractive\Util;
5
use TraderInteractive\Util\Arrays;
6
use TraderInteractive\Util\Http;
7
use GuzzleHttp\Psr7\Request;
8
use Psr\Http\Message\RequestInterface;
9
use Psr\Http\Message\ResponseInterface;
10
11
/**
12
 * Layer for OAuth2 Authentication
13
 */
14
final class Authentication
15
{
16
    /**
17
     * Function to create a Request object for obtaining a new token from the API
18
     *
19
     * @var callable
20
     */
21
    private $getTokenRequestFunc;
22
23
    /**
24
     * Private constructor to safeguard undeclared functions
25
     *
26
     * @param callable $getTokenRequestFunc Function to create a Request object for obtaining a new token from the API
27
     */
28
    private function __construct(callable $getTokenRequestFunc)
29
    {
30
        $this->getTokenRequestFunc = $getTokenRequestFunc;
31
    }
32
33
    /**
34
     * Creates a new instance of Authentication for Client Credentials grant type
35
     *
36
     * @param string $clientId        The oauth client id
37
     * @param string $clientSecret    The oauth client secret
38
     * @param string $refreshResource The refresh token resource of the API Only needed since apigee doesnt use the
39
     *                                token resource that is in the oauth2 spec
40
     * @param string $tokenResource   The access token resource of the API
41
     *
42
     * @return Authentication
43
     */
44
    public static function createClientCredentials(
45
        string $clientId,
46
        string $clientSecret,
47
        string $refreshResource = 'token',
48
        string $tokenResource = 'token'
49
    ) : Authentication {
50
        $getTokenRequestFunc = function (
51
            string $baseUrl,
52
            string $refreshToken = null
53
        ) use (
54
            $clientId,
55
            $clientSecret,
56
            $refreshResource,
57
            $tokenResource
58
        ) {
59
            if ($refreshToken !== null) {
60
                return self::getRefreshTokenRequest(
61
                    $baseUrl,
62
                    $clientId,
63
                    $clientSecret,
64
                    $refreshResource,
65
                    $refreshToken
66
                );
67
            }
68
69
            $data = ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => 'client_credentials'];
70
            return new Request(
71
                'POST',
72
                "{$baseUrl}/{$tokenResource}",
73
                ['Content-Type' => 'application/x-www-form-urlencoded'],
74
                Http::buildQueryString($data)
75
            );
76
        };
77
78
        return new self($getTokenRequestFunc);
79
    }
80
81
    /**
82
     * Creates a new instance of Authentication for Client Credentials grant type
83
     *
84
     * @param string $clientId        The oauth client id
85
     * @param string $clientSecret    The oauth client secret
86
     * @param string $authUrl         The oauth auth url
87
     * @param string $tokenResource   The access token resource of the API
88
     *
89
     * @return Authentication
90
     */
91
    public static function createApiGatewayClientCredentials(
92
        string $clientId,
93
        string $clientSecret,
94
        string $authUrl,
95
        string $tokenResource = 'token'
96
    ) : Authentication {
97
        $getTokenRequestFunc = function (
98
            string $unusedBaseUrl,
0 ignored issues
show
Unused Code introduced by
The parameter $unusedBaseUrl is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

98
            /** @scrutinizer ignore-unused */ string $unusedBaseUrl,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
99
            string $unusedRefreshToken = null
0 ignored issues
show
Unused Code introduced by
The parameter $unusedRefreshToken is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

99
            /** @scrutinizer ignore-unused */ string $unusedRefreshToken = null

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
100
        ) use (
101
            $clientId,
102
            $clientSecret,
103
            $authUrl,
104
            $tokenResource
105
        ) {
106
            $data = ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => 'client_credentials'];
107
            return new Request(
108
                'POST',
109
                "{$authUrl}/oauth2/{$tokenResource}",
110
                ['Content-Type' => 'application/x-www-form-urlencoded'],
111
                Http::buildQueryString($data)
112
            );
113
        };
114
115
        return new self($getTokenRequestFunc);
116
    }
117
118
    /**
119
     * Creates a new instance of Authentication for Owner Credentials grant type
120
     *
121
     * @param string $clientId        The oauth client id
122
     * @param string $clientSecret    The oauth client secret
123
     * @param string $username        The oauth username
124
     * @param string $password        The oauth password
125
     * @param string $refreshResource The refresh token resource of the API. Only needed since apigee doesnt use the
126
     *                                token resource that is in the oauth2 spec
127
     * @param string $tokenResource   The access token resource of the API
128
     *
129
     * @return Authentication
130
     */
131
    public static function createOwnerCredentials(
132
        string $clientId,
133
        string $clientSecret,
134
        string $username,
135
        string $password,
136
        string $refreshResource = 'token',
137
        string $tokenResource = 'token'
138
    ) : Authentication {
139
        $getTokenRequestFunc = function (
140
            string $baseUrl,
141
            string $refreshToken = null
142
        ) use (
143
            $clientId,
144
            $clientSecret,
145
            $username,
146
            $password,
147
            $refreshResource,
148
            $tokenResource
149
        ) {
150
            if ($refreshToken !== null) {
151
                return self::getRefreshTokenRequest(
152
                    $baseUrl,
153
                    $clientId,
154
                    $clientSecret,
155
                    $refreshResource,
156
                    $refreshToken
157
                );
158
            }
159
160
            $data = [
161
                'client_id' => $clientId,
162
                'client_secret' => $clientSecret,
163
                'username' => $username,
164
                'password' => $password,
165
                'grant_type' => 'password',
166
            ];
167
            return new Request(
168
                'POST',
169
                "{$baseUrl}/{$tokenResource}",
170
                ['Content-Type' => 'application/x-www-form-urlencoded'],
171
                Http::buildQueryString($data)
172
            );
173
        };
174
175
        return new self($getTokenRequestFunc);
176
    }
177
178
    /**
179
     * Extracts an access token from the given API response
180
     *
181
     * @param ResponseInterface $response The API response containing the access token
182
     *
183
     * @return array Array containing the access token, refresh token and expires timestamp
184
     */
185
    public static function parseTokenResponse(ResponseInterface $response)
186
    {
187
        $parsedJson = json_decode((string)$response->getBody(), true);
188
        Util::ensureNot('invalid_client', Arrays::get($parsedJson, 'error'), 'Invalid Credentials');
189
        Util::ensure(
190
            200,
191
            $response->getStatusCode(),
192
            Arrays::get($parsedJson, 'error_description', 'Unknown API error')
193
        );
194
        return [
195
            $parsedJson['access_token'],
196
            Arrays::get($parsedJson, 'refresh_token'),
197
            time() + (int)$parsedJson['expires_in'],
198
        ];
199
    }
200
201
    /**
202
     * Creates a Request object for obtaining a new token from the API
203
     *
204
     * @param string      $baseUrl      The base url of the API
205
     * @param string|null $refreshToken The refresh token of the API
206
     *
207
     * @return RequestInterface
208
     */
209
    public function getTokenRequest(
210
        string $baseUrl,
211
        string $refreshToken = null
212
    ) : RequestInterface {
213
        return call_user_func($this->getTokenRequestFunc, $baseUrl, $refreshToken);
214
    }
215
216
    /**
217
     * Build a refresh token request
218
     *
219
     * @param string $baseUrl API base url
220
     * @param string $clientId The client id
221
     * @param string $clientSecret The client secret
222
     * @param string $refreshResource The refresh token resource of the API
223
     *     Only needed since apigee doesnt use the token resource that is in the oauth2 spec
224
     * @param string $refreshToken The refresh token of the API
225
     *
226
     * @return RequestInterface The built token refresh request
227
     */
228
    private static function getRefreshTokenRequest(
229
        string $baseUrl,
230
        string $clientId,
231
        string $clientSecret,
232
        string $refreshResource,
233
        string $refreshToken
234
    ) : RequestInterface {
235
        //NOTE client_id and client_secret are needed for Apigee but are not in the oauth2 spec
236
        $data = [
237
            'client_id' => $clientId,
238
            'client_secret' => $clientSecret,
239
            'refresh_token' => $refreshToken,
240
            'grant_type' => 'refresh_token',
241
        ];
242
243
        //NOTE the oauth2 spec says the refresh resource should be the same as the token resource, which is impossible
244
        //in Apigee and why the $refreshResource variable exists
245
        return new Request(
246
            'POST',
247
            "{$baseUrl}/{$refreshResource}",
248
            ['Content-Type' => 'application/x-www-form-urlencoded'],
249
            Http::buildQueryString($data)
250
        );
251
    }
252
}
253