Пример #1
0
    def test_token_refresh_store_expires_soon(self):
        # Tests the case where an access token that is valid when it is read
        # from the store expires before the original request succeeds.
        expiration = (datetime.datetime.utcnow() +
                      datetime.timedelta(minutes=15))
        credentials = self._create_test_credentials(expiration=expiration)

        storage = file_module.Storage(FILENAME)
        storage.put(credentials)
        credentials = storage.get()
        new_cred = copy.copy(credentials)
        new_cred.access_token = 'bar'
        storage.put(new_cred)

        access_token = '1/3w'
        token_response = {'access_token': access_token, 'expires_in': 3600}
        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.UNAUTHORIZED
            }, b'Initial token expired'),
            ({
                'status': http_client.UNAUTHORIZED
            }, b'Store token expired'),
            ({
                'status': http_client.OK
            }, json.dumps(token_response).encode('utf-8')),
            ({
                'status': http_client.OK
            }, b'Valid response to original request')
        ])

        credentials.authorize(http)
        transport.request(http, 'https://example.com')
        self.assertEqual(credentials.access_token, access_token)
Пример #2
0
 def test_credentials_good(self):
     credentials = self._make_credentials()
     http = http_mock.HttpMockSequence([
         ({
             'status': http_client.OK
         }, b'{"access_token":"1/3w","expires_in":3600}'),
         ({
             'status': http_client.OK
         }, 'echo_request_headers'),
     ])
     http = credentials.authorize(http)
     resp, content = transport.request(http, 'http://example.org')
     self.assertEqual(b'Bearer 1/3w', content[b'Authorization'])
    def test_authorize_401(self, utcnow):
        utcnow.return_value = T1_DATE

        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.OK
            }, b''),
            ({
                'status': http_client.UNAUTHORIZED
            }, b''),
            ({
                'status': http_client.OK
            }, b''),
        ])
        self.jwt.authorize(http)
        transport.request(http, self.url)
        token_1 = self.jwt.access_token

        utcnow.return_value = T2_DATE
        response, _ = transport.request(http, self.url)
        self.assertEquals(response.status, http_client.OK)
        token_2 = self.jwt.access_token
        # Check the 401 forced a new token
        self.assertNotEqual(token_1, token_2)

        # Verify mocks.
        certs = {'key': datafile('public_cert.pem')}
        self.assertEqual(len(http.requests), 3)
        issued_at_vals = (T1, T1, T2)
        exp_vals = (T1_EXPIRY, T1_EXPIRY, T2_EXPIRY)
        for info, issued_at, exp_val in zip(http.requests, issued_at_vals,
                                            exp_vals):
            self.assertEqual(info['uri'], self.url)
            self.assertEqual(info['method'], 'GET')
            self.assertIsNone(info['body'])
            self.assertEqual(len(info['headers']), 1)
            bearer, token = info['headers'][b'Authorization'].split()
            self.assertEqual(bearer, b'Bearer')
            # To parse the token, skip the time check, since this
            # test intentionally has stale tokens.
            with mock.patch('oauth2client.crypt._verify_time_range',
                            return_value=True):
                payload = crypt.verify_signed_jwt_with_certs(token,
                                                             certs,
                                                             audience=self.url)
            self.assertEqual(len(payload), 5)
            self.assertEqual(payload['iss'], self.service_account_email)
            self.assertEqual(payload['sub'], self.service_account_email)
            self.assertEqual(payload['iat'], issued_at)
            self.assertEqual(payload['exp'], exp_val)
            self.assertEqual(payload['aud'], self.url)
