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

createApiGatewayClientCredentials()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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