80 lines
2.8 KiB
Python
80 lines
2.8 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, IKerberosService
|
|
|
|
|
|
@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():
|
|
# This is reached when we are the server and the client has
|
|
# forwarded their credentials to us.
|
|
token = None
|
|
if g.get('need_admin_creds', False):
|
|
# Some Kerberos bindings in some programming languages can't
|
|
# perform delegation, so use the admin creds here.
|
|
token = component.getUtility(IKerberosService).get_admin_creds_token()
|
|
elif 'client_token' in g:
|
|
token = g.client_token
|
|
if token is not None:
|
|
spnego_kwargs['creds'] = gssapi.Credentials(token=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)
|