import json import socket from flask.testing import FlaskClient import gssapi import pytest from requests import Request from requests_gssapi import HTTPSPNEGOAuth from zope import component from ceo_common.interfaces import IConfig @pytest.fixture(scope='session') def client(app): app_client = app.test_client() return CeodTestClient(app_client) class CeodTestClient: def __init__(self, app_client: FlaskClient): cfg = component.getUtility(IConfig) self.client = app_client self.admin_principal = cfg.get('ldap_admin_principal') # this is only used for the HTTPSNEGOAuth self.base_url = f'http://{socket.getfqdn()}' self.cached_auth = {} def get_auth(self, principal): if principal in self.cached_auth: return self.cached_auth[principal] name = gssapi.Name(principal) creds = gssapi.Credentials(name=name, usage='initiate') auth = HTTPSPNEGOAuth( opportunistic_auth=True, target_name='ceod', creds=creds, ) self.cached_auth[principal] = auth return auth def get_headers(self, principal): # method doesn't matter here because we just need the headers req = Request('GET', self.base_url, auth=self.get_auth(principal)) return req.prepare().headers.items() def request(self, method, path, principal, **kwargs): if principal is None: principal = self.admin_principal resp = self.client.open( path, method=method, headers=self.get_headers(principal), **kwargs) status = int(resp.status.split(' ', 1)[0]) try: data = json.loads(resp.data) except json.JSONDecodeError: data = resp.data.decode() return status, data def get(self, path, principal=None, **kwargs): return self.request('GET', path, principal, **kwargs) def post(self, path, principal=None, **kwargs): return self.request('POST', path, principal, **kwargs) def delete(self, path, principal=None, **kwargs): return self.request('DELETE', path, principal, **kwargs)