Development
This commit is contained in:
parent
64f83d683e
commit
1a473296b7
2 changed files with 96 additions and 0 deletions
|
|
@ -174,5 +174,20 @@ def _seed_initial_account():
|
||||||
|
|
||||||
_seed_initial_account()
|
_seed_initial_account()
|
||||||
|
|
||||||
|
|
||||||
|
def _write_credentials_key():
|
||||||
|
key = settings.get_credentials_key()
|
||||||
|
if not key:
|
||||||
|
return
|
||||||
|
path = f'{config_utils.CONFIGS_DIR}/.credentials-key'
|
||||||
|
try:
|
||||||
|
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
||||||
|
os.write(fd, key + b'\n')
|
||||||
|
os.close(fd)
|
||||||
|
except OSError as exc:
|
||||||
|
print(f'[main] WARNING: Could not write .credentials-key: {exc}', file=sys.stderr)
|
||||||
|
|
||||||
|
_write_credentials_key()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=25327)
|
app.run(host="0.0.0.0", port=25327)
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,15 @@ module config.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import sqlite3
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
import mod_shared as shared
|
import mod_shared as shared
|
||||||
|
|
||||||
RADIUS_SECRET_FILE = shared.SCRIPT_DIR / ".radius-secret"
|
RADIUS_SECRET_FILE = shared.SCRIPT_DIR / ".radius-secret"
|
||||||
|
CREDENTIALS_KEY_FILE = shared.SCRIPT_DIR / ".credentials-key"
|
||||||
|
CREDENTIALS_DB_FILE = shared.SCRIPT_DIR / ".client-credentials"
|
||||||
RADIUS_CLIENTS_CONF = Path("/etc/freeradius/3.0/clients.conf")
|
RADIUS_CLIENTS_CONF = Path("/etc/freeradius/3.0/clients.conf")
|
||||||
RADIUS_USERS_FILE = Path("/etc/freeradius/3.0/users")
|
RADIUS_USERS_FILE = Path("/etc/freeradius/3.0/users")
|
||||||
RADIUS_CONF_FILE = Path("/etc/freeradius/3.0/radiusd.conf")
|
RADIUS_CONF_FILE = Path("/etc/freeradius/3.0/radiusd.conf")
|
||||||
|
|
@ -21,6 +25,44 @@ RADIUS_LOG_FILE = Path("/var/log/freeradius/radius.log")
|
||||||
RADIUS_HUNTGROUP_NAME = "routlin-aps"
|
RADIUS_HUNTGROUP_NAME = "routlin-aps"
|
||||||
|
|
||||||
|
|
||||||
|
# digest_type values (mirrors clientcredentials/action.py)
|
||||||
|
DIGEST_CYPHERTEXT_FERNET = 0
|
||||||
|
USER_TYPE_SUPPLICANT = 1
|
||||||
|
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# Credential helpers
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
def _load_fernet():
|
||||||
|
if not CREDENTIALS_KEY_FILE.exists():
|
||||||
|
print(f"WARNING: {CREDENTIALS_KEY_FILE} not found - cannot decrypt supplicant passwords")
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return Fernet(CREDENTIALS_KEY_FILE.read_text().strip().encode())
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"WARNING: Could not load credentials key: {exc}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _load_supplicant_credentials():
|
||||||
|
if not CREDENTIALS_DB_FILE.exists():
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(str(CREDENTIALS_DB_FILE))
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
rows = conn.execute(
|
||||||
|
"SELECT username, password, digest_type, vlan FROM credentials"
|
||||||
|
" WHERE user_type=? AND enabled=1",
|
||||||
|
(USER_TYPE_SUPPLICANT,)
|
||||||
|
).fetchall()
|
||||||
|
conn.close()
|
||||||
|
return [dict(r) for r in rows]
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"WARNING: Could not read credentials DB: {exc}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Data helpers
|
# Data helpers
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
@ -153,6 +195,45 @@ def build_radius_users(data):
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if auth_mode in ('eap_password', 'eap_certificate'):
|
||||||
|
creds = _load_supplicant_credentials()
|
||||||
|
fernet = _load_fernet() if auth_mode == 'eap_password' else None
|
||||||
|
for cred in creds:
|
||||||
|
vlan = vlan_by_name.get(cred['vlan'])
|
||||||
|
if not vlan:
|
||||||
|
continue
|
||||||
|
vlan_id = vlan.get('vlan_id')
|
||||||
|
username = cred['username']
|
||||||
|
if auth_mode == 'eap_password':
|
||||||
|
if fernet is None:
|
||||||
|
print(f"WARNING: Skipping '{username}' - credentials key unavailable")
|
||||||
|
continue
|
||||||
|
if cred['digest_type'] != DIGEST_CYPHERTEXT_FERNET:
|
||||||
|
print(f"WARNING: Skipping '{username}' - unexpected digest_type {cred['digest_type']}")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
plaintext = fernet.decrypt(cred['password'].encode()).decode()
|
||||||
|
except Exception:
|
||||||
|
print(f"WARNING: Skipping '{username}' - decryption failed")
|
||||||
|
continue
|
||||||
|
lines += [
|
||||||
|
f"# {username} -> VLAN {vlan_id} ({vlan['name']})",
|
||||||
|
f"{username} Cleartext-Password := \"{plaintext}\"",
|
||||||
|
f" Tunnel-Type = VLAN,",
|
||||||
|
f" Tunnel-Medium-Type = IEEE-802,",
|
||||||
|
f" Tunnel-Private-Group-Id = \"{vlan_id}\"",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
else: # eap_certificate - cert verified by TLS stack, entry provides VLAN reply attrs
|
||||||
|
lines += [
|
||||||
|
f"# {username} -> VLAN {vlan_id} ({vlan['name']})",
|
||||||
|
f"{username} Auth-Type := EAP",
|
||||||
|
f" Tunnel-Type = VLAN,",
|
||||||
|
f" Tunnel-Medium-Type = IEEE-802,",
|
||||||
|
f" Tunnel-Private-Group-Id = \"{vlan_id}\"",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
default_id = default_vlan.get('vlan_id')
|
default_id = default_vlan.get('vlan_id')
|
||||||
ap_ips = fr_opts.get('ap_ips', [])
|
ap_ips = fr_opts.get('ap_ips', [])
|
||||||
if apply_to == 'wireless':
|
if apply_to == 'wireless':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue