|
11 | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | | - |
| 14 | +import base64 |
15 | 15 | import datetime |
16 | 16 |
|
17 | 17 | import mock |
18 | 18 | import pytest |
| 19 | +import responses |
19 | 20 |
|
20 | 21 | from google.auth import _helpers |
21 | 22 | from google.auth import exceptions |
22 | 23 | from google.auth import jwt |
23 | 24 | from google.auth import transport |
24 | 25 | from google.auth.compute_engine import credentials |
| 26 | +from google.auth.transport import requests |
25 | 27 |
|
26 | 28 |
|
27 | 29 | class TestCredentials(object): |
@@ -270,6 +272,84 @@ def test_with_target_audience(self, sign, get, utcnow): |
270 | 272 | "target_audience": "https://actually.not", |
271 | 273 | } |
272 | 274 |
|
| 275 | + # Check that the signer have been initialized with a Request object |
| 276 | + assert isinstance(self.credentials._signer._request, transport.Request) |
| 277 | + |
| 278 | + @responses.activate |
| 279 | + def test_with_target_audience_integration(self): |
| 280 | + """ Test that it is possible to refresh credentials |
| 281 | + generated from `with_target_audience`. |
| 282 | +
|
| 283 | + Instead of mocking the methods, the HTTP responses |
| 284 | + have been mocked. |
| 285 | + """ |
| 286 | + |
| 287 | + # mock information about credentials |
| 288 | + responses.add( |
| 289 | + responses.GET, |
| 290 | + "http://metadata.google.internal/computeMetadata/v1/instance/" |
| 291 | + "service-accounts/default/?recursive=true", |
| 292 | + status=200, |
| 293 | + content_type="application/json", |
| 294 | + json={ |
| 295 | + "scopes": "email", |
| 296 | + "email": "service-account@example.com", |
| 297 | + "aliases": ["default"], |
| 298 | + }, |
| 299 | + ) |
| 300 | + |
| 301 | + # mock token for credentials |
| 302 | + responses.add( |
| 303 | + responses.GET, |
| 304 | + "http://metadata.google.internal/computeMetadata/v1/instance/" |
| 305 | + "service-accounts/service-account@example.com/token", |
| 306 | + status=200, |
| 307 | + content_type="application/json", |
| 308 | + json={ |
| 309 | + "access_token": "some-token", |
| 310 | + "expires_in": 3210, |
| 311 | + "token_type": "Bearer", |
| 312 | + }, |
| 313 | + ) |
| 314 | + |
| 315 | + # mock sign blob endpoint |
| 316 | + signature = base64.b64encode(b"some-signature").decode("utf-8") |
| 317 | + responses.add( |
| 318 | + responses.POST, |
| 319 | + "https://iam.googleapis.com/v1/projects/-/serviceAccounts/" |
| 320 | + "service-account@example.com:signBlob?alt=json", |
| 321 | + status=200, |
| 322 | + content_type="application/json", |
| 323 | + json={"keyId": "some-key-id", "signature": signature}, |
| 324 | + ) |
| 325 | + |
| 326 | + id_token = "{}.{}.{}".format( |
| 327 | + base64.b64encode(b'{"some":"some"}').decode("utf-8"), |
| 328 | + base64.b64encode(b'{"exp": 3210}').decode("utf-8"), |
| 329 | + base64.b64encode(b"token").decode("utf-8"), |
| 330 | + ) |
| 331 | + |
| 332 | + # mock id token endpoint |
| 333 | + responses.add( |
| 334 | + responses.POST, |
| 335 | + "https://www.googleapis.com/oauth2/v4/token", |
| 336 | + status=200, |
| 337 | + content_type="application/json", |
| 338 | + json={"id_token": id_token, "expiry": 3210}, |
| 339 | + ) |
| 340 | + |
| 341 | + self.credentials = credentials.IDTokenCredentials( |
| 342 | + request=requests.Request(), |
| 343 | + service_account_email="service-account@example.com", |
| 344 | + target_audience="https://audience.com", |
| 345 | + ) |
| 346 | + |
| 347 | + self.credentials = self.credentials.with_target_audience("https://actually.not") |
| 348 | + |
| 349 | + self.credentials.refresh(requests.Request()) |
| 350 | + |
| 351 | + assert self.credentials.token is not None |
| 352 | + |
273 | 353 | @mock.patch( |
274 | 354 | "google.auth._helpers.utcnow", |
275 | 355 | return_value=datetime.datetime.utcfromtimestamp(0), |
|
0 commit comments