def test_required_roles(self): """ Validates whether the required_roles decorator works """ from api.backend.decorators import required_roles @required_roles(['read', 'write', 'manage']) def the_function_rr(input_value, *args, **kwargs): """ Decorated function """ _ = args, kwargs output['value'] = input_value return HttpResponse(json.dumps(input_value)) time.sleep(180) output = {'value': None} request = self.factory.get('/') with self.assertRaises(HttpUnauthorizedException) as context: the_function_rr(1, request) self.assertEqual(context.exception.status_code, 401) time.sleep(180) request.client = type('Client', (), {}) request.user = type('User', (), {}) request.user.username = '******' with self.assertRaises(HttpUnauthorizedException) as context: the_function_rr(2, request) self.assertEqual(context.exception.status_code, 401) time.sleep(180) user = UserList.get_user_by_username('user') access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.user.username = '******' request.token = access_token with self.assertRaises(HttpForbiddenException) as context: the_function_rr(3, request) self.assertEqual(context.exception.status_code, 403) self.assertEqual(context.exception.error, 'invalid_roles') self.assertEqual(context.exception.error_description, 'This call requires roles: read, write, manage') time.sleep(180) user = UserList.get_user_by_username('admin') access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read', 'write', 'manage'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.username = '******' request.token = access_token response = the_function_rr(4, request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '4')
def test_client_credentials(self): """ Validates the Client Credentials """ from api.oauth2.tokenview import OAuth2TokenView time.sleep(180) data = {'grant_type': 'client_credentials'} request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'missing_header', HttpBadRequestException) time.sleep(180) header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format('foo', 'bar'))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.2', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_client', HttpBadRequestException) time.sleep(180) admin_na = UserList.get_user_by_username('admin_na') admin_na_client = Client() admin_na_client.ovs_type = 'USER' admin_na_client.grant_type = 'PASSWORD' admin_na_client.client_secret = OAuth2Toolbox.create_hash(64) admin_na_client.user = admin_na admin_na_client.save() header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format(admin_na_client.guid, admin_na_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.3', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_grant', HttpBadRequestException) time.sleep(180) admin_na_client.grant_type = 'CLIENT_CREDENTIALS' admin_na_client.save() request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.4', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'inactive_user', HttpBadRequestException) time.sleep(180) admin = UserList.get_user_by_username('admin') admin_client = Client() admin_client.ovs_type = 'USER' admin_client.grant_type = 'CLIENT_CREDENTIALS' admin_client.client_secret = OAuth2Toolbox.create_hash(64) admin_client.user = admin admin_client.save() header = 'Basic {0}'.format(base64.encodestring('{0}:foobar'.format(admin_client.guid))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.5', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_client', HttpBadRequestException) time.sleep(180) header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format(admin_client.guid, admin_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.6', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) self.assertEqual(response.status_code, 200) response_content = json.loads(response.content) self.assertIn('access_token', response_content) result = {'access_token': response_content['access_token'], 'token_type': 'bearer', 'expires_in': 3600} self.assertDictEqual(response_content, result)
def test_client_credentials(self): """ Validates the Client Credentials """ from oauth2.tokenview import OAuth2TokenView data = {'grant_type': 'client_credentials'} request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) # Fails because the HTTP_AUTHORIZATION header is missing self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'missing_header'})) header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format('foo', 'bar'))) request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because there is no such client self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'invalid_client'})) admin_na = UserList.get_user_by_username('admin_na') admin_na_client = Client() admin_na_client.ovs_type = 'USER' admin_na_client.grant_type = 'PASSWORD' admin_na_client.client_secret = OAuth2Toolbox.create_hash(64) admin_na_client.user = admin_na admin_na_client.save() header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format(admin_na_client.guid, admin_na_client.client_secret))) request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because the grant is of type Resource Owner Password Credentials self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'invalid_grant'})) admin_na_client.grant_type = 'CLIENT_CREDENTIALS' admin_na_client.save() request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because the grant is of type Resource Owner Password Credentials self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'inactive_user'})) admin = UserList.get_user_by_username('admin') admin_client = Client() admin_client.ovs_type = 'USER' admin_client.grant_type = 'CLIENT_CREDENTIALS' admin_client.client_secret = OAuth2Toolbox.create_hash(64) admin_client.user = admin admin_client.save() header = 'Basic {0}'.format(base64.encodestring('{0}:{1}'.format(admin_client.guid, admin_client.client_secret))) request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Succeeds self.assertEqual(response.status_code, 200) response_content = json.loads(response.content) self.assertIn('access_token', response_content) result = {'access_token': response_content['access_token'], 'token_type': 'bearer', 'expires_in': 3600} self.assertDictEqual(response_content, result)
def test_required_roles(self): """ Validates whether the required_roles decorator works """ from api.backend.decorators import required_roles @required_roles(['read', 'write', 'manage']) def the_function_rr(input_value, *args, **kwargs): """ Decorated function """ _ = args, kwargs output['value'] = input_value return HttpResponse(json.dumps(input_value)) time.sleep(180) output = {'value': None} request = self.factory.get('/') with self.assertRaises(HttpUnauthorizedException) as context: the_function_rr(1, request) self.assertEqual(context.exception.status_code, 401) time.sleep(180) request.client = type('Client', (), {}) request.user = type('User', (), {}) request.user.username = '******' with self.assertRaises(HttpUnauthorizedException) as context: the_function_rr(2, request) self.assertEqual(context.exception.status_code, 401) time.sleep(180) user = UserList.get_user_by_username('user') access_token, _ = OAuth2Toolbox.generate_tokens(user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.user.username = '******' request.token = access_token with self.assertRaises(HttpForbiddenException) as context: the_function_rr(3, request) self.assertEqual(context.exception.status_code, 403) self.assertEqual(context.exception.error, 'invalid_roles') self.assertEqual(context.exception.error_description, 'This call requires roles: read, write, manage') time.sleep(180) user = UserList.get_user_by_username('admin') access_token, _ = OAuth2Toolbox.generate_tokens(user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read', 'write', 'manage'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.username = '******' request.token = access_token response = the_function_rr(4, request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '4')
def test_required_roles(self): """ Validates whether the required_roles decorator works """ from backend.decorators import required_roles from rest_framework.exceptions import NotAuthenticated, PermissionDenied @required_roles(['read', 'write', 'manage']) def the_function(input_value, *args, **kwargs): """ Decorated function """ _ = args, kwargs output['value'] = input_value return HttpResponse(json.dumps(input_value)) output = {'value': None} user = UserList.get_user_by_username('user') request = self.factory.get('/') with self.assertRaises(NotAuthenticated) as context: the_function(1, request) self.assertEqual(context.exception.status_code, 401) request.client = type('Client', (), {}) request.user = type('User', (), {}) request.user.username = '******' with self.assertRaises(NotAuthenticated) as context: the_function(2, request) self.assertEqual(context.exception.status_code, 401) access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.user.username = '******' request.token = access_token with self.assertRaises(PermissionDenied) as context: the_function(3, request) self.assertEqual(context.exception.status_code, 403) self.assertEqual(context.exception.detail, 'This call requires roles: read, write, manage') user = UserList.get_user_by_username('admin') access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read', 'write', 'manage'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.username = '******' request.token = access_token response = the_function(4, request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '4')
def test_required_roles(self): """ Validates whether the required_roles decorator works """ from backend.decorators import required_roles from rest_framework.exceptions import NotAuthenticated, PermissionDenied @required_roles(["read", "write", "manage"]) def the_function(input_value, *args, **kwargs): """ Decorated function """ _ = args, kwargs output["value"] = input_value return HttpResponse(json.dumps(input_value)) output = {"value": None} user = UserList.get_user_by_username("user") request = Decorators.factory.get("/") with self.assertRaises(NotAuthenticated) as context: the_function(1, request) self.assertEqual(context.exception.status_code, 401) request.client = type("Client", (), {}) request.user = type("User", (), {}) request.user.username = "******" with self.assertRaises(NotAuthenticated) as context: the_function(2, request) self.assertEqual(context.exception.status_code, 401) access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(["read"]) ) access_token.expiration = int(time.time() + 86400) access_token.save() request.user.username = "******" request.token = access_token with self.assertRaises(PermissionDenied) as context: the_function(3, request) self.assertEqual(context.exception.status_code, 403) self.assertEqual(context.exception.detail, "This call requires roles: read, write, manage") user = UserList.get_user_by_username("admin") access_token, _ = OAuth2Toolbox.generate_tokens( user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(["read", "write", "manage"]) ) access_token.expiration = int(time.time() + 86400) access_token.save() request.username = "******" request.token = access_token response = the_function(4, request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, "4")
def post(self, request, *args, **kwargs): """ Handles token post """ _ = args, kwargs if 'grant_type' not in request.POST: return HttpResponseBadRequest, {'error': 'invalid_request'} grant_type = request.POST['grant_type'] scopes = None if 'scope' in request.POST: scopes = RoleList.get_roles_by_codes(request.POST['scope'].split(' ')) if grant_type == 'password': # Resource Owner Password Credentials Grant if 'username' not in request.POST or 'password' not in request.POST: return HttpResponseBadRequest, {'error': 'invalid_request'} username = request.POST['username'] password = request.POST['password'] user = UserList.get_user_by_username(username) if user is None or user.password != hashlib.sha256(password).hexdigest(): return HttpResponseBadRequest, {'error': 'invalid_client'} if user.is_active is False: return HttpResponseBadRequest, {'error': 'inactive_user'} clients = [client for client in user.clients if client.ovs_type == 'FRONTEND' and client.grant_type == 'PASSWORD'] if len(clients) != 1: return HttpResponseBadRequest, {'error': 'unauthorized_client'} client = clients[0] try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) access_token.expiration = int(time.time() + 86400) access_token.save() except ValueError as error: return HttpResponseBadRequest, {'error': str(error)} Toolbox.clean_tokens(client) return HttpResponse, {'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 86400} elif grant_type == 'client_credentials': # Client Credentials if 'HTTP_AUTHORIZATION' not in request.META: return HttpResponseBadRequest, {'error': 'missing_header'} _, password_hash = request.META['HTTP_AUTHORIZATION'].split(' ') client_id, client_secret = base64.decodestring(password_hash).split(':', 1) try: client = Client(client_id) if client.grant_type != 'CLIENT_CREDENTIALS': return HttpResponseBadRequest, {'error': 'invalid_grant'} if not client.user.is_active: return HttpResponseBadRequest, {'error': 'inactive_user'} try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) except ValueError as error: return HttpResponseBadRequest, {'error': str(error)} Toolbox.clean_tokens(client) return HttpResponse, {'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 3600} except: return HttpResponseBadRequest, {'error': 'invalid_client'} else: return HttpResponseBadRequest, {'error': 'unsupported_grant_type'}
def create(self, request): """ Creates a User :param request: The raw request :type request: Request """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) user = serializer.deserialize() if UserList.get_user_by_username(user.username) is not None: raise HttpNotAcceptableException(error_description='User with this username already exists', error='duplicate') user.save() pw_client = Client() pw_client.ovs_type = 'INTERNAL' pw_client.grant_type = 'PASSWORD' pw_client.user = user pw_client.save() cc_client = Client() cc_client.ovs_type = 'INTERNAL' cc_client.grant_type = 'CLIENT_CREDENTIALS' cc_client.client_secret = ''.join(random.choice(string.ascii_letters + string.digits + '|_=+*#@!/-[]{}<>.?,\'";:~') for _ in range(128)) cc_client.user = user cc_client.save() for junction in user.group.roles: for client in [cc_client, pw_client]: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() return user
def create(self, request): """ Creates a User :param request: The raw request :type request: Request """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) user = serializer.deserialize() if UserList.get_user_by_username(user.username) is not None: raise HttpNotAcceptableException(error='duplicate', error_description='User with this username already exists') user.save() pw_client = Client() pw_client.ovs_type = 'INTERNAL' pw_client.grant_type = 'PASSWORD' pw_client.user = user pw_client.save() cc_client = Client() cc_client.ovs_type = 'INTERNAL' cc_client.grant_type = 'CLIENT_CREDENTIALS' cc_client.client_secret = ''.join(random.choice(string.ascii_letters + string.digits + '|_=+*#@!/-[]{}<>.?,\'";:~') for _ in range(128)) cc_client.user = user cc_client.save() for junction in user.group.roles: for client in [cc_client, pw_client]: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() return user
def create(self, request): """ Creates a User """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) if serializer.is_valid(): user = serializer.object if UserList.get_user_by_username(user.username) is not None: return Response('User already exists', status=status.HTTP_303_SEE_OTHER) user.save() pw_client = Client() pw_client.ovs_type = 'INTERNAL' pw_client.grant_type = 'PASSWORD' pw_client.user = user pw_client.save() cc_client = Client() cc_client.ovs_type = 'INTERNAL' cc_client.grant_type = 'CLIENT_CREDENTIALS' cc_client.client_secret = ''.join(random.choice(string.ascii_letters + string.digits + '|_=+*#@!/-[]{}<>.?,\'";:~') for _ in range(128)) cc_client.user = user cc_client.save() for junction in user.group.roles: for client in [cc_client, pw_client]: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() serializer = FullSerializer(User, instance=user) return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def new_function(*args, **kw): """ Wrapped function """ start = time.time() request = _find_request(args) if not hasattr(request, 'user') or not hasattr(request, 'client'): raise HttpUnauthorizedException( error_description='Not authenticated', error='not_authenticated') user = UserList.get_user_by_username(request.user.username) if user is None: raise HttpUnauthorizedException( error_description='Not authenticated', error='not_authenticated') if not ApiToolbox.is_token_in_roles(request.token, roles): raise HttpForbiddenException( error_description='This call requires roles: {0}'.format( ', '.join(roles)), error='invalid_roles') duration = time.time() - start result = f(*args, **kw) if isinstance(result, OVSResponse): result.timings['security'] = [duration, 'Security'] return result
def test_required_roles(self): """ Validates whether the required_roles decorator works """ from backend.decorators import required_roles from rest_framework.exceptions import NotAuthenticated, PermissionDenied @required_roles(['read', 'write', 'manage']) def the_function(input_value, *args, **kwargs): """ Decorated function """ _ = args, kwargs output['value'] = input_value return HttpResponse(json.dumps(input_value)) output = {'value': None} user = UserList.get_user_by_username('user') request = self.factory.get('/') with self.assertRaises(NotAuthenticated) as context: the_function(1, request) self.assertEqual(context.exception.status_code, 401) request.client = type('Client', (), {}) request.user = type('User', (), {}) request.user.username = '******' with self.assertRaises(NotAuthenticated) as context: the_function(2, request) self.assertEqual(context.exception.status_code, 401) access_token, _ = OAuth2Toolbox.generate_tokens(user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.user.username = '******' request.token = access_token with self.assertRaises(PermissionDenied) as context: the_function(3, request) self.assertEqual(context.exception.status_code, 403) self.assertEqual(context.exception.detail, 'This call requires roles: read, write, manage') user = UserList.get_user_by_username('admin') access_token, _ = OAuth2Toolbox.generate_tokens(user.clients[0], generate_access=True, scopes=RoleList.get_roles_by_codes(['read', 'write', 'manage'])) access_token.expiration = int(time.time() + 86400) access_token.save() request.username = '******' request.token = access_token response = the_function(4, request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '4')
def test_authentication_backend(self): """ Validates the Authentication backend """ from django.contrib.auth.models import User as DUser from api.oauth2.tokenview import OAuth2TokenView from api.oauth2.backend import OAuth2Backend time.sleep(180) backend = OAuth2Backend() data = { 'grant_type': 'password', 'username': '******', 'password': '******' } request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) response_content = json.loads(response.content) access_token = response_content['access_token'] request = self.factory.get('/') response = backend.authenticate(request) self.assertIsNone(response) time.sleep(180) header = 'Bearer foobar' request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'invalid_token') time.sleep(180) header = 'Bearer {0}'.format(access_token) request = self.factory.get('/', HTTP_AUTHORIZATION=header) user, extra = backend.authenticate(request) self.assertIsInstance(user, DUser) self.assertIsNone(extra) self.assertEqual(request.token.access_token, access_token) self.assertEqual(request.client.user.username, 'admin') time.sleep(180) user = UserList.get_user_by_username('admin') user.is_active = False user.save() request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'inactive_user') user.is_active = True user.save() time.sleep(int(response_content['expires_in'])) request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'token_expired')
def test_authentication_backend(self): """ Validates the Authentication backend """ from django.contrib.auth.models import User as DUser from api.oauth2.tokenview import OAuth2TokenView from api.oauth2.backend import OAuth2Backend time.sleep(180) backend = OAuth2Backend() data = {'grant_type': 'password', 'username': '******', 'password': '******'} request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) response_content = json.loads(response.content) access_token = response_content['access_token'] request = self.factory.get('/') response = backend.authenticate(request) self.assertIsNone(response) time.sleep(180) header = 'Bearer foobar' request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'invalid_token') time.sleep(180) header = 'Bearer {0}'.format(access_token) request = self.factory.get('/', HTTP_AUTHORIZATION=header) user, extra = backend.authenticate(request) self.assertIsInstance(user, DUser) self.assertIsNone(extra) self.assertEqual(request.token.access_token, access_token) self.assertEqual(request.client.user.username, 'admin') time.sleep(180) user = UserList.get_user_by_username('admin') user.is_active = False user.save() request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'inactive_user') user.is_active = True user.save() time.sleep(int(response_content['expires_in'])) request = self.factory.get('/', HTTP_AUTHORIZATION=header) with self.assertRaises(HttpUnauthorizedException) as context: backend.authenticate(request) self.assertEqual(context.exception.status_code, 401) self.assertEqual(str(context.exception.error), 'token_expired')
def new_function(*args, **kw): """ Wrapped function """ request = _find_request(args) if not hasattr(request, 'user') or not hasattr(request, 'client'): raise NotAuthenticated() user = UserList.get_user_by_username(request.user.username) if user is None: raise NotAuthenticated() if not Toolbox.is_token_in_roles(request.token, roles): raise PermissionDenied('This call requires roles: %s' % (', '.join(roles))) return f(*args, **kw)
def new_function(*args, **kw): """ Wrapped function """ request = args[1] if not hasattr(request, 'user') or not hasattr(request, 'client'): raise NotAuthenticated() user = UserList.get_user_by_username(request.user.username) if user is None: raise NotAuthenticated() if not Toolbox.is_token_in_roles(request.token, roles): raise PermissionDenied('This call requires roles: %s' % (', '.join(roles))) return f(*args, **kw)
def new_function(*args, **kw): """ Wrapped function """ request = _find_request(args) if not hasattr(request, 'user') or not hasattr(request, 'client'): raise HttpUnauthorizedException(error_description='Not authenticated', error='not_authenticated') user = UserList.get_user_by_username(request.user.username) if user is None: raise HttpUnauthorizedException(error_description='Not authenticated', error='not_authenticated') if not Toolbox.is_token_in_roles(request.token, roles): raise HttpForbiddenException(error_description='This call requires roles: {0}'.format(', '.join(roles)), error='invalid_roles') return f(*args, **kw)
def user(): admin = UserList.get_user_by_username('admin') alba_client = None alba_secret = None clients = admin.clients for client in clients: if client.name == 'alba': alba_client = client.client_id alba_secret = client.client_secret if alba_client is None: return {'error': 'user not found'} return {'client': alba_client, 'secret': alba_secret}
def user(): admin = UserList.get_user_by_username("admin") alba_client = None alba_secret = None clients = admin.clients for client in clients: if client.name == "alba": alba_client = client.client_id alba_secret = client.client_secret if alba_client is None: return {"error": "user not found"} return {"client": alba_client, "secret": alba_secret}
def new_function(*args, **kw): """ Wrapped function """ request = _find_request(args) if not hasattr(request, 'user') or not hasattr(request, 'client'): raise HttpUnauthorizedException( error_description='Not authenticated', error='not_authenticated') user = UserList.get_user_by_username(request.user.username) if user is None: raise HttpUnauthorizedException( error_description='Not authenticated', error='not_authenticated') if not Toolbox.is_token_in_roles(request.token, roles): raise HttpForbiddenException( error_description='This call requires roles: {0}'.format( ', '.join(roles)), error='invalid_roles') return f(*args, **kw)
def user(): admin = UserList.get_user_by_username("admin") print "[+] admin guid: %s" % admin.guid alba_client = None alba_secret = None clients = admin.clients for client in clients: if client.name == "alba": alba_client = client.client_id alba_secret = client.client_secret print "[+] alba client already set" if alba_client is None: print '[+] adding "alba" oauth2 client' choice = string.ascii_letters + string.digits # Creating user alclient = Client() alclient.ovs_type = "USER" alclient.name = "alba" alclient.grant_type = "CLIENT_CREDENTIALS" alclient.client_secret = "".join( random.choice(choice) for _ in range(64)) alclient.user = admin alclient.save() # Adding roles for junction in admin.group.roles: roleclient = RoleClient() roleclient.client = alclient roleclient.role = junction.role roleclient.save() alba_client = alclient.client_id alba_secret = alclient.client_secret return {"client_id": alba_client, "client_secret": alba_secret}
def create(self, request): """ Creates a User """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) if serializer.is_valid(): user = serializer.object if UserList.get_user_by_username(user.username) is not None: return Response('User already exists', status=status.HTTP_303_SEE_OTHER) user.save() pw_client = Client() pw_client.ovs_type = 'INTERNAL' pw_client.grant_type = 'PASSWORD' pw_client.user = user pw_client.save() cc_client = Client() cc_client.ovs_type = 'INTERNAL' cc_client.grant_type = 'CLIENT_CREDENTIALS' cc_client.client_secret = ''.join( random.choice(string.ascii_letters + string.digits + '|_=+*#@!/-[]{}<>.?,\'";:~') for _ in range(128)) cc_client.user = user cc_client.save() for junction in user.group.roles: for client in [cc_client, pw_client]: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() serializer = FullSerializer(User, instance=user) return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def create(self, request): """ Creates a User """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) if serializer.is_valid(): user = serializer.object if UserList.get_user_by_username(user.username) is not None: return Response('User already exists', status=status.HTTP_303_SEE_OTHER) user.save() client = Client() client.ovs_type = 'FRONTEND' client.grant_type = 'PASSWORD' client.user = user client.save() for junction in user.group.roles: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() serializer = FullSerializer(User, instance=user) return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def test_metadata(self): """ Validates the authentication related information at the API root's metadata. - The 'roles' key is already checked in the Scope-related tests """ from ovs.dal.lists.bearertokenlist import BearerTokenList from api.oauth2.tokenview import OAuth2TokenView from api.view import MetadataView def _raise_exception(argument): _ = argument raise RuntimeError('foobar') result_data = { 'authenticated': False, 'authentication_state': None, 'username': None, 'userguid': None } time.sleep(180) data = { 'grant_type': 'password', 'username': '******', 'password': '******' } request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) response_content = json.loads(response.content) self.assertIn('expires_in', response_content) self.assertIn('access_token', response_content) time.sleep(180) expiry = int(response_content['expires_in']) access_token = response_content['access_token'] request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1') response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'unauthenticated'}.items()), response_content) time.sleep(180) header = 'Basic foobar' request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'invalid_authorization_type' }.items()), response_content) time.sleep(180) header = 'Bearer foobar' request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'invalid_token'}.items()), response_content) time.sleep(180) user = UserList.get_user_by_username('admin') header = 'Bearer {0}'.format(access_token) request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict( result_data.items() + { 'authenticated': True, 'authentication_state': 'authenticated', 'username': user.username, 'userguid': user.guid }.items()), response_content) time.sleep(180) user.is_active = False user.save() request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'inactive_user'}.items()), response_content) user.is_active = True user.save() time.sleep(180) original_method = BearerTokenList.get_by_access_token BearerTokenList.get_by_access_token = staticmethod(_raise_exception) request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'unexpected_exception'}.items()), response_content) time.sleep(180) BearerTokenList.get_by_access_token = staticmethod(original_method) time.sleep(expiry) request = self.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset( dict(result_data.items() + {'authentication_state': 'token_expired'}.items()), response_content)
def test_client_credentials(self): """ Validates the Client Credentials """ from api.oauth2.tokenview import OAuth2TokenView time.sleep(180) data = {'grant_type': 'client_credentials'} request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'missing_header', HttpBadRequestException) time.sleep(180) header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format('foo', 'bar'))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.2', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_client', HttpBadRequestException) time.sleep(180) admin_na = UserList.get_user_by_username('admin_na') admin_na_client = Client() admin_na_client.ovs_type = 'USER' admin_na_client.grant_type = 'PASSWORD' admin_na_client.client_secret = OAuth2Toolbox.create_hash(64) admin_na_client.user = admin_na admin_na_client.save() header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format( admin_na_client.guid, admin_na_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.3', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_grant', HttpBadRequestException) time.sleep(180) admin_na_client.grant_type = 'CLIENT_CREDENTIALS' admin_na_client.save() request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.4', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'inactive_user', HttpBadRequestException) time.sleep(180) admin = UserList.get_user_by_username('admin') admin_client = Client() admin_client.ovs_type = 'USER' admin_client.grant_type = 'CLIENT_CREDENTIALS' admin_client.client_secret = OAuth2Toolbox.create_hash(64) admin_client.user = admin admin_client.save() header = 'Basic {0}'.format( base64.encodestring('{0}:foobar'.format(admin_client.guid))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.5', HTTP_AUTHORIZATION=header) self._assert_failure(OAuth2TokenView.as_view(), request, 400, 'invalid_client', HttpBadRequestException) time.sleep(180) header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format(admin_client.guid, admin_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.6', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) self.assertEqual(response.status_code, 200) response_content = json.loads(response.content) self.assertIn('access_token', response_content) result = { 'access_token': response_content['access_token'], 'token_type': 'bearer', 'expires_in': 3600 } self.assertDictEqual(response_content, result)
def post(self, request, *args, **kwargs): """ Handles token post """ logger = LogHandler.get('api', 'oauth2') _ = args, kwargs if 'grant_type' not in request.POST: raise HttpBadRequestException(error='invalid_request', error_description='No grant type specified') grant_type = request.POST['grant_type'] scopes = None if 'scope' in request.POST: scopes = RoleList.get_roles_by_codes(request.POST['scope'].split(' ')) if grant_type == 'password': # Resource Owner Password Credentials Grant if 'username' not in request.POST or 'password' not in request.POST: raise HttpBadRequestException(error='invalid_request', error_description='Invalid request') username = request.POST['username'] password = request.POST['password'] user = UserList.get_user_by_username(username) if user is None or user.password != hashlib.sha256(password).hexdigest(): raise HttpBadRequestException(error='invalid_client', error_description='Invalid client') if user.is_active is False: raise HttpBadRequestException(error='inactive_user', error_description='User is inactive') clients = [client for client in user.clients if client.ovs_type == 'INTERNAL' and client.grant_type == 'PASSWORD'] if len(clients) != 1: raise HttpBadRequestException(error='unauthorized_client', error_description='Client is unautorized') client = clients[0] try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) access_token.expiration = int(time.time() + 86400) access_token.save() except ValueError as error: if error.message == 'invalid_scope': raise HttpBadRequestException(error='invalid_scope', error_description='Invalid scope requested') raise Toolbox.clean_tokens(client) return HttpResponse(json.dumps({'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 86400}), content_type='application/json') elif grant_type == 'client_credentials': # Client Credentials if 'HTTP_AUTHORIZATION' not in request.META: raise HttpBadRequestException(error='missing_header', error_description='Authorization header missing') _, password_hash = request.META['HTTP_AUTHORIZATION'].split(' ') client_id, client_secret = base64.b64decode(password_hash).split(':', 1) try: client = Client(client_id) if client.grant_type != 'CLIENT_CREDENTIALS': raise HttpBadRequestException(error='invalid_grant', error_description='The given grant type is not supported') if client.client_secret != client_secret: raise HttpBadRequestException(error='invalid_client', error_description='Invalid client') if not client.user.is_active: raise HttpBadRequestException(error='inactive_user', error_description='User is inactive') try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) except ValueError as error: if error.message == 'invalid_scope': raise HttpBadRequestException(error='invalid_scope', error_description='Invalid scope requested') raise try: Toolbox.clean_tokens(client) except Exception as error: logger.error('Error during session cleanup: {0}'.format(error)) return HttpResponse(json.dumps({'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 3600}), content_type='application/json') except HttpBadRequestException: raise except ObjectNotFoundException as ex: logger.warning('Error matching client: {0}'.format(ex)) raise HttpBadRequestException(error='invalid_client', error_description='Client could not be found') except Exception as ex: logger.exception('Error matching client: {0}'.format(ex)) raise HttpBadRequestException(error='invalid_client', error_description='Error loading client') else: raise HttpBadRequestException(error='unsupported_grant_type', error_description='Unsupported grant type')
def post(self, request, *args, **kwargs): """ Handles token post """ logger = LogHandler.get('api', 'oauth2') _ = args, kwargs if 'grant_type' not in request.POST: return HttpResponseBadRequest, {'error': 'invalid_request'} grant_type = request.POST['grant_type'] scopes = None if 'scope' in request.POST: scopes = RoleList.get_roles_by_codes(request.POST['scope'].split(' ')) if grant_type == 'password': # Resource Owner Password Credentials Grant if 'username' not in request.POST or 'password' not in request.POST: return HttpResponseBadRequest, {'error': 'invalid_request'} username = request.POST['username'] password = request.POST['password'] user = UserList.get_user_by_username(username) if user is None or user.password != hashlib.sha256(password).hexdigest(): return HttpResponseBadRequest, {'error': 'invalid_client'} if user.is_active is False: return HttpResponseBadRequest, {'error': 'inactive_user'} clients = [client for client in user.clients if client.ovs_type == 'INTERNAL' and client.grant_type == 'PASSWORD'] if len(clients) != 1: return HttpResponseBadRequest, {'error': 'unauthorized_client'} client = clients[0] try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) access_token.expiration = int(time.time() + 86400) access_token.save() except ValueError as error: return HttpResponseBadRequest, {'error': str(error)} Toolbox.clean_tokens(client) return HttpResponse, {'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 86400} elif grant_type == 'client_credentials': # Client Credentials if 'HTTP_AUTHORIZATION' not in request.META: return HttpResponseBadRequest, {'error': 'missing_header'} _, password_hash = request.META['HTTP_AUTHORIZATION'].split(' ') client_id, client_secret = base64.b64decode(password_hash).split(':', 1) try: client = Client(client_id) if client.grant_type != 'CLIENT_CREDENTIALS': return HttpResponseBadRequest, {'error': 'invalid_grant'} if client.client_secret != client_secret: return HttpResponseBadRequest, {'error': 'invalid_client'} if not client.user.is_active: return HttpResponseBadRequest, {'error': 'inactive_user'} try: access_token, _ = Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) except ValueError as error: return HttpResponseBadRequest, {'error': str(error)} try: Toolbox.clean_tokens(client) except Exception as error: logger.error('Error during session cleanup: {0}'.format(error)) return HttpResponse, {'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 3600} except Exception as ex: logger.exception('Error matching client: {0}'.format(ex)) return HttpResponseBadRequest, {'error': 'invalid_client'} else: return HttpResponseBadRequest, {'error': 'unsupported_grant_type'}
def test_load(self): """ Validates whether the load decorator works """ from backend.decorators import load from rest_framework.exceptions import NotAcceptable from django.http import Http404 @load(User, min_version=2, max_version=2) def the_function_1(input_value, request, user, version, mandatory, optional="default"): """ Decorated function """ output["value"] = { "request": request, "mandatory": mandatory, "optional": optional, "version": version, "user": user, } return HttpResponse(json.dumps(input_value)) @load(User) def the_function_2(input_value, request, user, pk, version): """ Decorated function """ output["value"] = {"request": request, "user": user, "pk": pk, "version": version} return HttpResponse(json.dumps(input_value)) output = {"value": None} user = UserList.get_user_by_username("user") request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=1") with self.assertRaises(NotAcceptable) as context: the_function_1(1, request) self.assertEqual(context.exception.status_code, 406) self.assertEqual( context.exception.detail, "API version requirements: {0} <= <version> <= {1}. Got {2}".format(2, 2, 1) ) request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=*") with self.assertRaises(Http404): the_function_1(2, request, pk=str(uuid.uuid4())) request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=*") request.DATA = {} request.QUERY_PARAMS = {} with self.assertRaises(NotAcceptable) as context: the_function_1(3, request, pk=user.guid) self.assertEqual(context.exception.status_code, 406) self.assertEqual(context.exception.detail, "Invalid data passed: mandatory is missing") request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=*") request.DATA = {"mandatory": "mandatory"} request.QUERY_PARAMS = {} response = the_function_1(4, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({"mandatory": "mandatory", "optional": "default", "user": user}, output["value"]) self.assertIn("request", output["value"].keys()) self.assertEqual(json.loads(response.content), 4) request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=*") request.DATA = {} request.QUERY_PARAMS = {"mandatory": "mandatory", "optional": "optional"} response = the_function_1(5, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset( {"mandatory": "mandatory", "optional": "optional", "version": 2, "user": user}, output["value"] ) self.assertIn("request", output["value"].keys()) self.assertEqual(json.loads(response.content), 5) request = Decorators.factory.get("/", HTTP_ACCEPT="application/json; version=*") request.DATA = {} request.QUERY_PARAMS = {"mandatory": "mandatory", "optional": "optional"} response = the_function_2(6, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({"pk": user.guid, "version": 3, "user": user}, output["value"]) self.assertIn("request", output["value"].keys()) self.assertEqual(json.loads(response.content), 6)
def test_client_credentials(self): """ Validates the Client Credentials """ from oauth2.tokenview import OAuth2TokenView data = {'grant_type': 'client_credentials'} request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) # Fails because the HTTP_AUTHORIZATION header is missing self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'missing_header'})) header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format('foo', 'bar'))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.2', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because there is no such client self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'invalid_client'})) admin_na = UserList.get_user_by_username('admin_na') admin_na_client = Client() admin_na_client.ovs_type = 'USER' admin_na_client.grant_type = 'PASSWORD' admin_na_client.client_secret = OAuth2Toolbox.create_hash(64) admin_na_client.user = admin_na admin_na_client.save() header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format( admin_na_client.guid, admin_na_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.3', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because the grant is of type Resource Owner Password Credentials self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'invalid_grant'})) admin_na_client.grant_type = 'CLIENT_CREDENTIALS' admin_na_client.save() request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.4', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because the grant is of type Resource Owner Password Credentials self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'inactive_user'})) admin = UserList.get_user_by_username('admin') admin_client = Client() admin_client.ovs_type = 'USER' admin_client.grant_type = 'CLIENT_CREDENTIALS' admin_client.client_secret = OAuth2Toolbox.create_hash(64) admin_client.user = admin admin_client.save() header = 'Basic {0}'.format( base64.encodestring('{0}:foobar'.format(admin_client.guid))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.5', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Fails because it's an invalid secret self.assertEqual(response.status_code, 400) self.assertEqual(response.content, json.dumps({'error': 'invalid_client'})) header = 'Basic {0}'.format( base64.encodestring('{0}:{1}'.format(admin_client.guid, admin_client.client_secret))) request = self.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.6', HTTP_AUTHORIZATION=header) response = OAuth2TokenView.as_view()(request) # Succeeds self.assertEqual(response.status_code, 200) response_content = json.loads(response.content) self.assertIn('access_token', response_content) result = { 'access_token': response_content['access_token'], 'token_type': 'bearer', 'expires_in': 3600 } self.assertDictEqual(response_content, result)
def test_load(self): """ Validates whether the load decorator works """ from backend.decorators import load from rest_framework.exceptions import NotAcceptable from django.http import Http404 @load(User, min_version=2, max_version=2) def the_function_1(input_value, request, user, version, mandatory, optional='default'): """ Decorated function """ output['value'] = { 'request': request, 'mandatory': mandatory, 'optional': optional, 'version': version, 'user': user } return HttpResponse(json.dumps(input_value)) @load(User) def the_function_2(input_value, request, user, pk, version): """ Decorated function """ output['value'] = { 'request': request, 'user': user, 'pk': pk, 'version': version } return HttpResponse(json.dumps(input_value)) output = {'value': None} user = UserList.get_user_by_username('user') request = self.factory.get('/', HTTP_ACCEPT='application/json; version=1') with self.assertRaises(NotAcceptable) as context: the_function_1(1, request) self.assertEqual(context.exception.status_code, 406) self.assertEqual( context.exception.detail, 'API version requirements: {0} <= <version> <= {1}. Got {2}'. format(2, 2, 1)) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') with self.assertRaises(Http404): the_function_1(2, request, pk=str(uuid.uuid4())) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = {} with self.assertRaises(NotAcceptable) as context: the_function_1(3, request, pk=user.guid) self.assertEqual(context.exception.status_code, 406) self.assertEqual(context.exception.detail, 'Invalid data passed: mandatory is missing') request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {'mandatory': 'mandatory'} request.QUERY_PARAMS = {} response = the_function_1(4, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset( { 'mandatory': 'mandatory', 'optional': 'default', 'user': user }, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 4) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = { 'mandatory': 'mandatory', 'optional': 'optional' } response = the_function_1(5, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset( { 'mandatory': 'mandatory', 'optional': 'optional', 'version': 2, 'user': user }, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 5) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = { 'mandatory': 'mandatory', 'optional': 'optional' } response = the_function_2(6, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset( { 'pk': user.guid, 'version': 3, 'user': user }, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 6)
def test_metadata(self): """ Validates the authentication related information at the API root's metadata. - The 'roles' key is already checked in the Scope-related tests """ from ovs.dal.lists.bearertokenlist import BearerTokenList from oauth2.tokenview import OAuth2TokenView from view import MetadataView def raise_exception(argument): _ = argument raise RuntimeError('foobar') result_data = {'authenticated': False, 'authentication_state': None, 'username': None, 'userguid': None} data = {'grant_type': 'password', 'username': '******', 'password': '******'} request = Authentication.factory.post('/', data=data, HTTP_X_REAL_IP='127.0.0.1') response = OAuth2TokenView.as_view()(request) response_content = json.loads(response.content) expiry = int(response_content['expires_in']) access_token = response_content['access_token'] request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1') response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'unauthenticated'}.items()), response_content) header = 'Basic foobar' request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'invalid_authorization_type'}.items()), response_content) header = 'Bearer foobar' request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'invalid_token'}.items()), response_content) user = UserList.get_user_by_username('admin') header = 'Bearer {0}'.format(access_token) request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authenticated': True, 'username': user.username, 'userguid': user.guid}.items()), response_content) time.sleep(180) # Make sure to not hit the rate limit user.is_active = False user.save() request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'inactive_user'}.items()), response_content) original_method = BearerTokenList.get_by_access_token BearerTokenList.get_by_access_token = staticmethod(raise_exception) request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'unexpected_exception'}.items()), response_content) BearerTokenList.get_by_access_token = staticmethod(original_method) time.sleep(expiry) request = Authentication.factory.get('/', HTTP_X_REAL_IP='127.0.0.1', HTTP_AUTHORIZATION=header) response = MetadataView.as_view()(request) response_content = json.loads(response.content) self.assertDictContainsSubset(dict(result_data.items() + {'authentication_state': 'token_expired'}.items()), response_content)
def test_load(self): """ Validates whether the load decorator works """ from backend.decorators import load from rest_framework.exceptions import NotAcceptable from django.http import Http404 @load(User, min_version=2, max_version=2) def the_function_1(input_value, request, user, version, mandatory, optional='default'): """ Decorated function """ output['value'] = {'request': request, 'mandatory': mandatory, 'optional': optional, 'version': version, 'user': user} return HttpResponse(json.dumps(input_value)) @load(User) def the_function_2(input_value, request, user, pk, version): """ Decorated function """ output['value'] = {'request': request, 'user': user, 'pk': pk, 'version': version} return HttpResponse(json.dumps(input_value)) output = {'value': None} user = UserList.get_user_by_username('user') request = self.factory.get('/', HTTP_ACCEPT='application/json; version=1') with self.assertRaises(NotAcceptable) as context: the_function_1(1, request) self.assertEqual(context.exception.status_code, 406) self.assertEqual(context.exception.detail, 'API version requirements: {0} <= <version> <= {1}. Got {2}'.format(2, 2, 1)) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') with self.assertRaises(Http404): the_function_1(2, request, pk=str(uuid.uuid4())) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = {} with self.assertRaises(NotAcceptable) as context: the_function_1(3, request, pk=user.guid) self.assertEqual(context.exception.status_code, 406) self.assertEqual(context.exception.detail, 'Invalid data passed: mandatory is missing') request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {'mandatory': 'mandatory'} request.QUERY_PARAMS = {} response = the_function_1(4, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({'mandatory': 'mandatory', 'optional': 'default', 'user': user}, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 4) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = {'mandatory': 'mandatory', 'optional': 'optional'} response = the_function_1(5, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({'mandatory': 'mandatory', 'optional': 'optional', 'version': 2, 'user': user}, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 5) request = self.factory.get('/', HTTP_ACCEPT='application/json; version=*') request.DATA = {} request.QUERY_PARAMS = {'mandatory': 'mandatory', 'optional': 'optional'} response = the_function_2(6, request, pk=user.guid) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({'pk': user.guid, 'version': 3, 'user': user}, output['value']) self.assertIn('request', output['value'].keys()) self.assertEqual(json.loads(response.content), 6)
def post(self, request, *args, **kwargs): """ Handles token post """ logger = LogHandler.get('api', 'oauth2') _ = args, kwargs if 'grant_type' not in request.POST: raise HttpBadRequestException(error='invalid_request', error_description='No grant type specified') grant_type = request.POST['grant_type'] scopes = None if 'scope' in request.POST: scopes = RoleList.get_roles_by_codes(request.POST['scope'].split(' ')) if grant_type == 'password': # Resource Owner Password Credentials Grant if 'username' not in request.POST or 'password' not in request.POST: raise HttpBadRequestException(error='invalid_request', error_description='Invalid request') username = request.POST['username'] password = request.POST['password'] user = UserList.get_user_by_username(username) if user is None or user.password != hashlib.sha256(password).hexdigest(): raise HttpBadRequestException(error='invalid_client', error_description='Invalid client') if user.is_active is False: raise HttpBadRequestException(error='inactive_user', error_description='User is inactive') clients = [client for client in user.clients if client.ovs_type == 'INTERNAL' and client.grant_type == 'PASSWORD'] if len(clients) != 1: raise HttpBadRequestException(error='unauthorized_client', error_description='Client is unauthorized') client = clients[0] try: access_token, _ = OAuth2Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) access_token.expiration = int(time.time() + 86400) access_token.save() except ValueError as error: if error.message == 'invalid_scope': raise HttpBadRequestException(error='invalid_scope', error_description='Invalid scope requested') raise OAuth2Toolbox.clean_tokens(client) return HttpResponse(json.dumps({'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 86400}), content_type='application/json') elif grant_type == 'client_credentials': # Client Credentials if 'HTTP_AUTHORIZATION' not in request.META: raise HttpBadRequestException(error='missing_header', error_description='Authorization header missing') _, password_hash = request.META['HTTP_AUTHORIZATION'].split(' ') client_id, client_secret = base64.b64decode(password_hash).split(':', 1) try: client = Client(client_id) if client.grant_type != 'CLIENT_CREDENTIALS': raise HttpBadRequestException(error='invalid_grant', error_description='The given grant type is not supported') if client.client_secret != client_secret: raise HttpBadRequestException(error='invalid_client', error_description='Invalid client') if not client.user.is_active: raise HttpBadRequestException(error='inactive_user', error_description='User is inactive') try: access_token, _ = OAuth2Toolbox.generate_tokens(client, generate_access=True, scopes=scopes) except ValueError as error: if error.message == 'invalid_scope': raise HttpBadRequestException(error='invalid_scope', error_description='Invalid scope requested') raise try: OAuth2Toolbox.clean_tokens(client) except Exception as error: logger.error('Error during session cleanup: {0}'.format(error)) return HttpResponse(json.dumps({'access_token': access_token.access_token, 'token_type': 'bearer', 'expires_in': 3600}), content_type='application/json') except HttpBadRequestException: raise except ObjectNotFoundException as ex: logger.warning('Error matching client: {0}'.format(ex)) raise HttpBadRequestException(error='invalid_client', error_description='Client could not be found') except Exception as ex: logger.exception('Error matching client: {0}'.format(ex)) raise HttpBadRequestException(error='invalid_client', error_description='Error loading client') else: raise HttpBadRequestException(error='unsupported_grant_type', error_description='Unsupported grant type')