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 __init__(self, request_validator, db_session, user_info_provider, signature_alg='HS256', signature_key=None, signature_kid=None, namespace=uuid.UUID('66deca4c-4e8a-44ce-a617-3d37bc0bcfaa'), *args, **kwargs): BearerToken.__init__(self, request_validator, *args, **kwargs) self.db_session = db_session self.user_info_provider = user_info_provider self.namespace = namespace self.signature_alg = signature_alg self.signature_key = signature_key self.signature_kid = signature_kid
def create_access_token(self, request, user, scope, client): """ Create and return a new access token. """ _days = 24 * 60 * 60 token_generator = BearerToken( expires_in=settings.OAUTH_EXPIRE_PUBLIC_CLIENT_DAYS * _days, request_validator=oauth2_settings.OAUTH2_VALIDATOR_CLASS(), ) self._populate_create_access_token_request(request, user, scope, client) return token_generator.create_token(request, refresh_token=True)
def test_create_token_response_without_refresh_token(self): # self.auth.refresh_token = False so we don't generate a refresh token self.auth = ExternalTokenGrant( 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 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 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 __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 __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 setUp(self): self.mock_validator = mock.MagicMock() 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 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 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_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) 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_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_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_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_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_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_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_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_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_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_error_response(self): bearer = BearerToken(self.mock_validator) self.mock_validator.authenticate_client.return_value = False headers, body, status_code = self.auth.create_token_response( self.request, bearer) error_msg = json.loads(body) self.assertIn('error', error_msg) self.assertEqual(error_msg['error'], 'invalid_client') self.assertIn('Content-Type', headers) self.assertEqual(headers['Content-Type'], 'application/json')
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_query) self.assertEqual(b, None) 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 create_dot_access_token(request, user, client, expires_in=None, scopes=None): """ Create and return a new (persisted) access token, including a refresh token. The token is returned in the form of a Dict: { u'access_token': u'some string', u'refresh_token': u'another string', u'token_type': u'Bearer', u'expires_in': 36000, u'scope': u'profile email', }, """ expires_in = _get_expires_in_value(expires_in) token_generator = BearerToken( expires_in=expires_in, request_validator=dot_settings.OAUTH2_VALIDATOR_CLASS(), ) _populate_create_access_token_request(request, user, client, scopes) return token_generator.create_token(request, refresh_token=True)
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_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)
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): bearer = BearerToken(self.mock_validator) 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.assertIn('Content-Type', headers) self.assertEqual(headers['Content-Type'], 'application/json')
def create_access_token(self, user, oauth_client): class RequestValidator(object): def save_bearer_token(self, token, request): print token return Token.set_for_oauth2(token, request) validator = RequestValidator() bearer_token_generator = BearerToken(request_validator=validator, expires_in=3600) class RequestMock(object): scopes = ['admin'] state = '123' extra_credentials = None def __init__(self, user, client): self.user = user self.client = client request = RequestMock(user=user, client=oauth_client) token = bearer_token_generator.create_token(request, refresh_token=True) return token['access_token']
def __init__(self, request_validator, signature_key=None, signature_alg='HS256', *args, **kwargs): BearerToken.__init__(self, request_validator, *args, **kwargs) self.signature_key = signature_key self.signature_alg = signature_alg