mirror of
https://github.com/os-mnemo/pan-globalprotect-okta
synced 2026-07-31 07:44:38 +02:00
Rework certificate parts. Use different client certificates.
Reshape and reword configuration file.
This commit is contained in:
+36
-25
@@ -1,38 +1,49 @@
|
|||||||
|
# --- general
|
||||||
debug = 0
|
debug = 0
|
||||||
|
|
||||||
vpn_url = https://vpn.example.com
|
|
||||||
#vpn_url_cert = vpn_url.cert
|
|
||||||
|
|
||||||
okta_url = https://example.okta.com
|
okta_url = https://example.okta.com
|
||||||
#okta_url_cert = okta_url.cert
|
vpn_url = https://vpn.example.com
|
||||||
|
|
||||||
#gateway = NEWYORK1-GW # optional gateway name to choose
|
# "gateway_url" forces authentication with specific gateway.
|
||||||
#gateway_url = https://ny1-gw.my.lan # optional gateway url to authenticate
|
#gateway_url = https://ny1-gw.my.lan
|
||||||
another_dance = 0 # second round of authentication
|
# "another_dance" (0/1) defines whether to do second authentication, i.e.,
|
||||||
|
# after authentication with portal, do another authentication with gateway.
|
||||||
|
#another_dance = 0
|
||||||
|
|
||||||
username = myuser
|
username = myuser
|
||||||
password = mypass
|
password = mypass
|
||||||
#client_cert = path-to-myusers-client-cert-as-unencrypted-pem-file.pem
|
# "gateway" is a preferred gateway selection, which portal asks for.
|
||||||
|
gateway = NEWYORK1-GW
|
||||||
|
|
||||||
#openconnect_certs = path-to-a-writeable-filename-in-which-the-script-will-collect-all-involved-server-certs-if-not-set-a-temp-file-is-used-instead
|
# --- multi-factor authentication
|
||||||
|
#mfa_order = totp sms
|
||||||
# mfa_order = totp sms
|
#sms.okta = 0
|
||||||
sms.okta = 0
|
|
||||||
#totp.okta = ABCDEFGHIJKLMNOP
|
#totp.okta = ABCDEFGHIJKLMNOP
|
||||||
#totp.google = ABCDEFGHIJKLMNOP
|
#totp.google = ABCDEFGHIJKLMNOP
|
||||||
#totp.symantec = ABCDEFGHIJKLMNOP
|
#totp.symantec = ABCDEFGHIJKLMNOP
|
||||||
|
|
||||||
execute = 0 # execute openconnect command
|
# --- certificates
|
||||||
openconnect_cmd = sudo openconnect # command to run openconnect
|
# "certs" is (optional) path to certificate file, which will be overwritten
|
||||||
openconnect_args = # optional arguments to openconnect
|
# and stored with all certificates encountered (in config and portal data).
|
||||||
|
# by default, "certs" is not specified, so a temporary file will be created.
|
||||||
# "openconnect_fmt" is automatically detected by running "openconnect_cmd" -V
|
|
||||||
# otherwise, it can be manually formatted what exactly pipe to openconect:
|
|
||||||
# - supports <cookie>, <gateway_name>, etc
|
|
||||||
# - other characters are provided as-is
|
|
||||||
#
|
#
|
||||||
# - for openconnect 8.05+
|
# any "*_cert" is (optional) path to readable and unencrypted certificate
|
||||||
#openconnect_fmt = <cookie><gateway_name><cookie>
|
# file, which will be appended to "certs". four specific settings exists:
|
||||||
# - for openconnect 8.00 - 8.04
|
# "vpn_url_cert" and "okta_url_cert" are used to verify relevant URLs.
|
||||||
#openconnect_fmt = <cookie><gateway_name>
|
# "vpn_cli_cert" and "okta_cli_cert" are used as client certificate.
|
||||||
|
#
|
||||||
|
#certs = certs.pem
|
||||||
|
#vpn_url_cert = vpn.pem
|
||||||
|
#okta_url_cert = okta.pem
|
||||||
|
#vpn_cli_cert = vpn_cli.pem
|
||||||
|
#okta_cli_cert = okta_cli.pem
|
||||||
|
|
||||||
|
# --- execution
|
||||||
|
# "execute" (0/1) defines if openconnect (as specified with "openconnect_cmd"
|
||||||
|
# and "openconnect_args") is executed after OKTA authentication dance.
|
||||||
|
execute = 0
|
||||||
|
openconnect_cmd = sudo openconnect
|
||||||
|
openconnect_args =
|
||||||
|
# "openconnect_fmt" is manually specified format what to pipe to openconect.
|
||||||
|
# supports <cookie>, <username>, etc. other characters are provided as-is
|
||||||
|
#openconnect_fmt = <cookie><cookie>
|
||||||
|
|
||||||
|
|||||||
+28
-18
@@ -198,7 +198,7 @@ class Conf(object):
|
|||||||
self._lines = {} # type: Dict[str, int]
|
self._lines = {} # type: Dict[str, int]
|
||||||
self.debug = False
|
self.debug = False
|
||||||
self.vpn_url = '' # for reassignment
|
self.vpn_url = '' # for reassignment
|
||||||
self.certs = '' # for type
|
self.certs = '' # for filename
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
# type: (str) -> str
|
# type: (str) -> str
|
||||||
@@ -220,10 +220,11 @@ class Conf(object):
|
|||||||
if not cert:
|
if not cert:
|
||||||
return
|
return
|
||||||
if not self.certs:
|
if not self.certs:
|
||||||
if 'openconnect_certs' in self._store:
|
if 'certs' in self._store:
|
||||||
self.certs_fh = io.open(self._store['openconnect_certs'], 'wb')
|
self.certs_fh = io.open(self._store['certs'], 'wb')
|
||||||
else:
|
else:
|
||||||
self.certs_fh = tempfile.NamedTemporaryFile()
|
self.certs_fh = tempfile.NamedTemporaryFile(prefix='gpvpn_', delete=False)
|
||||||
|
log('using temporary file {0} for storing certificates'.format(self.certs_fh.name))
|
||||||
self.certs = self.certs_fh.name
|
self.certs = self.certs_fh.name
|
||||||
self.certs_fh.write(cert)
|
self.certs_fh.write(cert)
|
||||||
|
|
||||||
@@ -271,12 +272,16 @@ class Conf(object):
|
|||||||
conf._store['username'] = input('username: ').strip()
|
conf._store['username'] = input('username: ').strip()
|
||||||
if len(conf._store.get('password', '').strip()) == 0:
|
if len(conf._store.get('password', '').strip()) == 0:
|
||||||
conf._store['password'] = getpass.getpass('password: ').strip()
|
conf._store['password'] = getpass.getpass('password: ').strip()
|
||||||
for cert_name in ['vpn_url_cert', 'okta_url_cert', 'client_cert']:
|
for k in conf._store.keys():
|
||||||
|
if not k.endswith('_cert'):
|
||||||
|
continue
|
||||||
cert_file = conf._store.get(k, '').strip()
|
cert_file = conf._store.get(k, '').strip()
|
||||||
if cert_file:
|
if cert_file:
|
||||||
cert_file = os.path.expandvars(os.path.expanduser(cert_file))
|
cert_file = os.path.expandvars(os.path.expanduser(cert_file))
|
||||||
if not os.path.exists(cert_file):
|
if not os.path.exists(cert_file):
|
||||||
err('configured "{0}" file "{1}" does not exist'.format(cert_name, cert_file))
|
err('configured "{0}" file "{1}" does not exist'.format(k, cert_file))
|
||||||
|
if k.endswith('_cli_cert'):
|
||||||
|
continue
|
||||||
with io.open(cert_file, 'rb') as fp:
|
with io.open(cert_file, 'rb') as fp:
|
||||||
conf.add_cert(fp.read())
|
conf.add_cert(fp.read())
|
||||||
for k in keys:
|
for k in keys:
|
||||||
@@ -391,15 +396,15 @@ def paloalto_prelogin(conf, s, gateway_url=None):
|
|||||||
# 2nd round or direct gateway: use gateway
|
# 2nd round or direct gateway: use gateway
|
||||||
log('prelogin request [gateway_url]')
|
log('prelogin request [gateway_url]')
|
||||||
url = '{0}/ssl-vpn/prelogin.esp'.format(gateway_url)
|
url = '{0}/ssl-vpn/prelogin.esp'.format(gateway_url)
|
||||||
verify = conf.get_cert('vpn_url', True)
|
|
||||||
else:
|
|
||||||
# 1st round: use portal
|
|
||||||
log('prelogin request [vpn_url]')
|
|
||||||
url = '{0}/global-protect/prelogin.esp'.format(conf.vpn_url)
|
|
||||||
if conf.certs:
|
if conf.certs:
|
||||||
verify = conf.certs
|
verify = conf.certs
|
||||||
else:
|
else:
|
||||||
verify = True
|
verify = True
|
||||||
|
else:
|
||||||
|
# 1st round: use portal
|
||||||
|
log('prelogin request [vpn_url]')
|
||||||
|
url = '{0}/global-protect/prelogin.esp'.format(conf.vpn_url)
|
||||||
|
verify = conf.get_cert('vpn_url', True)
|
||||||
_, _h, c = send_req(conf, s, 'prelogin', url, {}, get=True, verify=verify)
|
_, _h, c = send_req(conf, s, 'prelogin', url, {}, get=True, verify=verify)
|
||||||
x = parse_xml(c)
|
x = parse_xml(c)
|
||||||
saml_req = x.find('.//saml-request')
|
saml_req = x.find('.//saml-request')
|
||||||
@@ -683,9 +688,12 @@ def okta_redirect(conf, s, session_token, redirect_url):
|
|||||||
log('okta redirect form request [vpn_url]')
|
log('okta redirect form request [vpn_url]')
|
||||||
purl, pexp = parse_url(form_url), parse_url(conf.vpn_url)
|
purl, pexp = parse_url(form_url), parse_url(conf.vpn_url)
|
||||||
if purl != pexp:
|
if purl != pexp:
|
||||||
# NOTE: redirect to nearest (geo) portal/gateway without any prior knowledge
|
# NOTE: redirect to nearest (geo) gateway without any prior knowledge
|
||||||
warn('{0}: unexpected url found {1} != {2}'.format('redirect form', purl, pexp))
|
warn('{0}: unexpected url found {1} != {2}'.format('redirect form', purl, pexp))
|
||||||
_, h, c = send_req(conf, s, 'redirect form', form_url, form_data)
|
verify = True # type: Union[str, bool]
|
||||||
|
if conf.certs:
|
||||||
|
verify = conf.certs
|
||||||
|
_, h, c = send_req(conf, s, 'redirect form', form_url, form_data, verify=verify)
|
||||||
else:
|
else:
|
||||||
_, h, c = send_req(conf, s, 'redirect form', form_url, form_data,
|
_, h, c = send_req(conf, s, 'redirect form', form_url, form_data,
|
||||||
expected_url=conf.vpn_url, verify=conf.get_cert('vpn_url', True))
|
expected_url=conf.vpn_url, verify=conf.get_cert('vpn_url', True))
|
||||||
@@ -757,7 +765,7 @@ def okta_saml_2(conf, s, gateway_url, saml_xml):
|
|||||||
url, data = parse_form(xhtml)
|
url, data = parse_form(xhtml)
|
||||||
dbg_form(conf, 'okta.saml request(2)', data)
|
dbg_form(conf, 'okta.saml request(2)', data)
|
||||||
log('okta redirect form request (2) [gateway]')
|
log('okta redirect form request (2) [gateway]')
|
||||||
verify = False # type: Union[str, bool]
|
verify = True # type: Union[str, bool]
|
||||||
if conf.certs:
|
if conf.certs:
|
||||||
verify = conf.certs
|
verify = conf.certs
|
||||||
_, h, c = send_req(conf, s, 'okta redirect form (2)', url, data,
|
_, h, c = send_req(conf, s, 'okta redirect form (2)', url, data,
|
||||||
@@ -842,8 +850,8 @@ def main():
|
|||||||
s = requests.Session()
|
s = requests.Session()
|
||||||
s.headers['User-Agent'] = 'PAN GlobalProtect'
|
s.headers['User-Agent'] = 'PAN GlobalProtect'
|
||||||
|
|
||||||
if conf.client_cert:
|
if conf.okta_cli_cert:
|
||||||
s.cert = conf.client_cert
|
s.cert = conf.okta_cli_cert
|
||||||
|
|
||||||
if args.list_gateways:
|
if args.list_gateways:
|
||||||
log('listing gateways')
|
log('listing gateways')
|
||||||
@@ -910,11 +918,13 @@ def main():
|
|||||||
cmd = conf.openconnect_cmd or 'openconnect'
|
cmd = conf.openconnect_cmd or 'openconnect'
|
||||||
cmd += ' --protocol=gp -u \'{0}\''
|
cmd += ' --protocol=gp -u \'{0}\''
|
||||||
cmd += ' --usergroup {1}'
|
cmd += ' --usergroup {1}'
|
||||||
if conf.client_cert:
|
if conf.vpn_cli_cert:
|
||||||
cmd += ' --certificate=\'{0}\''.format(conf.client_cert)
|
cmd += ' --certificate=\'{0}\''.format(conf.vpn_cli_cert)
|
||||||
if conf.certs:
|
if conf.certs:
|
||||||
cmd += ' --cafile=\'{0}\''.format(conf.certs)
|
cmd += ' --cafile=\'{0}\''.format(conf.certs)
|
||||||
cmd += ' --passwd-on-stdin ' + conf.openconnect_args + ' \'{2}\''
|
cmd += ' --passwd-on-stdin ' + conf.openconnect_args + ' \'{2}\''
|
||||||
|
if conf.certs:
|
||||||
|
cmd += '; rm -f \'{0}\''.format(conf.certs)
|
||||||
cmd = cmd.format(username, cookie_type,
|
cmd = cmd.format(username, cookie_type,
|
||||||
gateway_url if conf.get_bool('another_dance') else conf.vpn_url)
|
gateway_url if conf.get_bool('another_dance') else conf.vpn_url)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user