Пример #4
0
 def _credentials_refresh(self, credentials):
     http = http_mock.HttpMockSequence([
         ({
             'status': http_client.OK
         }, b'{"access_token":"1/3w","expires_in":3600}'),
         ({
             'status': http_client.UNAUTHORIZED
         }, b''),
         ({
             'status': http_client.OK
         }, b'{"access_token":"3/3w","expires_in":3600}'),
         ({
             'status': http_client.OK
         }, 'echo_request_headers'),
     ])
     http = credentials.authorize(http)
     _, content = transport.request(http, 'http://example.org')
     return content
    def test_authorize_no_aud(self, time, utcnow):
        utcnow.return_value = T1_DATE
        time.return_value = T1

        jwt = service_account._JWTAccessCredentials(
            self.service_account_email,
            self.signer,
            private_key_id=self.private_key_id,
            client_id=self.client_id)

        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.OK
            }, b''),
        ])

        jwt.authorize(http)
        transport.request(http, self.url)

        # Ensure we do not cache the token
        self.assertIsNone(jwt.access_token)

        # Verify mocks.
        self.assertEqual(len(http.requests), 1)
        info = http.requests[0]
        self.assertEqual(info['method'], 'GET')
        self.assertEqual(info['uri'], self.url)
        self.assertIsNone(info['body'])
        self.assertEqual(len(info['headers']), 1)
        bearer, token = info['headers'][b'Authorization'].split()
        self.assertEqual(bearer, b'Bearer')
        certs = {'key': datafile('public_cert.pem')}
        payload = crypt.verify_signed_jwt_with_certs(token,
                                                     certs,
                                                     audience=self.url)
        self.assertEqual(len(payload), 5)
        self.assertEqual(payload['iss'], self.service_account_email)
        self.assertEqual(payload['sub'], self.service_account_email)
        self.assertEqual(payload['iat'], T1)
        self.assertEqual(payload['exp'], T1_EXPIRY)
        self.assertEqual(payload['aud'], self.url)
    def test_authorize_success(self, time, utcnow):
        utcnow.return_value = T1_DATE
        time.return_value = T1

        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.OK
            }, b''),
            ({
                'status': http_client.OK
            }, b''),
        ])

        self.jwt.authorize(http)
        transport.request(http, self.url)

        # Ensure we use the cached token
        utcnow.return_value = T2_DATE
        transport.request(http, self.url)

        # Verify mocks.
        certs = {'key': datafile('public_cert.pem')}
        self.assertEqual(len(http.requests), 2)
        for info in http.requests:
            self.assertEqual(info['method'], 'GET')
            self.assertEqual(info['uri'], self.url)
            self.assertIsNone(info['body'])
            self.assertEqual(len(info['headers']), 1)
            bearer, token = info['headers'][b'Authorization'].split()
            self.assertEqual(bearer, b'Bearer')
            payload = crypt.verify_signed_jwt_with_certs(token,
                                                         certs,
                                                         audience=self.url)
            self.assertEqual(len(payload), 5)
            self.assertEqual(payload['iss'], self.service_account_email)
            self.assertEqual(payload['sub'], self.service_account_email)
            self.assertEqual(payload['iat'], T1)
            self.assertEqual(payload['exp'], T1_EXPIRY)
            self.assertEqual(payload['aud'], self.url)
Пример #7
0
    def test_token_refresh_stream_body(self):
        expiration = (datetime.datetime.utcnow() +
                      datetime.timedelta(minutes=15))
        credentials = self._create_test_credentials(expiration=expiration)

        storage = file_module.Storage(FILENAME)
        storage.put(credentials)
        credentials = storage.get()
        new_cred = copy.copy(credentials)
        new_cred.access_token = 'bar'
        storage.put(new_cred)

        valid_access_token = '1/3w'
        token_response = {
            'access_token': valid_access_token,
            'expires_in': 3600
        }
        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.UNAUTHORIZED
            }, b'Initial token expired'),
            ({
                'status': http_client.UNAUTHORIZED
            }, b'Store token expired'),
            ({
                'status': http_client.OK
            }, json.dumps(token_response).encode('utf-8')),
            ({
                'status': http_client.OK
            }, 'echo_request_body')
        ])

        body = six.StringIO('streaming body')

        credentials.authorize(http)
        _, content = transport.request(http, 'https://example.com', body=body)
        self.assertEqual(content, 'streaming body')
        self.assertEqual(credentials.access_token, valid_access_token)
    def test_access_token(self, utcnow):
        # Configure the patch.
        seconds = 11
        NOW = datetime.datetime(1992, 12, 31, second=seconds)
        utcnow.return_value = NOW

        # Create a custom credentials with a mock signer.
        signer = mock.Mock()
        signed_value = b'signed-content'
        signer.sign = mock.Mock(name='sign', return_value=signed_value)
        credentials = service_account.ServiceAccountCredentials(
            self.service_account_email,
            signer,
            private_key_id=self.private_key_id,
            client_id=self.client_id,
        )

        # Begin testing.
        lifetime = 2  # number of seconds in which the token expires
        EXPIRY_TIME = datetime.datetime(1992,
                                        12,
                                        31,
                                        second=seconds + lifetime)

        token1 = u'first_token'
        token_response_first = {
            'access_token': token1,
            'expires_in': lifetime,
        }
        token2 = u'second_token'
        token_response_second = {
            'access_token': token2,
            'expires_in': lifetime,
        }
        http = http_mock.HttpMockSequence([
            ({
                'status': http_client.OK
            }, json.dumps(token_response_first).encode('utf-8')),
            ({
                'status': http_client.OK
            }, json.dumps(token_response_second).encode('utf-8')),
        ])

        # Get Access Token, First attempt.
        self.assertIsNone(credentials.access_token)
        self.assertFalse(credentials.access_token_expired)
        self.assertIsNone(credentials.token_expiry)
        token = credentials.get_access_token(http=http)
        self.assertEqual(credentials.token_expiry, EXPIRY_TIME)
        self.assertEqual(token1, token.access_token)
        self.assertEqual(lifetime, token.expires_in)
        self.assertEqual(token_response_first, credentials.token_response)
        # Two utcnow calls are expected:
        # - get_access_token() -> _do_refresh_request (setting expires in)
        # - get_access_token() -> _expires_in()
        expected_utcnow_calls = [mock.call()] * 2
        self.assertEqual(expected_utcnow_calls, utcnow.mock_calls)
        # One call to sign() expected: Actual refresh was needed.
        self.assertEqual(len(signer.sign.mock_calls), 1)

        # Get Access Token, Second Attempt (not expired)
        self.assertEqual(credentials.access_token, token1)
        self.assertFalse(credentials.access_token_expired)
        token = credentials.get_access_token(http=http)
        # Make sure no refresh occurred since the token was not expired.
        self.assertEqual(token1, token.access_token)
        self.assertEqual(lifetime, token.expires_in)
        self.assertEqual(token_response_first, credentials.token_response)
        # Three more utcnow calls are expected:
        # - access_token_expired
        # - get_access_token() -> access_token_expired
        # - get_access_token -> _expires_in
        expected_utcnow_calls = [mock.call()] * (2 + 3)
        self.assertEqual(expected_utcnow_calls, utcnow.mock_calls)
        # No call to sign() expected: the token was not expired.
        self.assertEqual(len(signer.sign.mock_calls), 1 + 0)

        # Get Access Token, Third Attempt (force expiration)
        self.assertEqual(credentials.access_token, token1)
        credentials.token_expiry = NOW  # Manually force expiry.
        self.assertTrue(credentials.access_token_expired)
        token = credentials.get_access_token(http=http)
        # Make sure refresh occurred since the token was not expired.
        self.assertEqual(token2, token.access_token)
        self.assertEqual(lifetime, token.expires_in)
        self.assertFalse(credentials.access_token_expired)
        self.assertEqual(token_response_second, credentials.token_response)
        # Five more utcnow calls are expected:
        # - access_token_expired
        # - get_access_token -> access_token_expired
        # - get_access_token -> _do_refresh_request
        # - get_access_token -> _expires_in
        # - access_token_expired
        expected_utcnow_calls = [mock.call()] * (2 + 3 + 5)
        self.assertEqual(expected_utcnow_calls, utcnow.mock_calls)
        # One more call to sign() expected: Actual refresh was needed.
        self.assertEqual(len(signer.sign.mock_calls), 1 + 0 + 1)

        self.assertEqual(credentials.access_token, token2)