Completed
Push — master ( 0b567a...5de823 )
by Chad
24s queued 21s
created

createApiGatewayClientCredentials()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 3
dl 0
loc 23
rs 9.7998
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 Owner Credentials grant type
83
     *
84
     * @param string $clientId        The oauth client id
85
     * @param string $clientSecret    The oauth client secret
86
     * @param string $username        The oauth username
87
     * @param string $password        The oauth password
88
     * @param string $refreshResource The refresh token resource of the API. Only needed since apigee doesnt use the
89
     *                                token resource that is in the oauth2 spec
90
     * @param string $tokenResource   The access token resource of the API
91
     *
92
     * @return Authentication
93
     */
94
    public static function createOwnerCredentials(
95
        string $clientId,
96
        string $clientSecret,
97
        string $username,
98
        string $password,
99
        string $refreshResource = 'token',
100
        string $tokenResource = 'token'
101
    ) : Authentication {
102
        $getTokenRequestFunc = function (
103
            string $baseUrl,
104
            string $refreshToken = null
105
        ) use (
106
            $clientId,
107
            $clientSecret,
108
            $username,
109
            $password,
110
            $refreshResource,
111
            $tokenResource
112
        ) {
113
            if ($refreshToken !== null) {
114
                return self::getRefreshTokenRequest(
115
                    $baseUrl,
116
                    $clientId,
117
                    $clientSecret,
118
                    $refreshResource,
119
                    $refreshToken
120
                );
121
            }
122
123
            $data = [
124
                'client_id' => $clientId,
125
                'client_secret' => $clientSecret,
126
                'username' => $username,
127
                'password' => $password,
128
                'grant_type' => 'password',
129
            ];
130
            return new Request(
131
                'POST',
132
                "{$baseUrl}/{$tokenResource}",
133
                ['Content-Type' => 'application/x-www-form-urlencoded'],
134
                Http::buildQueryString($data)
135
            );
136
        };
137
138
        return new self($getTokenRequestFunc);
139
    }
140
141
    /**
142
     * Creates a new instance of Authentication for API Gateway Client Credentials grant type
143
     *
144
     * @param string $clientId     The oauth client id
145
     * @param string $clientSecret The oauth client secret
146
     * @param string $authUrl      The oauth auth url
147
     *
148
     * @return Authentication
149
     */
150
    public static function createApiGatewayClientCredentials(
151
        string $clientId,
152
        string $clientSecret,
153
        string $authUrl
154
    ) : Authentication {
155
        $getTokenRequestFunc = function (
156
            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

156
            /** @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...
157
            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

157
            /** @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...
158
        ) use (
159
            $clientId,
160
            $clientSecret,
161
            $authUrl
162
        ) {
163
            $data = ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => 'client_credentials'];
164
            return new Request(
165
                'POST',
166
                $authUrl,
167
                ['Content-Type' => 'application/x-www-form-urlencoded'],
168
                Http::buildQueryString($data)
169
            );
170
        };
171
172
        return new self($getTokenRequestFunc);
173
    }
174
175
    /**
176
     * Extracts an access token from the given API response
177
     *
178
     * @param ResponseInterface $response The API response containing the access token
179
     *
180
     * @return array Array containing the access token, refresh token and expires timestamp
181
     */
182
    public static function parseTokenResponse(ResponseInterface $response)
183
    {
184
        $parsedJson = json_decode((string)$response->getBody(), true);
185
        Util::ensureNot('invalid_client', Arrays::get($parsedJson, 'error'), 'Invalid Credentials');
186
        Util::ensure(
187
            200,
188
            $response->getStatusCode(),
189
            Arrays::get($parsedJson, 'error_description', 'Unknown API error')
190
        );
191
        return [
192
            $parsedJson['access_token'],
193
            Arrays::get($parsedJson, 'refresh_token'),
194
            time() + (int)$parsedJson['expires_in'],
195
        ];
196
    }
197
198
    /**
199
     * Creates a Request object for obtaining a new token from the API
200
     *
201
     * @param string      $baseUrl      The base url of the API
202
     * @param string|null $refreshToken The refresh token of the API
203
     *
204
     * @return RequestInterface
205
     */
206
    public function getTokenRequest(string $baseUrl, string $refreshToken = null) : RequestInterface
207
    {
208
        return call_user_func($this->getTokenRequestFunc, $baseUrl, $refreshToken);
209
    }
210
211
    /**
212
     * Build a refresh token request
213
     *
214
     * @param string $baseUrl API base url
215
     * @param string $clientId The client id
216
     * @param string $clientSecret The client secret
217
     * @param string $refreshResource The refresh token resource of the API
218
     *     Only needed since apigee doesnt use the token resource that is in the oauth2 spec
219
     * @param string $refreshToken The refresh token of the API
220
     *
221
     * @return RequestInterface The built token refresh request
222
     */
223
    private static function getRefreshTokenRequest(
224
        string $baseUrl,
225
        string $clientId,
226
        string $clientSecret,
227
        string $refreshResource,
228
        string $refreshToken
229
    ) : RequestInterface {
230
        //NOTE client_id and client_secret are needed for Apigee but are not in the oauth2 spec
231
        $data = [
232
            'client_id' => $clientId,
233
            'client_secret' => $clientSecret,
234
            'refresh_token' => $refreshToken,
235
            'grant_type' => 'refresh_token',
236
        ];
237
238
        //NOTE the oauth2 spec says the refresh resource should be the same as the token resource, which is impossible
239
        //in Apigee and why the $refreshResource variable exists
240
        return new Request(
241
            'POST',
242
            "{$baseUrl}/{$refreshResource}",
243
            ['Content-Type' => 'application/x-www-form-urlencoded'],
244
            Http::buildQueryString($data)
245
        );
246
    }
247
}
248