def graphql_login(request): """Authentication and JWT generation logic for the Hasura ``login`` action.""" status = 200 if utils.verify_graphql_request(request.headers): try: # Load the request body as JSON data = json.loads(request.body) data = data["input"] # Authenticate the user with Django's back-end user = authenticate(**data) # A successful auth will return a ``User`` object if user: payload, jwt_token = utils.generate_jwt(user) data = {"token": f"{jwt_token}", "expires": payload["exp"]} else: status = 401 data = utils.generate_hasura_error_payload( "Invalid credentials", "InvalidCredentials") # ``KeyError`` will occur if the request bypasses Hasura except KeyError: status = 400 data = utils.generate_hasura_error_payload("Invalid request body", "InvalidRequestBody") else: status = 403 data = utils.generate_hasura_error_payload( "Unauthorized access method", "Unauthorized") return JsonResponse(data, status=status)
def test_get_jwt_payload(self): payload, encoded_payload = utils.generate_jwt(self.user) try: self.assertTrue(utils.get_jwt_payload(encoded_payload)) except AttributeError: self.fail( "get_jwt_payload() raised an AttributeError unexpectedly!")
def test_verify_hasura_claims(self): payload, encoded_payload = utils.generate_jwt(self.user) try: self.assertTrue(utils.verify_hasura_claims(payload)) except AttributeError: self.fail( "verify_hasura_claims() raised an AttributeError unexpectedly!" )
def test_verify_jwt(self): payload, encoded_payload = utils.generate_jwt(self.user) try: self.assertTrue( utils.verify_jwt_user(payload["https://hasura.io/jwt/claims"])) except AttributeError: self.fail( "verify_jwt_user() raised an AttributeError unexpectedly!")
def test_verify_jwt_with_invalid_user(self): payload, encoded_payload = utils.generate_jwt(self.user) payload["https://hasura.io/jwt/claims"]["X-Hasura-User-Id"] = "999" try: self.assertFalse( utils.verify_jwt_user(payload["https://hasura.io/jwt/claims"])) except AttributeError: self.fail( "verify_jwt_user() raised an AttributeError unexpectedly!")
def test_graphql_webhook_without_claims(self): payload, token = utils.generate_jwt(self.user, exclude_hasura=True) response = self.client.get( self.uri, content_type="application/json", **{ "HTTP_AUTHORIZATION": f"Bearer {token}", }, ) self.assertEqual(response.status_code, 401)
def test_graphql_whoami(self): payload, token = utils.generate_jwt(self.user) response = self.client.post( self.uri, content_type="application/json", **{ "HTTP_HASURA_ACTION_SECRET": "changeme", "HTTP_AUTHORIZATION": f"Bearer {token}" }, ) self.assertEqual(response.status_code, 200) # Test bypasses Hasura so the ``["data"]["whoami"]`` keys are not present self.assertEqual(response.json()["username"], self.user.username)
def test_graphql_webhook_with_valid_jwt_and_inactive_user(self): payload, token = utils.generate_jwt(self.user) self.user.is_active = False self.user.save() response = self.client.get( self.uri, content_type="application/json", **{ "HTTP_AUTHORIZATION": f"Bearer {token}", }, ) self.assertEqual(response.status_code, 401) self.assertJSONEqual(force_str(response.content), self.public_data) self.user.is_active = True self.user.save()
def test_graphql_webhook_with_valid_jwt(self): payload, token = utils.generate_jwt(self.user) data = { "X-Hasura-Role": f"{self.user.role}", "X-Hasura-User-Id": f"{self.user.id}", "X-Hasura-User-Name": f"{self.user.username}", } response = self.client.get( self.uri, content_type="application/json", **{ "HTTP_AUTHORIZATION": f"Bearer {token}", }, ) self.assertEqual(response.status_code, 200) self.assertJSONEqual(force_str(response.content), data)
def test_verify_hasura_claims_without_claims(self): payload, token = utils.generate_jwt(self.user) del payload["https://hasura.io/jwt/claims"] result = utils.verify_hasura_claims(payload) self.assertFalse(result)
def test_generate_jwt_with_expiration(self): expiration = datetime(2099, 1, 1).timestamp() payload, encoded_payload = utils.generate_jwt(self.user, exp=expiration) self.assertTrue(payload["exp"], expiration)
def test_generate_jwt(self): try: payload, encoded_payload = utils.generate_jwt(self.user) except AttributeError: self.fail("generate_jwt() raised an AttributeError unexpectedly!")