2021-08-23 09:59:01 -04:00
|
|
|
from base64 import b64encode
|
|
|
|
from typing import Union
|
|
|
|
|
2021-07-24 17:09:10 -04:00
|
|
|
import gssapi
|
|
|
|
import requests
|
|
|
|
from requests_gssapi import HTTPSPNEGOAuth
|
|
|
|
from zope import component
|
|
|
|
from zope.interface import implementer
|
|
|
|
|
2021-08-23 09:59:01 -04:00
|
|
|
from ceo_common.krb5.utils import get_fwd_tgt
|
2021-08-18 19:48:17 -04:00
|
|
|
from ceo_common.interfaces import IConfig, IHTTPClient
|
2021-07-24 17:09:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
@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')
|
2021-08-03 19:19:33 -04:00
|
|
|
self.base_domain = cfg.get('base_domain')
|
2021-07-24 17:09:10 -04:00
|
|
|
|
2021-08-23 09:59:01 -04:00
|
|
|
def request(self, host: str, api_path: str, method: str, principal: str,
|
|
|
|
need_cred: bool, **kwargs):
|
2021-08-21 02:27:33 -04:00
|
|
|
# always use the FQDN
|
|
|
|
if '.' not in host:
|
|
|
|
host = host + '.' + self.base_domain
|
2021-08-23 09:59:01 -04:00
|
|
|
|
|
|
|
# SPNEGO
|
|
|
|
if principal is not None:
|
|
|
|
gssapi_name = gssapi.Name(principal)
|
|
|
|
creds = gssapi.Credentials(name=gssapi_name, usage='initiate')
|
|
|
|
else:
|
|
|
|
creds = None
|
2021-07-24 17:09:10 -04:00
|
|
|
auth = HTTPSPNEGOAuth(
|
|
|
|
opportunistic_auth=True,
|
2021-08-21 02:27:33 -04:00
|
|
|
target_name=gssapi.Name('ceod/' + host),
|
2021-08-17 21:59:24 -04:00
|
|
|
creds=creds,
|
2021-07-24 17:09:10 -04:00
|
|
|
)
|
2021-08-23 09:59:01 -04:00
|
|
|
|
|
|
|
# Forwarded TGT (X-KRB5-CRED)
|
|
|
|
headers = {}
|
|
|
|
if need_cred:
|
|
|
|
b = get_fwd_tgt('ceod/' + host)
|
|
|
|
headers['X-KRB5-CRED'] = b64encode(b).decode()
|
|
|
|
|
2021-07-24 17:09:10 -04:00
|
|
|
return requests.request(
|
|
|
|
method,
|
|
|
|
f'{self.scheme}://{host}:{self.ceod_port}{api_path}',
|
2021-08-23 09:59:01 -04:00
|
|
|
auth=auth, headers=headers, **kwargs,
|
2021-07-24 17:09:10 -04:00
|
|
|
)
|
|
|
|
|
2021-08-23 09:59:01 -04:00
|
|
|
def get(self, host: str, api_path: str, principal: Union[str, None] = None,
|
|
|
|
need_cred: bool = False, **kwargs):
|
|
|
|
return self.request(host, api_path, 'GET', principal, need_cred, **kwargs)
|
|
|
|
|
|
|
|
def post(self, host: str, api_path: str, principal: Union[str, None] = None,
|
|
|
|
need_cred: bool = False, **kwargs):
|
|
|
|
return self.request(host, api_path, 'POST', principal, need_cred, **kwargs)
|
2021-07-24 17:09:10 -04:00
|
|
|
|
2021-08-23 09:59:01 -04:00
|
|
|
def patch(self, host: str, api_path: str, principal: Union[str, None] = None,
|
|
|
|
need_cred: bool = False, **kwargs):
|
|
|
|
return self.request(host, api_path, 'PATCH', principal, need_cred, **kwargs)
|
2021-07-24 17:09:10 -04:00
|
|
|
|
2021-08-23 09:59:01 -04:00
|
|
|
def delete(self, host: str, api_path: str, principal: Union[str, None] = None,
|
|
|
|
need_cred: bool = False, **kwargs):
|
|
|
|
return self.request(host, api_path, 'DELETE', principal, need_cred, **kwargs)
|