11<?php
22
3+ declare (strict_types=1 );
4+
35namespace Platformsh \OAuth2 \Client ;
46
7+ use Closure ;
58use GuzzleHttp \Exception \BadResponseException ;
69use League \OAuth2 \Client \Grant \AbstractGrant ;
710use League \OAuth2 \Client \Grant \ClientCredentials ;
1417
1518class GuzzleMiddleware
1619{
17- /** @var AbstractProvider $provider */
18- private $ provider ;
20+ private readonly AbstractProvider $ provider ;
1921
20- /** @var AbstractGrant $grant */
21- private $ grant ;
22+ private readonly AbstractGrant $ grant ;
2223
23- /** @var AccessToken|null */
24- private $ accessToken ;
24+ private readonly array $ grantOptions ;
2525
26- /** @var array */
27- private $ grantOptions ;
26+ private ?AccessToken $ accessToken ;
2827
29- /** @var callable|null */
30- private $ tokenSave ;
28+ private ?Closure $ tokenSave ;
3129
32- /** @var callable|null */
33- protected $ onRefreshStart ;
30+ private ?Closure $ onRefreshStart ;
3431
35- /** @var callable|null */
36- protected $ onRefreshEnd ;
32+ private ?Closure $ onRefreshEnd ;
3733
38- /** @var callable|null */
39- protected $ onRefreshError ;
34+ private ?Closure $ onRefreshError ;
4035
41- /** @var callable|null */
42- protected $ onStepUpAuthResponse ;
36+ private ?Closure $ onStepUpAuthResponse ;
4337
44- /**
45- * GuzzleMiddleware constructor.
46- *
47- * @param AbstractProvider $provider
48- * @param AbstractGrant $grant
49- * @param array $grantOptions
50- */
51- public function __construct (AbstractProvider $ provider , AbstractGrant $ grant = null , array $ grantOptions = [])
38+ public function __construct (AbstractProvider $ provider , ?AbstractGrant $ grant = null , array $ grantOptions = [])
5239 {
5340 $ this ->provider = $ provider ;
5441 $ this ->grant = $ grant ?: new ClientCredentials ();
5542 $ this ->grantOptions = $ grantOptions ;
5643 }
5744
45+ /**
46+ * Main middleware callback.
47+ */
48+ public function __invoke (callable $ next ): callable
49+ {
50+ return function (RequestInterface $ request , array $ options ) use ($ next ) {
51+ if (! $ this ->isOAuth2 ($ request , $ options )) {
52+ return $ next ($ request , $ options );
53+ }
54+
55+ $ token = $ this ->getAccessToken ();
56+ $ request = $ this ->authenticateRequest ($ request , $ token );
57+
58+ /** @var \GuzzleHttp\Promise\PromiseInterface $promise */
59+ $ promise = $ next ($ request , $ options );
60+
61+ return $ promise ->then (function (ResponseInterface $ response ) use ($ request , $ options , $ token , $ next ) {
62+ if ($ response ->getStatusCode () !== 401 ) {
63+ return $ response ;
64+ }
65+
66+ if (isset ($ this ->onStepUpAuthResponse ) && $ this ->isStepUpAuthenticationResponse ($ response )) {
67+ $ newToken = call_user_func ($ this ->onStepUpAuthResponse , $ response );
68+ $ this ->setAccessToken ($ newToken );
69+ } else {
70+ // Consider the old token invalid, and get a new one.
71+ $ this ->getAccessToken ($ token );
72+ }
73+
74+ // Retry the request.
75+ $ request = $ this ->authenticateRequest ($ request , $ token );
76+ return $ next ($ request , $ options );
77+ });
78+ };
79+ }
80+
5881 /**
5982 * Set a callback that will save a token whenever a new one is acquired.
6083 *
6184 * @param callable $tokenSave
6285 * A callback accepting one argument (the AccessToken) that will save a
6386 * token.
6487 */
65- public function setTokenSaveCallback (callable $ tokenSave )
88+ public function setTokenSaveCallback (callable $ tokenSave ): void
6689 {
67- $ this ->tokenSave = $ tokenSave ;
90+ $ this ->tokenSave = Closure:: fromCallable ( $ tokenSave) ;
6891 }
6992
7093 /**
@@ -74,9 +97,9 @@ public function setTokenSaveCallback(callable $tokenSave)
7497 * A callback which accepts 1 argument, the refresh token being used if
7598 * available (a string or null), and returns an AccessToken or null.
7699 */
77- public function setOnRefreshStart (callable $ callback )
100+ public function setOnRefreshStart (callable $ callback ): void
78101 {
79- $ this ->onRefreshStart = $ callback ;
102+ $ this ->onRefreshStart = Closure:: fromCallable ( $ callback) ;
80103 }
81104
82105 /**
@@ -86,9 +109,9 @@ public function setOnRefreshStart(callable $callback)
86109 * A callback which accepts 1 argument, the refresh token which was used
87110 * if available (a string or null).
88111 */
89- public function setOnRefreshEnd (callable $ callback )
112+ public function setOnRefreshEnd (callable $ callback ): void
90113 {
91- $ this ->onRefreshEnd = $ callback ;
114+ $ this ->onRefreshEnd = Closure:: fromCallable ( $ callback) ;
92115 }
93116
94117 /**
@@ -98,9 +121,9 @@ public function setOnRefreshEnd(callable $callback)
98121 * A callback which accepts one argument, the BadResponseException, and
99122 * returns an AccessToken or null.
100123 */
101- public function setOnRefreshError (callable $ callback )
124+ public function setOnRefreshError (callable $ callback ): void
102125 {
103- $ this ->onRefreshError = $ callback ;
126+ $ this ->onRefreshError = Closure:: fromCallable ( $ callback) ;
104127 }
105128
106129 /**
@@ -110,79 +133,38 @@ public function setOnRefreshError(callable $callback)
110133 * A callback which accepts one argument, the response, of type \GuzzleHttp\Message\ResponseInterface,
111134 * and returns an AccessToken or null.
112135 */
113- public function setOnStepUpAuthResponse (callable $ callback )
136+ public function setOnStepUpAuthResponse (callable $ callback ): void
114137 {
115- $ this ->onStepUpAuthResponse = $ callback ;
138+ $ this ->onStepUpAuthResponse = Closure:: fromCallable ( $ callback) ;
116139 }
117140
118141 /**
119- * Main middleware callback.
120- *
121- * @param callable $next
122- *
123- * @return callable
142+ * Sets the access token for the next request(s) and saves it to storage.
124143 */
125- public function __invoke ( callable $ next )
144+ public function setAccessToken ( AccessToken $ token ): void
126145 {
127- return function (RequestInterface $ request , array $ options ) use ($ next ) {
128- if (!$ this ->isOAuth2 ($ request , $ options )) {
129- return $ next ($ request , $ options );
130- }
131-
132- $ token = $ this ->getAccessToken ();
133- $ request = $ this ->authenticateRequest ($ request , $ token );
134-
135- /** @var \GuzzleHttp\Promise\PromiseInterface $promise */
136- $ promise = $ next ($ request , $ options );
137-
138- return $ promise ->then (function (ResponseInterface $ response ) use ($ request , $ options , $ token , $ next ) {
139- if ($ response ->getStatusCode () !== 401 ) {
140- return $ response ;
141- }
142-
143- if (isset ($ this ->onStepUpAuthResponse ) && $ this ->isStepUpAuthenticationResponse ($ response )) {
144- $ newToken = call_user_func ($ this ->onStepUpAuthResponse , $ response );
145- $ this ->accessToken = $ newToken ;
146- if (is_callable ($ this ->tokenSave )) {
147- call_user_func ($ this ->tokenSave , $ this ->accessToken );
148- }
149- } else {
150- // Consider the old token invalid, and get a new one.
151- $ this ->getAccessToken ($ token );
152- }
153-
154- // Retry the request.
155- $ request = $ this ->authenticateRequest ($ request , $ token );
156- return $ next ($ request , $ options );
157- });
158- };
146+ $ this ->accessToken = $ token ;
147+ if ($ this ->tokenSave ) {
148+ ($ this ->tokenSave )($ this ->accessToken );
149+ }
159150 }
160151
161152 /**
162153 * Checks for a step-up authentication response (RFC 9470).
163- *
164- * @param ResponseInterface $response
165- *
166- * @return bool
167154 */
168- protected function isStepUpAuthenticationResponse (ResponseInterface $ response )
155+ protected function isStepUpAuthenticationResponse (ResponseInterface $ response ): bool
169156 {
170157 $ authHeader = implode ("\n" , $ response ->getHeader ('WWW-Authenticate ' ));
171- return stripos ($ authHeader , 'Bearer ' ) !== false && strpos ($ authHeader , 'insufficient_user_authentication ' ) !== false ;
158+ return stripos ($ authHeader , 'Bearer ' ) !== false && str_contains ($ authHeader , 'insufficient_user_authentication ' );
172159 }
173160
174161 /**
175162 * Check if a request is configured to use OAuth2.
176- *
177- * @param RequestInterface $request
178- * @param array $options
179- *
180- * @return bool
181163 */
182- private function isOAuth2 (RequestInterface $ request , array $ options )
164+ private function isOAuth2 (RequestInterface $ request , array $ options ): bool
183165 {
184166 // The 'auth' option must be set to 'oauth2'.
185- if (!isset ($ options ['auth ' ]) || $ options ['auth ' ] !== 'oauth2 ' ) {
167+ if (! isset ($ options ['auth ' ]) || $ options ['auth ' ] !== 'oauth2 ' ) {
186168 return false ;
187169 }
188170
@@ -196,13 +178,8 @@ private function isOAuth2(RequestInterface $request, array $options)
196178
197179 /**
198180 * Add authentication to an HTTP request.
199- *
200- * @param RequestInterface $request
201- * @param AccessToken $token
202- *
203- * @return RequestInterface
204181 */
205- private function authenticateRequest (RequestInterface $ request , AccessToken $ token )
182+ private function authenticateRequest (RequestInterface $ request , AccessToken $ token ): RequestInterface
206183 {
207184 foreach ($ this ->provider ->getHeaders ($ token ->getToken ()) as $ name => $ value ) {
208185 $ request = $ request ->withHeader ($ name , $ value );
@@ -217,17 +194,12 @@ private function authenticateRequest(RequestInterface $request, AccessToken $tok
217194 * @param AccessToken|null $invalid
218195 * A token to consider invalid.
219196 *
220- * @return AccessToken
221- * The OAuth2 access token.
222197 * @throws IdentityProviderException
223198 */
224- private function getAccessToken (AccessToken $ invalid = null )
199+ private function getAccessToken (AccessToken $ invalid = null ): AccessToken
225200 {
226- if (!isset ($ this ->accessToken ) || $ this ->accessToken ->hasExpired () || ($ invalid && $ this ->accessToken === $ invalid )) {
227- $ this ->accessToken = $ this ->acquireAccessToken ();
228- if (is_callable ($ this ->tokenSave )) {
229- call_user_func ($ this ->tokenSave , $ this ->accessToken );
230- }
201+ if (! isset ($ this ->accessToken ) || $ this ->accessToken ->hasExpired () || ($ invalid && $ this ->accessToken === $ invalid )) {
202+ $ this ->setAccessToken ($ this ->acquireAccessToken ());
231203 }
232204
233205 return $ this ->accessToken ;
@@ -236,10 +208,9 @@ private function getAccessToken(AccessToken $invalid = null)
236208 /**
237209 * Acquire a new access token using a refresh token or the configured grant.
238210 *
239- * @return AccessToken
240211 * @throws IdentityProviderException
241212 */
242- private function acquireAccessToken ()
213+ private function acquireAccessToken (): AccessToken
243214 {
244215 if (isset ($ this ->accessToken ) && $ this ->accessToken ->getRefreshToken ()) {
245216 $ currentRefreshToken = $ this ->accessToken ->getRefreshToken ();
@@ -250,7 +221,9 @@ private function acquireAccessToken()
250221 return $ result ;
251222 }
252223 }
253- return $ this ->provider ->getAccessToken (new RefreshToken (), ['refresh_token ' => $ this ->accessToken ->getRefreshToken ()]);
224+ return $ this ->provider ->getAccessToken (new RefreshToken (), [
225+ 'refresh_token ' => $ this ->accessToken ->getRefreshToken (),
226+ ]);
254227 } catch (BadResponseException $ e ) {
255228 if (isset ($ this ->onRefreshError )) {
256229 $ accessToken = call_user_func ($ this ->onRefreshError , $ e );
@@ -268,27 +241,4 @@ private function acquireAccessToken()
268241
269242 return $ this ->provider ->getAccessToken ($ this ->grant , $ this ->grantOptions );
270243 }
271-
272- /**
273- * Set the access token for the next request(s).
274- *
275- * @param AccessToken $token
276- */
277- public function setAccessToken (AccessToken $ token )
278- {
279- $ this ->accessToken = $ token ;
280- }
281-
282- /**
283- * Set the access token for the next request(s), and save it to storage.
284- *
285- * @param AccessToken $token
286- */
287- public function saveAccessToken (AccessToken $ token )
288- {
289- $ this ->accessToken = $ token ;
290- if (is_callable ($ this ->tokenSave )) {
291- call_user_func ($ this ->tokenSave , $ this ->accessToken );
292- }
293- }
294244}
0 commit comments