Commit ad04b5f8 authored by Peder Bergebakken Sundt's avatar Peder Bergebakken Sundt
Browse files

Initial commit

parents
#!/usr/bin/env python3
from threading import Lock
from concurrent.futures import ThreadPoolExecutor
from itertools import starmap
from pprint import pprint
from typing import List, Dict, Union, TypedDict, Tuple
import requests # pip
import traceback
import xmltodict # pip
DISCOVERY_URL = "https://discovery.geteduroam.no/v1/discovery.json"
DISCOVERY = requests.get(DISCOVERY_URL).json()
N_WORKERS = 5
N_WORKERS = 20
stdout_lock = Lock()
def call(*a, **kw): # decorator builder
def decorator(func):
return func(*a, **kw)
return decorator
def get_eap_configs(discovery, profile_handler):
with ThreadPoolExecutor(max_workers=N_WORKERS) as e:
for instance in discovery["instances"]: # feature request: ability to download a partial EAP config for Oauth=True profiles
#if instance["country"] != "NO": continue
#print(instance["cat_idp"])
for profile in instance["profiles"]:
if profile.get("oauth") == False:
@call(profile, instance)
def closure(profile, instance): # store profile and instance in a local scope
future = e.submit(requests.get, profile["eapconfig_endpoint"])
@future.add_done_callback
def callback(future):
resp = future.result()
if not resp.ok: return # todo, print why?
#with open(f"eap-configs/{profile["id"]}.eap-config", "w") as f:
# f.write(eap_config_xml)
eap_config_xml = resp.text
try:
profile_handler(profile["id"], eap_config_xml, profile, instance)
except:
print()
traceback.print_exc()
print(profile["eapconfig_endpoint"])
print(eap_config_xml)
print()
print()
def parse_profile(profile_id: str, eap_config_xml: str, profile: dict, instance: dict):
def ensure_list(element): # xml to dict is weird
if element is None:
return []
if isinstance(element, list):
return element
return [element]
eap_config = xmltodict.parse(eap_config_xml)
#pprint(eap_config)
provider = eap_config["EAPIdentityProviderList"]["EAPIdentityProvider"]
display_name = provider.get("ProviderInfo", {}).get("DisplayName")
description = provider.get("ProviderInfo", {}).get("Description")
ieee80211 = ensure_list(provider.get("CredentialApplicability", {}).get("IEEE80211"))
ieee8023 = ensure_list(provider.get("CredentialApplicability", {}).get("IEEE8023"))
supported_eap_types = []
for auth_method in ensure_list(provider["AuthenticationMethods"]["AuthenticationMethod"]):
eap_method = int(auth_method["EAPMethod"]["Type"])
inner_auth_method = int(
auth_method
.get("InnerAuthenticationMethod", {})
.get("EAPMethod", {})
.get("Type")
or auth_method
.get("InnerAuthenticationMethod", {})
.get("NonEAPAuthMethod", {})
.get("Type")
or 0
)
servers = ensure_list(auth_method.get("ServerSideCredential", {}).get("ServerID"))
certificates = [
(
ca["@format"],
ca["@encoding"],
ca["#text"],
)
for ca in ensure_list(auth_method.get("ServerSideCredential", {}).get("CA"))
]
supported_eap_types.append((eap_method, inner_auth_method))
test_auth_method(
display_name = f"{display_name} - {profile_id}",
eap_method = eap_method,
inner_auth_method = inner_auth_method,
servers = servers,
certificates = certificates,
ieee80211 = ieee80211,
ieee8023 = ieee8023,
)
continue # TODO: fix:
print( auth_method.get("ClientSideCredential", "asd") )
auth_method.get("ClientSideCredential", {}).get("OuterIdentity")
auth_method.get("ClientSideCredential", {}).get("InnerIdentityPrefix")
auth_method.get("ClientSideCredential", {}).get("InnerIdentitySuffix")
auth_method.get("ClientSideCredential", {}).get("InnerIdentityHint")
auth_method.get("ClientSideCredential", {}).get("UserName")
auth_method.get("ClientSideCredential", {}).get("Password")
auth_method.get("ClientSideCredential", {}).get("ClientCertificate")
ensure_list(auth_method.get("ClientSideCredential", {}).get("IntermediateCACertificate"))
auth_method.get("ClientSideCredential", {}).get("Passphrase")
auth_method.get("ClientSideCredential", {}).get("PAC")
auth_method.get("ClientSideCredential", {}).get("ProvisionPAC")
# print supported eap types
with stdout_lock:
print(display_name + ":")
print("\t" + "\n\t".join(starmap(eap_type_to_string, supported_eap_types)))
print()
class IEEE80211_SSID(TypedDict):
SSID: str
MinRSNProto: str #"TKIP" or "CCMP"
class IEEE80211_HS2(TypedDict):
ConsortiumOID: str
class IEEE8023(TypedDict):
NetworkID: str
def test_auth_method(*,
display_name : str,
eap_method : int,
inner_auth_method : int,
servers : List[str],
certificates : List[Tuple[str, str, str]],
ieee80211 : List[Union[IEEE80211_SSID, IEEE80211_HS2]],
ieee8023 : List[IEEE8023],
):
return # disable
print("display_name: ", display_name)
print("eap_method: ", eap_method)
print("inner_auth_method:", inner_auth_method)
print("servers: ", servers)
print("certificates: ", certificates)
print("ieee80211: ", ieee80211)
print("ieee8023: ", ieee8023)
print("EAP Method: ", eap_type_to_string(eap_method, inner_auth_method))
print()
def eap_type_to_string(eap_method, inner_auth_method):
if (eap_method, inner_auth_method) == (25, 26): return "EAP-PEAP -> MSCHAPv2"
elif (eap_method, inner_auth_method) == (13, 0): return "EAP-TLS"
elif (eap_method, inner_auth_method) == (21, 1): return "EAP-TTLS -> PAP"
elif (eap_method, inner_auth_method) == (21, 2): return "EAP-TTLS -> MSCHAP"
elif (eap_method, inner_auth_method) == (21, 3): return "EAP-TTLS -> MSCHAPv2"
elif (eap_method, inner_auth_method) == (21, 25): return "EAP-TTLS -> EAP-PEAP -> EAP-MSCHAPv2"
elif (eap_method, inner_auth_method) == (21, 26): return "EAP-TTLS -> EAP-MSCHAPv2"
else:
return f"UNKNOWN({eap_method=}, {inner_auth_method=})"
def run_rad_eap_test(*,
profile_id,
radius_host, radius_port, radius_secret,
ssid, method, phase2_method,
domain_names,
user_cert_data, user_key_data, user_key_password,
):
# -H <address> - Address of radius server (DNS name or IP address). When using
# DNS name IPv4 address will be used unless -6 option is present.
# Both IPv4 or IPv6 addresses may be used.
# -P <port> - Port of radius server
# -S <secret> - Secret for radius server communication
# -u <username> - Username (user@realm.tld)
# -A <anonymous_id> - Anonymous identity (anonymous_user@realm.tld)
# -p <password> - Password
# -t <timeout> - Timeout (default is 5 seconds)
# -m <method> - Method (WPA-EAP | IEEE8021X)
# -v - Verbose (prints decoded last Access-accept packet)
# -c - Prints all packets decoded
# -s <ssid> - SSID
# -e <method> - EAP method (PEAP | TLS | TTLS | LEAP)
# -M <mac_addr> - MAC address in xx:xx:xx:xx:xx:xx format
# -i <connect_info> - Connection info (in radius log: connect from <connect_info>)
# -d <domain_name> - Constraint for server domain name. FQDN is used as a full match
# requirement for the server certificate. Multiple values may be specified.
# Multiple values must be separated by semicollon.
# -k <user_key_file> - user certificate key file
# -l <user_key_file_password> - password for user certificate key file
# -j <user_cert_file> - user certificate file
# -a <ca_cert_file> - certificate of CA
# -2 <phase2 method> - Phase2 type (PAP,CHAP,MSCHAPV2)
# -x <subject_match> - Substring to be matched against the subject of the authentication server certificate.
# -N - Identify and do not delete temporary files
# -O <domain.edu.cctld> - Operator-Name value in domain name format
# -I <ip address> - explicitly specify NAS-IP-Address
# -C - request Chargeable-User-Identity
# -T - send Called-Station-Id in MAC:SSID format
# -f - send big access-request to cause fragmentation
# -b - print details about certificate of RADIUS server (whole certificate chain
# may be retrieved by eapol_test, there is a certain logic that tries to
# determine the end server cert and print it)
# -B <file> - save certificate of RADIUS server to specified file
# -n <directory> - store temporary files in specified directory
# -g - print the entire unmodified output of eapol_test
# -V - Show received Chargeable-User-Identity and/or Operator-Name
# -X <warn_days> - check certificate expiry (whole certificate chain may be retrieved by
# eapol_test, there is a certain logic that tries to determine the end
# server cert which is checked for expiry)
# -6 - force use of IPv6 when using DNS name as RADIUS server address
# -4 - use IPv4 when using DNS name as RADIUS server address (this is the
# default, but the option exists for compatibility)
# -h - show this message
outer_identity = "test_outer@"
username = "test_inner@"
password = "Hunter2"
pass
# TODO: -B
#pprint(DISCOVERY)
get_eap_configs(DISCOVERY, parse_profile)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment