def test_jwt_invalid_role_in_request_header(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-allowed-roles': ['contractor', 'editor'], 'x-hasura-default-role': 'contractor' }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'access-denied', 'path': '$' }, 'message': 'Your current role is not in allowed roles' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_no_allowed_roles_in_claim(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user' }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'jwt-missing-role-claims', 'path': '$' }, 'message': 'JWT claim does not contain x-hasura-allowed-roles' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_invalid_signature(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) wrong_key = gen_rsa_key() token = jwt.encode(self.claims, wrong_key, algorithm='HS256').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'invalid-jwt', 'path': '$' }, 'message': 'Could not verify JWT: JWSError JWSInvalidSignature' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_invalid_issuer(self, hge_ctx, endpoint): jwt_conf = json.loads(hge_ctx.hge_jwt_conf) if 'issuer' not in jwt_conf: pytest.skip('issuer not present in conf, skipping testing issuer') hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) self.claims['iss'] = 'rubbish_issuer' token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'invalid-jwt', 'path': '$' }, 'message': 'Could not verify JWT: JWTNotInIssuer' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_expiry(self, hge_ctx, ws_client): curr_time = datetime.utcnow() self.claims = { 'sub': '1234567890', 'name': 'John Doe', 'iat': math.floor(curr_time.timestamp()) } hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) exp = curr_time + timedelta(seconds=4) self.claims['exp'] = round(exp.timestamp()) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') payload = { 'headers': { 'Authorization': 'Bearer ' + token } } init_ws_conn(hge_ctx, ws_client, payload) time.sleep(6) assert ws_client.remote_closed == True, ws_client.remote_closed
def test_jwt_valid_issuer(self, hge_ctx, endpoint): jwt_conf = json.loads(hge_ctx.hge_jwt_conf) if 'issuer' not in jwt_conf: pytest.skip('issuer not present in conf, skipping testing issuer') issuer = jwt_conf['issuer'] hasura_claims = mk_claims( hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict[ 'claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims, hasura_claims, claims_namespace_path) self.claims['iss'] = issuer token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token check_query(hge_ctx, self.conf, add_auth=False, claims_namespace_path=claims_namespace_path)
def test_jwt_expired(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) exp = datetime.utcnow() - timedelta(minutes=1) self.claims['exp'] = round(exp.timestamp()) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'invalid-jwt', 'path': '$' }, 'message': 'Could not verify JWT: JWTExpired' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_no_issuer_in_conf(self, hge_ctx, endpoint): jwt_conf = json.loads(hge_ctx.hge_jwt_conf) if 'issuer' in jwt_conf: pytest.skip('issuer present in conf, skipping testing no issuer') hasura_claims = mk_claims( hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict[ 'claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims, hasura_claims, claims_namespace_path) self.claims['iss'] = 'rubbish-issuer' token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') authz_header = mk_authz_header(hge_ctx.hge_jwt_conf, token) self.conf['headers'].update(authz_header) self.conf['url'] = endpoint check_query(hge_ctx, self.conf, add_auth=False, claims_namespace_path=claims_namespace_path)
def test_jwt_no_audience_in_conf(self, hge_ctx, endpoint): jwt_conf = json.loads(hge_ctx.hge_jwt_conf) if 'audience' in jwt_conf: pytest.skip( 'audience present in conf, skipping testing no audience') hasura_claims = mk_claims( hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict[ 'claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims, hasura_claims, claims_namespace_path) self.claims['aud'] = 'hasura-test-suite' token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['url'] = endpoint check_query(hge_ctx, self.conf, add_auth=False, claims_namespace_path=claims_namespace_path)
def test_jwt_no_default_role(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm=hge_ctx.hge_jwt_algo) authz_header = mk_authz_header(hge_ctx.hge_jwt_conf, token) self.conf['headers'].update(authz_header) self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'jwt-missing-role-claims', 'path': '$' }, 'message': 'JWT claim does not contain x-hasura-default-role' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_invalid_allowed_roles_in_claim(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-allowed-roles': 'user', 'x-hasura-default-role': 'user' }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm=hge_ctx.hge_jwt_algo) authz_header = mk_authz_header(hge_ctx.hge_jwt_conf, token) self.conf['headers'].update(authz_header) self.conf['response'] = { 'errors': [{ 'extensions': { 'code': 'jwt-invalid-claims', 'path': '$' }, 'message': 'invalid x-hasura-allowed-roles; should be a list of roles: parsing [] failed, expected Array, but encountered String' }] } self.conf['url'] = endpoint if endpoint == '/v1/graphql': self.conf['status'] = 200 if endpoint == '/v1alpha1/graphql': self.conf['status'] = 400 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_valid_audience(self, hge_ctx, endpoint): jwt_conf = json.loads(hge_ctx.hge_jwt_conf) if 'audience' not in jwt_conf: pytest.skip( 'audience not present in conf, skipping testing audience') audience = jwt_conf['audience'] audience = audience if isinstance(audience, str) else audience[0] hasura_claims = mk_claims( hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict[ 'claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims, hasura_claims, claims_namespace_path) self.claims['aud'] = audience token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm=hge_ctx.hge_jwt_algo) self.conf['headers']['Authorization'] = 'Bearer ' + token check_query(hge_ctx, self.conf, add_auth=False, claims_namespace_path=claims_namespace_path)
def test_jwt_valid_claims_success(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-allowed-roles': ['user', 'editor'], 'x-hasura-default-role': 'user' }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['url'] = endpoint self.conf['status'] = 200 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_valid_claims_success(self, hge_ctx, endpoint): hasura_claims = mk_claims(hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-allowed-roles': ['user', 'editor'], 'x-hasura-default-role': 'user' }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict['claims_namespace_path'] self.claims = mk_claims_with_namespace_path(self.claims,hasura_claims,claims_namespace_path) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm=hge_ctx.hge_jwt_algo) authz_header = mk_authz_header(hge_ctx.hge_jwt_conf, token) self.conf['headers'].update(authz_header) self.conf['url'] = endpoint self.conf['status'] = 200 check_query(hge_ctx, self.conf, add_auth=False,claims_namespace_path=claims_namespace_path)
def test_jwt_expiry_leeway(self, hge_ctx, endpoint): hasura_claims = mk_claims( hge_ctx.hge_jwt_conf, { 'x-hasura-user-id': '1', 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) claims_namespace_path = None if 'claims_namespace_path' in hge_ctx.hge_jwt_conf_dict: claims_namespace_path = hge_ctx.hge_jwt_conf_dict[ 'claims_namespace_path'] if not 'allowed_skew' in hge_ctx.hge_jwt_conf_dict: pytest.skip( "This test expects 'allowed_skew' to be set in the JWT config") self.claims = mk_claims_with_namespace_path(self.claims, hasura_claims, claims_namespace_path) exp = datetime.now(timezone.utc) - timedelta(seconds=30) self.claims['exp'] = round(exp.timestamp()) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm=hge_ctx.hge_jwt_algo) self.conf['headers']['Authorization'] = 'Bearer ' + token self.conf['response'] = { 'data': { 'article': [{ 'id': 1, 'title': 'Article 1', 'content': 'Sample article content 1', 'is_published': False, 'author': { 'id': 1, 'name': 'Author 1' } }] } } self.conf['url'] = endpoint self.conf['status'] = 200 print("conf is ", self.conf) check_query(hge_ctx, self.conf, add_auth=False, claims_namespace_path=claims_namespace_path)