store GSSAPI token in flask.g
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
d8e5b1f1d4
commit
7d23fd690f
|
@ -30,10 +30,10 @@ class HTTPClient:
|
|||
'opportunistic_auth': True,
|
||||
'target_name': gssapi.Name('ceod/' + host),
|
||||
}
|
||||
if flask.has_request_context() and 'client_creds' in flask.g:
|
||||
if flask.has_request_context() and 'client_token' in flask.g:
|
||||
# This is reached when we are the server and the client has forwarded
|
||||
# their credentials to us.
|
||||
spnego_kwargs['creds'] = flask.g.client_creds
|
||||
spnego_kwargs['creds'] = gssapi.Credentials(token=flask.g.client_token)
|
||||
if delegate:
|
||||
# This is reached when we are the client and we want to forward our
|
||||
# credentials to the server.
|
||||
|
|
|
@ -52,7 +52,11 @@ def requires_authentication(f):
|
|||
|
||||
# Store the delegated credentials, if they were given
|
||||
if ctx.actual_flags & RequirementFlag.delegate_to_peer:
|
||||
g.client_creds = ctx.delegated_creds
|
||||
# For some reason, shit gets screwed up when you try to use a
|
||||
# gssapi.Credentials object which was created in another function.
|
||||
# So we're going to export the token instead (which is a bytes
|
||||
# object) and pass it to Credentials() whenever we need it.
|
||||
g.client_token = ctx.delegated_creds.export()
|
||||
|
||||
# TODO: don't pass client_princ to f anymore since it's stored in flask.g
|
||||
resp = make_response(f(client_princ, *args, **kwargs))
|
||||
|
|
|
@ -4,6 +4,7 @@ import pwd
|
|||
from typing import Union, Dict, List
|
||||
|
||||
from flask import g
|
||||
import gssapi
|
||||
import ldap3
|
||||
from zope import component
|
||||
from zope.interface import implementer
|
||||
|
@ -34,11 +35,12 @@ class LDAPService:
|
|||
if 'ldap_conn' in g:
|
||||
return g.ldap_conn
|
||||
kwargs = {'auto_bind': True, 'raise_exceptions': True}
|
||||
if 'client_creds' in g:
|
||||
if 'client_token' in g:
|
||||
kwargs['authentication'] = ldap3.SASL
|
||||
kwargs['sasl_mechanism'] = ldap3.KERBEROS
|
||||
creds = gssapi.Credentials(token=g.client_token)
|
||||
# see https://github.com/cannatag/ldap3/blob/master/ldap3/protocol/sasl/kerberos.py
|
||||
kwargs['sasl_credentials'] = (None, None, g.client_creds)
|
||||
kwargs['sasl_credentials'] = (None, None, creds)
|
||||
conn = ldap3.Connection(self.ldap_server_url, **kwargs)
|
||||
# cache the connection for a single request
|
||||
g.ldap_conn = conn
|
||||
|
|
|
@ -11,13 +11,14 @@ import time
|
|||
from unittest.mock import patch, Mock
|
||||
|
||||
import flask
|
||||
import gssapi
|
||||
import ldap3
|
||||
import pytest
|
||||
import requests
|
||||
import socket
|
||||
from zope import component
|
||||
|
||||
from .utils import gssapi_creds_ctx, ccache_cleanup # noqa: F401
|
||||
from .utils import gssapi_token_ctx, ccache_cleanup # noqa: F401
|
||||
from ceo_common.interfaces import IConfig, IKerberosService, ILDAPService, \
|
||||
IFileService, IMailmanService, IHTTPClient, IUWLDAPService, IMailService
|
||||
from ceo_common.model import Config, HTTPClient
|
||||
|
@ -99,13 +100,13 @@ def g_admin_ctx(app):
|
|||
"""
|
||||
@contextlib.contextmanager
|
||||
def wrapper():
|
||||
with gssapi_creds_ctx('ceod/admin') as creds, app.app_context():
|
||||
with gssapi_token_ctx('ceod/admin') as token, app.app_context():
|
||||
try:
|
||||
flask.g.auth_user = 'ceod/admin'
|
||||
flask.g.client_creds = creds
|
||||
flask.g.client_token = token
|
||||
yield
|
||||
finally:
|
||||
flask.g.pop('client_creds')
|
||||
flask.g.pop('client_token')
|
||||
flask.g.pop('auth_user')
|
||||
return wrapper
|
||||
|
||||
|
@ -117,13 +118,13 @@ def g_syscom(app):
|
|||
Use this fixture if you need syscom credentials for an HTTP request
|
||||
to a different process.
|
||||
"""
|
||||
with gssapi_creds_ctx('ctdalek') as creds, app.app_context():
|
||||
with gssapi_token_ctx('ctdalek') as token, app.app_context():
|
||||
try:
|
||||
flask.g.sasl_user = 'ctdalek'
|
||||
flask.g.client_creds = creds
|
||||
flask.g.client_token = token
|
||||
yield
|
||||
finally:
|
||||
flask.g.pop('client_creds')
|
||||
flask.g.pop('client_token')
|
||||
flask.g.pop('sasl_user')
|
||||
|
||||
|
||||
|
@ -135,7 +136,8 @@ def ldap_conn(cfg) -> ldap3.Connection:
|
|||
server_url = cfg.get('ldap_server_url')
|
||||
# sanity check
|
||||
assert server_url == cfg.get('uwldap_server_url')
|
||||
with gssapi_creds_ctx('ceod/admin') as creds:
|
||||
with gssapi_token_ctx('ceod/admin') as token:
|
||||
creds = gssapi.Credentials(token=token)
|
||||
conn = ldap3.Connection(
|
||||
server_url, auto_bind=True, raise_exceptions=True,
|
||||
authentication=ldap3.SASL, sasl_mechanism=ldap3.KERBEROS,
|
||||
|
@ -369,7 +371,7 @@ def app_process(cfg, app, http_client):
|
|||
try:
|
||||
# Currently the HTTPClient uses SPNEGO for all requests,
|
||||
# even GETs
|
||||
with gssapi_creds_ctx('ctdalek'):
|
||||
with gssapi_token_ctx('ctdalek'):
|
||||
for i in range(5):
|
||||
try:
|
||||
http_client.get(hostname, '/ping', delegate=False)
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
|
||||
import pytest
|
||||
|
||||
from .utils import gssapi_creds_ctx
|
||||
from .utils import gssapi_token_ctx
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
|
@ -14,5 +14,5 @@ def cli_setup(app_process):
|
|||
# messy because they would be sharing the same environment variables,
|
||||
# Kerberos cache, and registered utilities (via zope). So we're just
|
||||
# going to start the app in a child process intead.
|
||||
with gssapi_creds_ctx('ctdalek'):
|
||||
with gssapi_token_ctx('ctdalek'):
|
||||
yield
|
||||
|
|
|
@ -8,7 +8,7 @@ import pytest
|
|||
from requests import Request
|
||||
from requests_gssapi import HTTPSPNEGOAuth
|
||||
|
||||
from .utils import gssapi_creds_ctx
|
||||
from .utils import gssapi_token_ctx
|
||||
|
||||
__all__ = ['client']
|
||||
|
||||
|
@ -30,11 +30,11 @@ class CeodTestClient:
|
|||
|
||||
def get_auth(self, principal: str, delegate: bool):
|
||||
"""Acquire a HTTPSPNEGOAuth instance for the principal."""
|
||||
with gssapi_creds_ctx(principal) as creds:
|
||||
with gssapi_token_ctx(principal) as token:
|
||||
return HTTPSPNEGOAuth(
|
||||
opportunistic_auth=True,
|
||||
target_name=self.target_name,
|
||||
creds=creds,
|
||||
creds=gssapi.Credentials(token=token),
|
||||
delegate=delegate,
|
||||
)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ _cache = {}
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def gssapi_creds_ctx(principal: str):
|
||||
def gssapi_token_ctx(principal: str):
|
||||
"""
|
||||
Temporarily set KRB5CCNAME to a ccache storing credentials
|
||||
for the specified user, and yield the GSSAPI credentials.
|
||||
|
@ -35,7 +35,7 @@ def gssapi_creds_ctx(principal: str):
|
|||
else:
|
||||
creds, f = _cache[principal]
|
||||
os.environ['KRB5CCNAME'] = 'FILE:' + f.name
|
||||
yield creds
|
||||
yield creds.export()
|
||||
finally:
|
||||
os.environ['KRB5CCNAME'] = old_krb5ccname
|
||||
|
||||
|
|
Loading…
Reference in New Issue