Initial commit
This commit is contained in:
commit
66e15a8a18
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
__pycache__
|
||||
*.egg-info
|
||||
*.pyc
|
||||
.config
|
||||
build/
|
4
cic_auth_helper/data/config/http.ini
Normal file
4
cic_auth_helper/data/config/http.ini
Normal file
@ -0,0 +1,4 @@
|
||||
[http]
|
||||
auth_origin =
|
||||
auth_realm = "ge"
|
||||
hoba_cipher_id = 00
|
6
cic_auth_helper/data/config/pgp.ini
Normal file
6
cic_auth_helper/data/config/pgp.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[pgp]
|
||||
trusted_publickey_fingerprint =
|
||||
import_dir = /var/lib/cic-auth-helper/pgp
|
||||
publickey_filename = publickeys.asc
|
||||
signature_filename = signature.asc
|
||||
run_dir =
|
133
cic_auth_helper/runnable/server_pgp_hoba_session.py
Normal file
133
cic_auth_helper/runnable/server_pgp_hoba_session.py
Normal file
@ -0,0 +1,133 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import os
|
||||
import datetime
|
||||
import base64
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
# external imports
|
||||
from http_hoba_auth import hoba_auth_request_string
|
||||
from http_token_auth import SessionStore
|
||||
import confini
|
||||
|
||||
# local imports
|
||||
from usumbufu.challenge import Challenger
|
||||
#from usumbufu.filter.sha256 import SHA256Filter
|
||||
from usumbufu.filter.hoba import HobaFilter
|
||||
from usumbufu.filter.fetcher import FetcherFilter
|
||||
from usumbufu.filter.pgp import PGPFilter
|
||||
from usumbufu.filter.session import SessionFilter
|
||||
from usumbufu.filter import Filter
|
||||
from usumbufu.retrieve import Retriever
|
||||
from usumbufu.retrieve.file import FileFetcher
|
||||
from usumbufu.adapters.uwsgi import UWSGIHTTPAuthorization
|
||||
from usumbufu.adapters.uwsgi import UWSGIAdapter
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
data_dir = os.path.join(script_dir, '..', 'data')
|
||||
config_dir = os.path.join(data_dir, 'config')
|
||||
|
||||
argparser = argparse.ArgumentParser('Authentication helper for ingress routers')
|
||||
argparser.add_argument('-c', type=str, help='configuration override directory')
|
||||
argparser.add_argument('-v', action='store_true', help='be verbose')
|
||||
argparser.add_argument('-vv', action='store_true', help='be more verbose')
|
||||
args = argparser.parse_args(sys.argv[1:])
|
||||
|
||||
if args.vv:
|
||||
logg.setLevel(logging.DEBUG)
|
||||
elif args.v:
|
||||
logg.setLevel(logging.INFO)
|
||||
|
||||
config = confini.Config(config_dir, override_dirs=args.c)
|
||||
config.process()
|
||||
logg.debug('config loaded:\n' + str(config))
|
||||
|
||||
# The Retriever is at the heart of the setup.
|
||||
# It will run all the decoding steps from all the filters, ultimately resolving to a auth resource (typically ACL) and an identity
|
||||
challenger = Challenger()
|
||||
|
||||
# parse a hoba auth string to key, signature, nonce etc, to the "to be signed" format
|
||||
hoba_filter = HobaFilter(config.get('HTTP_AUTH_ORIGIN'), config.get('HTTP_AUTH_REALM'), challenger, alg=config.get('HTTP_HOBA_CIPHER_ID'))
|
||||
|
||||
trusted_publickeys = config.get('PGP_TRUSTED_PUBLICKEY_FINGERPRINT').split(',')
|
||||
|
||||
fetcher_pgp_trusted = FileFetcher(config.get('PGP_IMPORT_DIR'))
|
||||
pgp_filter = PGPFilter(trusted_publickeys, fetcher_pgp_trusted)
|
||||
|
||||
pgp_filter.import_keys(config.get('PGP_PUBLICKEY_FILENAME'), config.get('PGP_SIGNATURE_FILENAME'))
|
||||
|
||||
# set a session token for the identity, if not yet set
|
||||
# the session store can be used outside the pipeline to get session info (like the auth token for a Token header response)
|
||||
session_store = SessionStore(auth_expire_delta=1)
|
||||
session_filter = SessionFilter(session_store)
|
||||
|
||||
|
||||
# the decoders will be run in SEQUENCE. let's wire them up, like so:
|
||||
hoba_retriever = Retriever()
|
||||
hoba_retriever.add_decoder(hoba_filter)
|
||||
hoba_retriever.add_decoder(pgp_filter)
|
||||
hoba_retriever.add_decoder(session_filter)
|
||||
|
||||
bearer_retriever = Retriever()
|
||||
bearer_retriever.add_decoder(session_filter)
|
||||
|
||||
|
||||
# Below here is the runtime code for the UWSGI application
|
||||
# Most important to notice here is that the ChallengeRetriever is being passed to the UWSGIHTTPAuthorization object. This object can identify a HOBA request, and will attempt to validate the HOBA auth string using ChallengeRetriever.
|
||||
# cic_eth.Auth.check() (overloaded) will attempt to FETCH the ACL using the key (if any) resulting from the validation
|
||||
def do_auth(env):
|
||||
authenticator = UWSGIAdapter()
|
||||
http_authenticator = UWSGIHTTPAuthorization(hoba_retriever, env, config.get('HTTP_AUTH_REALM'), origin=config.get('HTTP_AUTH_ORIGIN'))
|
||||
bearer_authenticator = UWSGIHTTPAuthorization(bearer_retriever, env, config.get('HTTP_AUTH_REALM'), origin=config.get('HTTP_AUTH_ORIGIN'))
|
||||
http_authenticator.component_id = 'http-hoba'
|
||||
bearer_authenticator.component_id = 'http-bearer'
|
||||
try:
|
||||
authenticator.register(bearer_authenticator)
|
||||
authenticator.activate(bearer_authenticator.component_id)
|
||||
except TypeError as e:
|
||||
logg.debug('not a http bearer request: {}'.format(e))
|
||||
|
||||
try:
|
||||
authenticator.register(http_authenticator)
|
||||
authenticator.activate(http_authenticator.component_id)
|
||||
except TypeError as e:
|
||||
logg.debug('not a http hoba request: {}'.format(e))
|
||||
|
||||
return authenticator.check()
|
||||
|
||||
|
||||
# And to conclude, vanilla UWSGI stuff
|
||||
def application(env, start_response):
|
||||
headers = []
|
||||
print('env {}'.format(env))
|
||||
result = do_auth(env)
|
||||
if result == None:
|
||||
#if env.get('HTTP_AUTHORIZATION') != None:
|
||||
# start_response('403 failed miserably', headers)
|
||||
# return [b'']
|
||||
(challenge, expire) = challenger.request(env['REMOTE_ADDR'])
|
||||
headers.append(('WWW-Authenticate', hoba_auth_request_string(challenge, expire.timestamp(), realm=config.get('HTTP_AUTH_REALM'))),)
|
||||
start_response('401 authenticate or I will SCREAM_SNAKE_CASE at you', headers)
|
||||
return [b'']
|
||||
|
||||
# name the successful auth result parts
|
||||
auth_method_component_id = result[0]
|
||||
auth_string = result[1]
|
||||
auth_resource = result[2]
|
||||
auth_identity = result[3]
|
||||
logg.debug('result {}'.format(result))
|
||||
|
||||
session = session_store.get(auth_identity)
|
||||
logg.debug(f'session token: {session.auth}')
|
||||
|
||||
if auth_method_component_id == 'http-hoba':
|
||||
headers.append(('Token', base64.b64encode(session.auth).decode('utf-8'),))
|
||||
elif session.auth != auth_string:
|
||||
headers.append(('Token', base64.b64encode(session.auth).decode('utf-8'),))
|
||||
|
||||
start_response('200 OK', headers)
|
||||
return [str(auth_resource).encode('utf-8')]
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
usumbufu==0.3.1a5
|
||||
uWSGI==2.0.19.1
|
||||
confini==0.4.2
|
Loading…
Reference in New Issue
Block a user