def test_create_token_response(self): self.request.response_type = None self.mock_validator.validate_code.side_effect = self.set_scopes bearer = BearerToken(self.mock_validator) h, token, s = self.auth.create_token_response(self.request, bearer) token = json.loads(token) self.assertEqual(self.mock_validator.save_token.call_count, 1) self.assertIn('access_token', token) self.assertIn('refresh_token', token) self.assertIn('expires_in', token) self.assertIn('scope', token) self.assertIn('id_token', token) self.assertIn('openid', token['scope']) self.mock_validator.reset_mock() self.request.scopes = ('hello', 'world') h, token, s = self.auth.create_token_response(self.request, bearer) token = json.loads(token) self.assertEqual(self.mock_validator.save_token.call_count, 1) self.assertIn('access_token', token) self.assertIn('refresh_token', token) self.assertIn('expires_in', token) self.assertIn('scope', token) self.assertNotIn('id_token', token) self.assertNotIn('openid', token['scope'])
def __init__(self, request_validator, token_generator=None, token_expires_in=None, refresh_token_generator=None, **kwargs): """Construct a new web application server. :param request_validator: An implementation of oauthlib.oauth2.RequestValidator. :param token_expires_in: An int or a function to generate a token expiration offset (in seconds) given a oauthlib.common.Request object. :param token_generator: A function to generate a token from a request. :param refresh_token_generator: A function to generate a token from a request for the refresh token. :param kwargs: Extra parameters to pass to authorization-, token-, resource-, and revocation-endpoint constructors. """ auth_grant = AuthorizationCodeGrant(request_validator) refresh_grant = RefreshTokenGrant(request_validator) bearer = BearerToken(request_validator, token_generator, token_expires_in, refresh_token_generator) AuthorizationEndpoint.__init__(self, default_response_type='code', response_types={'code': auth_grant}, default_token_type=bearer) TokenEndpoint.__init__(self, default_grant_type='authorization_code', grant_types={ 'authorization_code': auth_grant, 'refresh_token': refresh_grant, }, default_token_type=bearer) ResourceEndpoint.__init__(self, default_token='Bearer', token_types={'Bearer': bearer}) RevocationEndpoint.__init__(self, request_validator)
def test_create_cors_headers_insecure_origin(self): bearer = BearerToken(self.mock_validator) self.request.headers['origin'] = 'http://foo.bar' headers = self.auth.create_token_response(self.request, bearer)[0] self.assertNotIn('Access-Control-Allow-Origin', headers) self.mock_validator.is_origin_allowed.assert_not_called()
def setUp(self): def set_user(request): request.user = mock.MagicMock() request.client = mock.MagicMock() request.client.client_id = 'mocked_client_id' return True self.mock_validator = mock.MagicMock() self.mock_validator.authenticate_client.side_effect = set_user self.mock_validator.get_code_challenge.return_value = None self.addCleanup(setattr, self, 'mock_validator', mock.MagicMock()) auth_code = AuthorizationCodeGrant( request_validator=self.mock_validator) supported_types = { 'authorization_code': auth_code, } self.expires_in = 1800 token = BearerToken( self.mock_validator, expires_in=self.expires_in ) self.endpoint = TokenEndpoint( 'authorization_code', default_token_type=token, grant_types=supported_types )
def test_create_token_response(self): bearer = BearerToken(self.mock_validator) headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(self.mock_validator.save_token.call_count, 1) self.assertIn('access_token', token) self.assertIn('token_type', token) self.assertIn('expires_in', token) self.assertIn('refresh_token', token) # ensure client_authentication_required() is properly called self.mock_validator.\ client_authentication_required.assert_called_once_with( self.request) # fail client authentication self.mock_validator.reset_mock() self.mock_validator.validate_user.return_value = True self.mock_validator.authenticate_client.return_value = False status_code = self.auth.create_token_response(self.request, bearer)[2] self.assertEqual(status_code, 401) self.assertEqual(self.mock_validator.save_token.call_count, 0) # mock client_authentication_required() returning False then fail self.mock_validator.reset_mock() self.mock_validator.client_authentication_required.return_value = False self.mock_validator.authenticate_client_id.return_value = False status_code = self.auth.create_token_response(self.request, bearer)[2] self.assertEqual(status_code, 401) self.assertEqual(self.mock_validator.save_token.call_count, 0)
def setUp(self): self.mock_validator = mock.MagicMock() self.mock_validator.get_code_challenge.return_value = None self.addCleanup(setattr, self, 'mock_validator', mock.MagicMock()) auth_code = AuthorizationCodeGrant(request_validator=self.mock_validator) auth_code.save_authorization_code = mock.MagicMock() implicit = ImplicitGrant( request_validator=self.mock_validator) implicit.save_token = mock.MagicMock() hybrid = HybridGrant(self.mock_validator) response_types = { 'code': auth_code, 'token': implicit, 'id_token': implicit, 'id_token token': implicit, 'code token': hybrid, 'code id_token': hybrid, 'code token id_token': hybrid, 'none': auth_code } self.expires_in = 1800 token = BearerToken( self.mock_validator, expires_in=self.expires_in ) self.endpoint = AuthorizationEndpoint( default_response_type='code', default_token_type=token, response_types=response_types )
def create_service_token(client, user): """Generate and return a bearer token for service calls Partners need a mechanism for automated, authorized API access. This function returns a bearer token for subsequent authorized calls. NB - as this opens a back door, it's only offered to users with the single role 'service'. """ if not current_app.config.get('TESTING') and ( len(user.roles) > 1 or user.roles[0].name != ROLE.SERVICE.value): raise ValueError("only service users can create service tokens") # Hacking a backdoor into the OAuth protocol to generate a valid token # Mock the request and validation needed to pass from oauthlib.oauth2.rfc6749.tokens import BearerToken fake_request = Mock() fake_request.state, fake_request.extra_credentials = None, None fake_request.client = client fake_request.user = user fake_request.scopes = ['email'] request_validator = Mock() request_validator.save_bearer_token = save_token bt = BearerToken(request_validator=request_validator) bt.expires_in = int(timedelta(days=365).total_seconds()) # one year bt.create_token(fake_request) # Token should now exist as only token for said user - return it return Token.query.filter_by(user_id=user.id).first()
def test_create_token_response_without_refresh_token(self): # self.auth.refresh_token = False so we don't generate a refresh token self.auth = ResourceOwnerPasswordCredentialsGrant( request_validator=self.mock_validator, refresh_token=False) bearer = BearerToken(self.mock_validator) headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(self.mock_validator.save_token.call_count, 1) self.assertIn('access_token', token) self.assertIn('token_type', token) self.assertIn('expires_in', token) # ensure no refresh token is generated self.assertNotIn('refresh_token', token) # ensure client_authentication_required() is properly called self.mock_validator.client_authentication_required.assert_called_once_with(self.request) # fail client authentication self.mock_validator.reset_mock() self.mock_validator.validate_user.return_value = True self.mock_validator.authenticate_client.return_value = False status_code = self.auth.create_token_response(self.request, bearer)[2] self.assertEqual(status_code, 401) self.assertEqual(self.mock_validator.save_token.call_count, 0) # mock client_authentication_required() returning False then fail self.mock_validator.reset_mock() self.mock_validator.client_authentication_required.return_value = False self.mock_validator.authenticate_client_id.return_value = False status_code = self.auth.create_token_response(self.request, bearer)[2] self.assertEqual(status_code, 401) self.assertEqual(self.mock_validator.save_token.call_count, 0)
def __init__(self, request_validator, token_generator=None, token_expires_in=None, refresh_token_generator=None, **kwargs): """Construct a client credentials grant server. :param request_validator: An implementation of oauthlib.oauth2.RequestValidator. :param token_expires_in: An int or a function to generate a token expiration offset (in seconds) given a oauthlib.common.Request object. :param token_generator: A function to generate a token from a request. :param refresh_token_generator: A function to generate a token from a request for the refresh token. :param kwargs: Extra parameters to pass to authorization-, token-, resource-, and revocation-endpoint constructors. """ self._params = {} refresh_grant = SocialTokenGrant(request_validator) bearer = BearerToken(request_validator, token_generator, token_expires_in, refresh_token_generator) TokenEndpoint.__init__(self, default_grant_type='convert_token', grant_types={ 'convert_token': refresh_grant, }, default_token_type=bearer)
def test_authorization(self, generate_token): scope, info = self.auth.validate_authorization_request(self.request) generate_token.return_value = 'abc' bearer = BearerToken(self.mock_validator) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertURLEqual(h['Location'], self.url_fragment, parse_fragment=True) self.assertEqual(b, None) self.assertEqual(s, 302) self.request.response_type = 'id_token' token = 'MOCKED_TOKEN' url = 'https://a.b/cb#state=abc&id_token=%s' % token h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertURLEqual(h['Location'], url, parse_fragment=True) self.assertEqual(b, None) self.assertEqual(s, 302) self.request.nonce = None h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location']) self.assertEqual(b, None) self.assertEqual(s, 302)
def test_estimate_type(self): request_validator = mock.MagicMock() request_validator.validate_bearer_token = self._mocked_validate_bearer_token request = Request("/", headers=self.bearer_headers) result = BearerToken( request_validator=request_validator).estimate_type(request) self.assertEqual(result, 9)
def test_none_multi_prompt(self): bearer = BearerToken(self.mock_validator) self.request.prompt = 'none login' self.assertRaises(errors.InvalidRequestError, self.auth.validate_authorization_request, self.request) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location']) self.request.prompt = 'none consent' self.assertRaises(errors.InvalidRequestError, self.auth.validate_authorization_request, self.request) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location']) self.request.prompt = 'none select_account' self.assertRaises(errors.InvalidRequestError, self.auth.validate_authorization_request, self.request) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location']) self.request.prompt = 'consent none login' self.assertRaises(errors.InvalidRequestError, self.auth.validate_authorization_request, self.request) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location'])
def test_lowercase_bearer_is_validated(self): request_validator = mock.MagicMock() request_validator.validate_bearer_token = self._mocked_validate_bearer_token request = Request("/", headers=self.valid_bearer_header_lowercase) result = BearerToken( request_validator=request_validator).validate_request(request) self.assertTrue(result)
def test_create_token_response(self): bearer = BearerToken(self.mock_validator) u, h, token, s = self.auth.create_token_response(self.request, bearer) token = json.loads(token) self.assertIn('access_token', token) self.assertIn('refresh_token', token) self.assertIn('expires_in', token) self.assertIn('scope', token)
def test_invalid_token(self): self.mock_validator.validate_refresh_token.return_value = False bearer = BearerToken(self.mock_validator) headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(token['error'], 'invalid_grant') self.assertEqual(status_code, 400)
def test_create_token_response(self): bearer = BearerToken(self.mock_validator) uri, headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertIn('access_token', token) self.assertIn('token_type', token) self.assertIn('expires_in', token)
def test_invalid_client(self): self.mock_validator.authenticate_client.return_value = False bearer = BearerToken(self.mock_validator) uri, headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(token['error'], 'invalid_client') self.assertEqual(status_code, 401)
def test_invalid_scope(self): self.mock_validator.get_original_scopes.return_value = ['baz'] bearer = BearerToken(self.mock_validator) uri, headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(token['error'], 'invalid_scope') self.assertEqual(status_code, 401)
def test_create_authorization_response(self, generate_token): generate_token.return_value = 'abc' bearer = BearerToken(self.mock_validator) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertURLEqual(h['Location'], 'https://a.b/cb?code=abc') self.request.response_mode = 'fragment' h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertURLEqual(h['Location'], 'https://a.b/cb#code=abc')
def test_create_authorization_grant(self): bearer = BearerToken(self.mock_validator) h, b, s = self.auth.create_authorization_response(self.request, bearer) grant = dict(Request(h['Location']).uri_query_params) self.assertIn('code', grant) self.assertTrue(self.mock_validator.validate_redirect_uri.called) self.assertTrue(self.mock_validator.validate_response_type.called) self.assertTrue(self.mock_validator.validate_scopes.called)
def test_create_token_response(self): bearer = BearerToken(self.mock_validator, expires_in=1800) orig_generate_token = common.generate_token self.addCleanup(setattr, common, 'generate_token', orig_generate_token) common.generate_token = lambda *args, **kwargs: '1234' uri, headers, body, status_code = self.auth.create_token_response( self.request, bearer) correct_uri = 'https://b.c/p#access_token=1234&token_type=Bearer&expires_in=1800&state=xyz&scope=hello+world' self.assertURLEqual(uri, correct_uri, parse_fragment=True)
def test_header_with_multispaces_is_validated(self): request_validator = mock.MagicMock() request_validator.validate_bearer_token = self._mocked_validate_bearer_token request = Request("/", headers=self.valid_header_with_multiple_spaces) result = BearerToken( request_validator=request_validator).validate_request(request) self.assertTrue(result)
def test_custom_token_validators(self): self.setup_validators() bearer = BearerToken(self.mock_validator) self.auth.create_token_response(self.request, bearer) self.assertTrue(self.tknval1.called) self.assertTrue(self.tknval2.called) self.assertFalse(self.authval1.called) self.assertFalse(self.authval2.called)
def test_custom_token_validators(self): tknval1, tknval2 = mock.Mock(), mock.Mock() self.auth.custom_validators.pre_token.append(tknval1) self.auth.custom_validators.post_token.append(tknval2) bearer = BearerToken(self.mock_validator) self.auth.create_token_response(self.request, bearer) self.assertTrue(tknval1.called) self.assertTrue(tknval2.called)
def test_create_cors_headers_invalid_origin(self): bearer = BearerToken(self.mock_validator) self.request.headers['origin'] = 'https://foo.bar' self.mock_validator.is_origin_allowed.return_value = False headers = self.auth.create_token_response(self.request, bearer)[0] self.assertNotIn('Access-Control-Allow-Origin', headers) self.mock_validator.is_origin_allowed.assert_called_once_with( 'abcdef', 'https://foo.bar', self.request)
def test_invalid_scope(self): self.mock_validator.get_original_scopes.return_value = ['baz'] self.mock_validator.is_within_original_scope.return_value = False bearer = BearerToken(self.mock_validator) headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertEqual(self.mock_validator.save_token.call_count, 0) self.assertEqual(token['error'], 'invalid_scope') self.assertEqual(status_code, 400)
def test_fake_bearer_is_not_validated(self): request_validator = mock.MagicMock() request_validator.validate_bearer_token = self._mocked_validate_bearer_token for fake_header in self.fake_bearer_headers: request = Request("/", headers=fake_header) result = BearerToken( request_validator=request_validator).validate_request(request) self.assertFalse(result)
def test_optional_nonce(self, generate_token): generate_token.return_value = 'abc' self.request.nonce = 'xyz' scope, info = self.auth.validate_authorization_request(self.request) bearer = BearerToken(self.mock_validator) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertURLEqual(h['Location'], self.url_fragment, parse_fragment=True) self.assertIsNone(b) self.assertEqual(s, 302)
def test_create_token_response(self): self.mock_validator.get_original_scopes.return_value = ['foo', 'bar'] bearer = BearerToken(self.mock_validator) uri, headers, body, status_code = self.auth.create_token_response( self.request, bearer) token = json.loads(body) self.assertIn('access_token', token) self.assertIn('token_type', token) self.assertIn('expires_in', token) self.assertEqual(token['scope'], 'foo')
def test_required_nonce(self, generate_token): generate_token.return_value = 'abc' self.request.nonce = None self.assertRaises(errors.InvalidRequestError, self.auth.validate_authorization_request, self.request) bearer = BearerToken(self.mock_validator) h, b, s = self.auth.create_authorization_response(self.request, bearer) self.assertIn('error=invalid_request', h['Location']) self.assertIsNone(b) self.assertEqual(s, 302)