2021-08-13 20:11:56 -04:00
|
|
|
import json
|
|
|
|
import socket
|
|
|
|
|
2021-08-25 22:19:18 -04:00
|
|
|
import flask
|
2021-08-13 20:11:56 -04:00
|
|
|
from flask.testing import FlaskClient
|
|
|
|
import gssapi
|
|
|
|
import pytest
|
|
|
|
from requests import Request
|
|
|
|
from requests_gssapi import HTTPSPNEGOAuth
|
|
|
|
|
2021-08-28 01:51:48 -04:00
|
|
|
from .utils import gssapi_token_ctx
|
2021-08-18 15:39:14 -04:00
|
|
|
|
|
|
|
__all__ = ['client']
|
2021-08-13 20:11:56 -04:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
|
|
def client(app):
|
|
|
|
app_client = app.test_client()
|
2021-08-23 19:01:24 -04:00
|
|
|
yield CeodTestClient(app_client)
|
2021-08-13 20:11:56 -04:00
|
|
|
|
|
|
|
|
|
|
|
class CeodTestClient:
|
2021-08-23 19:01:24 -04:00
|
|
|
def __init__(self, app_client: FlaskClient):
|
2021-08-13 20:11:56 -04:00
|
|
|
self.client = app_client
|
2021-08-18 15:39:14 -04:00
|
|
|
self.syscom_principal = 'ctdalek'
|
2021-08-13 20:11:56 -04:00
|
|
|
# this is only used for the HTTPSNEGOAuth
|
|
|
|
self.base_url = f'http://{socket.getfqdn()}'
|
2021-08-21 02:27:33 -04:00
|
|
|
# for SPNEGO
|
|
|
|
self.target_name = gssapi.Name('ceod/' + socket.getfqdn())
|
2021-08-19 16:33:44 -04:00
|
|
|
|
2021-08-25 22:19:18 -04:00
|
|
|
def get_auth(self, principal: str, delegate: bool):
|
2021-08-19 16:33:44 -04:00
|
|
|
"""Acquire a HTTPSPNEGOAuth instance for the principal."""
|
2021-08-28 01:51:48 -04:00
|
|
|
with gssapi_token_ctx(principal) as token:
|
2021-08-25 22:19:18 -04:00
|
|
|
return HTTPSPNEGOAuth(
|
|
|
|
opportunistic_auth=True,
|
|
|
|
target_name=self.target_name,
|
2021-08-28 01:51:48 -04:00
|
|
|
creds=gssapi.Credentials(token=token),
|
2021-08-25 22:19:18 -04:00
|
|
|
delegate=delegate,
|
|
|
|
)
|
2021-08-13 20:11:56 -04:00
|
|
|
|
2021-08-25 22:19:18 -04:00
|
|
|
def get_headers(self, principal: str, delegate: bool):
|
|
|
|
# Get the Authorization header (SPNEGO).
|
|
|
|
# The method doesn't matter here because we just need to extract
|
|
|
|
# the header using req.prepare().
|
|
|
|
req = Request('GET', self.base_url, auth=self.get_auth(principal, delegate))
|
|
|
|
headers = list(req.prepare().headers.items())
|
2021-08-18 15:39:14 -04:00
|
|
|
return headers
|
2021-08-13 20:11:56 -04:00
|
|
|
|
2021-08-28 23:09:02 -04:00
|
|
|
def request(self, method, path, principal, need_auth, delegate, **kwargs):
|
2021-08-25 22:19:18 -04:00
|
|
|
# make sure that we're not already in a Flask context
|
|
|
|
assert not flask.has_app_context()
|
2021-08-28 23:09:02 -04:00
|
|
|
if need_auth:
|
|
|
|
principal = principal or self.syscom_principal
|
|
|
|
headers = self.get_headers(principal, delegate)
|
|
|
|
else:
|
|
|
|
headers = []
|
2021-08-19 19:53:13 -04:00
|
|
|
resp = self.client.open(path, method=method, headers=headers, **kwargs)
|
2021-08-13 20:11:56 -04:00
|
|
|
status = int(resp.status.split(' ', 1)[0])
|
2021-08-18 15:39:14 -04:00
|
|
|
if resp.headers['content-type'] == 'application/json':
|
2021-08-13 20:11:56 -04:00
|
|
|
data = json.loads(resp.data)
|
2021-08-18 15:39:14 -04:00
|
|
|
else:
|
|
|
|
data = [json.loads(line) for line in resp.data.splitlines()]
|
2021-08-13 20:11:56 -04:00
|
|
|
return status, data
|
|
|
|
|
2021-08-28 23:09:02 -04:00
|
|
|
def get(self, path, principal=None, need_auth=True, delegate=True, **kwargs):
|
|
|
|
return self.request('GET', path, principal, need_auth, delegate, **kwargs)
|
2021-08-13 20:11:56 -04:00
|
|
|
|
2021-08-28 23:09:02 -04:00
|
|
|
def post(self, path, principal=None, need_auth=True, delegate=True, **kwargs):
|
|
|
|
return self.request('POST', path, principal, need_auth, delegate, **kwargs)
|
2021-08-13 20:11:56 -04:00
|
|
|
|
2021-08-28 23:09:02 -04:00
|
|
|
def patch(self, path, principal=None, need_auth=True, delegate=True, **kwargs):
|
|
|
|
return self.request('PATCH', path, principal, need_auth, delegate, **kwargs)
|
2021-08-18 15:39:14 -04:00
|
|
|
|
2021-08-28 23:09:02 -04:00
|
|
|
def delete(self, path, principal=None, need_auth=True, delegate=True, **kwargs):
|
|
|
|
return self.request('DELETE', path, principal, need_auth, delegate, **kwargs)
|