diff --git a/kanidm_book/src/radius.md b/kanidm_book/src/radius.md index 8d2b7e968..e859d9bca 100644 --- a/kanidm_book/src/radius.md +++ b/kanidm_book/src/radius.md @@ -117,6 +117,8 @@ The config.ini has the following template: dh = # Path to the radius servers dh params required_group = # name of a kanidm group which you must be a member of to # use radius. + cache_path = # A path to an area where cached user records can be stored. + # If in doubt, use /dev/shm/kanidmradiusd ; [client.localhost] # client. configures wifi/vpn consumers ; ipaddr = # ipv4 or ipv6 address of the NAS @@ -146,6 +148,7 @@ A fully configured example is: cert = /data/certs/cert.pem dh = /data/certs/dh required_group = radius_access_allowed + cache_path = /dev/shm/kanidmradiusd [client.localhost] ipaddr = 127.0.0.1 diff --git a/kanidm_rlm_python/config.ini b/kanidm_rlm_python/config.ini index 159512e1c..3bb47d74a 100644 --- a/kanidm_rlm_python/config.ini +++ b/kanidm_rlm_python/config.ini @@ -18,6 +18,7 @@ key = cert = dh = required_group = +cache_path = ; [client.localhost] ; ipaddr = diff --git a/kanidm_rlm_python/kanidmradius.py b/kanidm_rlm_python/kanidmradius.py index 0748d5791..2b27a934d 100644 --- a/kanidm_rlm_python/kanidmradius.py +++ b/kanidm_rlm_python/kanidmradius.py @@ -2,6 +2,7 @@ import sys import requests import logging import os +import json MAJOR, MINOR, _, _, _ = sys.version_info @@ -33,6 +34,8 @@ else: USER = CONFIG.get("kanidm_client", "user") SECRET = CONFIG.get("kanidm_client", "secret") DEFAULT_VLAN = CONFIG.get("radiusd", "vlan") +CACHE_PATH = CONFIG.get("radiusd", "cache_path") +TIMEOUT = 8 URL = CONFIG.get('kanidm_client', 'url') AUTH_URL = "%s/v1/auth" % URL @@ -40,13 +43,13 @@ AUTH_URL = "%s/v1/auth" % URL def _authenticate(s, acct, pw): init_auth = {"step": { "Init": [acct, None]}} - r = s.post(AUTH_URL, json=init_auth, verify=CA) + r = s.post(AUTH_URL, json=init_auth, verify=CA, timeout=TIMEOUT) if r.status_code != 200: print(r.json()) raise Exception("AuthInitFailed") cred_auth = {"step": { "Creds": [{"Password": pw}]}} - r = s.post(AUTH_URL, json=cred_auth, verify=CA) + r = s.post(AUTH_URL, json=cred_auth, verify=CA, timeout=TIMEOUT) if r.status_code != 200: print(r.json()) raise Exception("AuthCredFailed") @@ -58,12 +61,40 @@ def _get_radius_token(username): _authenticate(s, USER, SECRET) # Now get the radius token rtok_url = "%s/v1/account/%s/_radius/_token" % (URL, username) - r = s.get(rtok_url) + r = s.get(rtok_url, verify=CA, timeout=TIMEOUT) if r.status_code != 200: raise Exception("Failed to get RadiusAuthToken") tok = r.json() return(tok) +def _update_cache(token): + # Ensure the dir exists + try: + os.makedirs(CACHE_PATH, mode=0o700) + except: + # Already exists + pass + # User Item + item = os.path.join(CACHE_PATH, token["uuid"]) + uitem = os.path.join(CACHE_PATH, token["name"]) + # Token to json. + with open(item, 'w') as f: + json.dump(token, f) + # Symlink username -> uuid + try: + os.symlink(item, uitem) + except Exception as e: + print(e) + +def _get_cache(username): + print("Getting cached token ...") + uitem = os.path.join(CACHE_PATH, username) + try: + with open(uitem, 'r') as f: + return json.load(f) + except: + None + def check_vlan(acc, group): if CONFIG.has_section("group.%s" % group['name']): if CONFIG.has_option("group.%s" % group['name'], "vlan"): @@ -84,10 +115,18 @@ def authorize(args): username = dargs['User-Name'] + tok = None + try: tok = _get_radius_token(username) + # Update the cache? + _update_cache(tok) except Exception as e: print(e) + # Attempt the cache. + tok = _get_cache(username) + + if tok == None: return radiusd.RLM_MODULE_NOTFOUND # print("got token %s" % tok)