Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Peder Bergebakken Sundt
geteduroam-scraper
Commits
ad04b5f8
Commit
ad04b5f8
authored
Aug 14, 2020
by
Peder Bergebakken Sundt
Browse files
Initial commit
parents
Changes
1
Hide whitespace changes
Inline
Side-by-side
scrape.py
0 → 100755
View file @
ad04b5f8
#!/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
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment