pyceo/ceo_common/model/HTTPClient.py

72 lines
2.3 KiB
Python

import flask
from flask import g
import gssapi
import requests
from requests_gssapi import HTTPSPNEGOAuth
from zope import component
from zope.interface import implementer
from ceo_common.interfaces import IConfig, IHTTPClient
@implementer(IHTTPClient)
class HTTPClient:
def __init__(self):
# Determine how to connect to other ceod instances
cfg = component.getUtility(IConfig)
if cfg.get('ceod_use_https'):
self.scheme = 'https'
else:
self.scheme = 'http'
self.ceod_port = cfg.get('ceod_port')
self.base_domain = cfg.get('base_domain')
def request(self, method: str, host: str, path: str, **kwargs):
# always use the FQDN
if '.' not in host:
host = host + '.' + self.base_domain
if method == 'GET':
need_auth = path.startswith('/api/members') or \
path.startswith('/api/cloud')
delegate = False
else:
need_auth = True
delegate = True
# SPNEGO
if need_auth:
spnego_kwargs = {
'opportunistic_auth': True,
'target_name': gssapi.Name('ceod/' + host),
}
if flask.has_request_context() and 'client_token' in g:
# This is reached when we are the server and the client has
# forwarded their credentials to us.
spnego_kwargs['creds'] = gssapi.Credentials(token=flask.g.client_token)
elif delegate:
# This is reached when we are the client and we want to
# forward our credentials to the server.
spnego_kwargs['delegate'] = True
auth = HTTPSPNEGOAuth(**spnego_kwargs)
else:
auth = None
return requests.request(
method,
f'{self.scheme}://{host}:{self.ceod_port}{path}',
auth=auth, **kwargs,
)
def get(self, host: str, path: str, **kwargs):
return self.request('GET', host, path, **kwargs)
def post(self, host: str, path: str, **kwargs):
return self.request('POST', host, path, **kwargs)
def patch(self, host: str, path: str, **kwargs):
return self.request('PATCH', host, path, **kwargs)
def delete(self, host: str, path: str, **kwargs):
return self.request('DELETE', host, path, **kwargs)