69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
|
import socket
|
||
|
|
||
|
import gssapi
|
||
|
from gssapi.raw.exceptions import ExpiredCredentialsError
|
||
|
import requests
|
||
|
from requests_gssapi import HTTPSPNEGOAuth
|
||
|
from zope import component
|
||
|
from zope.interface import implementer
|
||
|
|
||
|
from ceo_common.interfaces import IConfig, IKerberosService, 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')
|
||
|
|
||
|
# Determine which principal to use for SPNEGO
|
||
|
# TODO: this code is duplicated in app_factory.py. Figure out
|
||
|
# how to write it only once.
|
||
|
if socket.gethostname() == cfg.get('ceod_admin_host'):
|
||
|
spnego_principal = cfg.get('ldap_admin_principal')
|
||
|
else:
|
||
|
spnego_principal = f'ceod/{socket.getfqdn()}'
|
||
|
|
||
|
# Initialize variables to get Kerberos cache tickets
|
||
|
krb_realm = cfg.get('ldap_sasl_realm')
|
||
|
self.gssapi_name = gssapi.Name(f'{spnego_principal}@{krb_realm}')
|
||
|
self.krb_srv = component.getUtility(IKerberosService)
|
||
|
|
||
|
def get_creds(self):
|
||
|
"""Get GSSAPI credentials to use for SPNEGO."""
|
||
|
for _ in range(2):
|
||
|
try:
|
||
|
creds = gssapi.Credentials(name=self.gssapi_name, usage='initiate')
|
||
|
creds.inquire()
|
||
|
return creds
|
||
|
except ExpiredCredentialsError:
|
||
|
self.krb_srv.kinit()
|
||
|
raise Exception('could not acquire GSSAPI credentials')
|
||
|
|
||
|
def request(self, host: str, api_path: str, method='GET', **kwargs):
|
||
|
auth = HTTPSPNEGOAuth(
|
||
|
opportunistic_auth=True,
|
||
|
target_name='ceod',
|
||
|
creds=self.get_creds(),
|
||
|
)
|
||
|
return requests.request(
|
||
|
method,
|
||
|
f'{self.scheme}://{host}:{self.ceod_port}{api_path}',
|
||
|
auth=auth,
|
||
|
**kwargs,
|
||
|
)
|
||
|
|
||
|
def get(self, host: str, api_path: str, **kwargs):
|
||
|
return self.request(host, api_path, 'GET', **kwargs)
|
||
|
|
||
|
def post(self, host: str, api_path: str, **kwargs):
|
||
|
return self.request(host, api_path, 'POST', **kwargs)
|
||
|
|
||
|
def delete(self, host: str, api_path: str, **kwargs):
|
||
|
return self.request(host, api_path, 'DELETE', **kwargs)
|