Coder Social home page Coder Social logo

arthepsy / pan-globalprotect-okta Goto Github PK

View Code? Open in Web Editor NEW
98.0 9.0 42.0 147 KB

PaloAlto Networks GlobalProtect VPN (integrated with OKTA) command-line client

Shell 9.46% Python 88.61% Dockerfile 1.60% Nix 0.33%
vpn globalprotect paloalto paloaltonetworks okta openconnect totp sms

pan-globalprotect-okta's Introduction

pan-globalprotect-okta

Command-line client for PaloAlto Networks' GlobalProtect VPN, integrated with OKTA. This utility will do the authentication dance with OKTA to retrieve cookie, which will be passed to OpenConnect for creating actual VPN connection. Compatible with Python 2 and 3. Tested on FreeBSD, Linux and MacOS X. Tested with OpenConnect 8.00 - 8.10.

It also supports multiple second factor authentication implementations like Google, OKTA, YubiKey, SMS, etc. TOPT authentication can work without user interaction, if initial secret is provided. Otherwise, it will ask for generated code.

To gather TOTP secret, there are two possibilities - either scan the provided QR code with normal QR code scanner and write down the secret. Or create backup from current OTP application in phone. Some applications have this feature, but some don't. For example, andOTP on Android do support this feature.

usage

This utility depends on requests and lxml Python libraries. If TOTP secret is being used, then pyotp is also required. For YubiKey, fido2 is required.

   ./gp-okta.py gp-okta.conf

docker

Build Docker image before running container:

docker build -t gp-okta .

Edit gp-okta.conf and launch Docker container:

sh run-docker.sh

configuration

Configuration file should be self-explanatory. Options can be overridden with GP_ prefixed respective environment variables, e.g., GP_PASSWORD will override password option in configuration file.

changelog

v1.00 (2020-05-xx)

  • new MFA: push, Symantec, WebAuthN/YubiKey
  • GnuGP config encryption
  • direct gateway authentication
  • second authentication dance
  • use client certificates
  • verify server certificates
  • type checking

v0.99 (2019-02-14)

  • supported MFA: OKTA, Google, SMS
  • interactive and hard-coded MFA
  • configurable gateway choice
  • Python2 and Python3 support
  • Dockerfile example
  • workarounds for known issues

known issues

If openconnect returns with ioctl or fgets (stdin): Resource temporarily unavailable error, then this openconnect version requires different openconnect_fmt than detected or manually specified. Run openconnect manually and paste line-by-line required options to figure out required openconnect_fmt. Also, please, open an issue and report it.

pan-globalprotect-okta's People

Contributors

aclindsa avatar agriic avatar arthepsy avatar atoms avatar coldcoff avatar dlenski avatar siers avatar stromnet avatar supertylerc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pan-globalprotect-okta's Issues

TypeError: cannot convert <class 'NoneType'> to bytes

OS: Arch Linux
pan-globalprotect-okta revision: da771a4

Output

[INFO] load conf
[INFO] prelogin request [vpn_url]
[INFO] okta saml request [okta_url]
Traceback (most recent call last):
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 1226, in <module>
    sys.exit(main())
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 1178, in main
    rsaml, redirect_url = okta_saml(conf, saml_xml)
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 475, in okta_saml
    redirect_url = get_redirect_url(conf, c, url)
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 377, in get_redirect_url
    from_uri = _refx(rx_from_uri)
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 155, in <lambda>
    _refx = lambda mx: to_b(mx.group(1)).decode('unicode_escape').strip()
  File "/opt/pan-globalprotect-okta/./gp-okta.py", line 91, in to_b
    raise _type_err(v, 'bytes')
TypeError: cannot convert <class 'NoneType'> to bytes

Config details:
I use totp.google

execute = 1
openconnect_cmd = sudo openconnect
openconnect_args =

Thanks!

Hi @arthepsy , thanks for the awesome tool. It saved my day.
I was able to connect with openconnect to GlobalProtect VPN with Okta OTP.

Gentoo Linux. No Systemd.

Authentication failure post pOTP

I am getting an authentication failure after sending the correct OTP challenge that OKTA verify produced, is this something you have seen before:

---
[INFO] portal-userauthcookie: empty
[INFO] global protect login
err: login request failed. status code: 512, text:

var respStatus = "Error";
var respMsg = "Authentication failure: Invalid username or password";
thisForm.inputStr.value = "";

I can provide additional logs if necessary. When I do open a browser to the VPN URL gateway, it does redirect me to the page after successful authentication so something must have been working somehow.

Script fails with err: did not find saml request

With everything configured correctly, the script fails with

# prelogin.response:
status code: 200, text:
<?xml version="1.0" encoding="UTF-8" ?>
<prelogin-response>
<status>Success</status>
<ccusername></ccusername>
<autosubmit>false</autosubmit>
<msg></msg>
<newmsg></newmsg>
<authentication-message>Enter login credentials</authentication-message>
<panos-version>1</panos-version><region>US</region>
</prelogin-response>
---
err: did not find saml request

requests.exceptions.MissingSchema: Invalid URL '/login/cert': No schema supplied.

I'm just trying out your code for the first time and first of all -- thank you! It's awesome that people are working on this. My school just switched to Pan-GP with okta and I haven't been able to access the VPN from my Ubuntu system.

I'm hoping that I'm just doing something simple wrong. I used a QR reader to get my totp secret and I think I've set up the config file correctly:

debug = 0
vpn_url = https://vpn.ursinus.edu
okta_url = https://ursinus.okta.com
username = ########
password = ########
totp.okta = ###################
#totp.google = ABCDEFGHIJKLMNOP
#gateway = Manual ny1-gw.example.com
#openconnect_cmd = sudo openconnect
openconnect_args = # optional arguments to openconnect
execute = 0 # execute openconnect command
bug.nl = 0 # newline work-around for openconnect
bug.username = 0 # username work-around for openconnect

I get the following error when I run:

~/git-repos/arthespy-okta$ ./gp-okta.py gp-okta.conf
[INFO] prelogin request
[INFO] okta saml request
[INFO] okta auth request
[INFO] sessionToken: 201116eJg70sxUsqIiW_ZuqZlAKqJRPTccwWsiLnAFytuvuODEfRbvL
[INFO] okta redirect request
[INFO] okta redirect form request
Traceback (most recent call last):
File "./gp-okta.py", line 379, in
main()
File "./gp-okta.py", line 342, in main
saml_username, prelogin_cookie = okta_redirect(conf, s, token, redirect_url)
File "./gp-okta.py", line 286, in okta_redirect
r = s.post(url, data=data)
File "/home/tcarroll/.local/lib/python2.7/site-packages/requests/sessions.py", line 581, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/home/tcarroll/.local/lib/python2.7/site-packages/requests/sessions.py", line 519, in request
prep = self.prepare_request(req)
File "/home/tcarroll/.local/lib/python2.7/site-packages/requests/sessions.py", line 462, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/home/tcarroll/.local/lib/python2.7/site-packages/requests/models.py", line 313, in prepare
self.prepare_url(url, params)
File "/home/tcarroll/.local/lib/python2.7/site-packages/requests/models.py", line 387, in prepare_url
raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '/login/cert': No schema supplied. Perhaps you meant http:///login/cert?

Any advice would be helpful!

Thanks!

Cheers,
tom

Redirect issue

Hi appears most of this is working on my end except for the final redirect:

$ ./gp-okta.py gp-okta.conf [±master ●]
[INFO] load conf
[INFO] prelogin request [vpn_url]
[INFO] okta saml request [okta_url]
[INFO] okta auth request [okta_url]
[INFO] mfa okta push request [okta_url]
[INFO] sessionToken:
201116CJbTYXdCLWHHnNxJbmniXd3lwwZQNH6qkFP1-kf0Is5_WoBOg
[INFO] okta redirect request 1 [okta_url]
[ERROR] redirect.request failed.
status: 400

And the errror appears to be a bad saml request

400: Bad Request>

Bad Request

Your request resulted in an error.

Description: Bad SAML request

Login error message after disconnect

OS: manjaro, uh... 20.0.1 but it's a rolling release so.. current as of today.
openconnect:

OpenConnect version v8.05
Using GnuTLS. Features present: PKCS#11, RSA software token, HOTP software token, TOTP software token, Yubikey OATH, System keys, DTLS, ESP
Supported protocols: anyconnect (default), nc, gp, pulse

pan-globalprotect-okta revision: f88beb9

When connecting using pan-globalprotect-okta and then ^C to disconnect I get the message:

Invalid user name
Logout failed.
Error: argument "via" is wrong: use nexthop syntax to specify multiple via

When doing the openconnect connection naively with openconnect:
echo <pass> | sudo opeconnect --protocol=gp <portal/gateway address> -u <username> --passwd-on-stdin

I get Logout successful when disconnecting.

prelogin.response: "Valid client certificate is required"

Hi (and first of all thanks for your GP/Okta related efforts!),

I have access to a GP VPN portal of which there is a newer version now that also requires a second factor via Okta.

Trying your gp-okta.py script to address this, I run into the problem that the prelogin.response says "Valid client certificate is required" - and that is plausible since the non-Okta-using instance of the GP gateway also requires valid client certificates to be presented - which works fine when I do so with the "openconnect --certificate ..." option.

Could you support presenting a client certificate when requesting "https://vpn.example.com/global-protect/prelogin.esp"?

For completeness, the relevant part of the gp-okta.py output with "debug=1" I see:

[INFO] prelogin request
# prelogin.request:
https://vpn.example.com/global-protect/prelogin.esp
---
# prelogin.response:
status: 200
...
<?xml version="1.0" encoding="UTF-8" ?>
<prelogin-response>
<status>Error</status>
<ccusername></ccusername>
<autosubmit></autosubmit>
<msg>Valid client certificate is required</msg>
<newmsg>Required client certificate not found. Please contact your IT 
administrator.</newmsg>

OKTA not sending SMS

I have OKTA configured to send me SMS for the challenge, and had to add the following to make the code accept it as a totp_factors:

diff --git a/gp-okta.py b/gp-okta.py
index 99b165bdac83..dfd88cf8fa76 100755
--- a/gp-okta.py
+++ b/gp-okta.py
@@ -278,7 +278,7 @@ def okta_mfa(conf, s, j):
             return u2f_resp
 
     totp_factors = [
-        x for x in factors if x.get('type') == 'token:software:totp'
+        x for x in factors if x.get('type') == 'token:software:totp' or x.get('type') == 'sms'
     ]
     dbg(conf.get('debug'), 'totp_factors', totp_factors)
     if len(totp_factors) == 0:

Though for some reason that does not trigger OKTA to send a SMS, any clues what could be missing? Enabling OKTA verify is an option, though some other people my prefer using SMS (e.g: traveling etc.).

Not working with fido2 0.9.3

Installed fido2 to use with yubikey but tool failed with a bad call to get_assertion. It seems the API has changed a bit but I was able to get version 0.8.0.

Some quick hacks was not enough to get it working even after that first hurdle was fixed. I'll open a PR with that as a WIP

Authentication failure

I am currently using Okta/SAML authentication for both Mac and Windows clients are they are connecting fine. When I use globalconnect on my linux client it seems to bypass Okta/SAML and authenticate against the local db. When attempting to use this client I am getting the following.

[root@localhost]~/pan-globalprotect-okta# ./gp-okta.py gp-okta.conf
[INFO] prelogin request
[INFO] okta saml request
[INFO] okta auth request
err: okta auth request failed. status code: 401, text:
{"errorCode":"E0000004","errorSummary":"Authentication failed","errorLink":"E0000004","errorId":"oaeU1wwig8KQxqvCjiiefewKg","errorCauses":[]}

[root@localhost]~/pan-globalprotect-okta# more gp-okta.conf
debug = 0
vpn_url = https://..io
okta_url = https://****.okta.com
username = ****
password = ****

[root@localhost]~/openconnect# ./openconnect --protocol=gp ..io -vvv
Please enter your username and password
Username: xxx
Password:
POST https://xxx-xxx.xxxx.io/ssl-vpn/login.esp
Attempting to connect to server 69.75.20.146:443
Connected to xx.xx.xx.xx:443
SSL negotiation with xxx.xxx.io
Matched peer certificate subject name 'xxx-xxx.xxx.io'
Connected to HTTPS on xxx-xxx.xxx.io
Got HTTP response: HTTP/1.1 200 OK
Date: Mon, 27 Aug 2018 15:56:30 GMT
Content-Type: application/xml; charset=UTF-8
Content-Length: 625
Connection: keep-alive
ETag: "2bbc3-2346-5a72047f"
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
X-FRAME-OPTIONS: DENY
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Set-Cookie: PHPSESSID=aaa1c727455ed2207ce42c05edf5b14f; secure; HttpOnly
Strict-Transport-Security: max-age=31536000;
X-XSS-Protection: 1; mode=block;
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self';
Ignoring unknown HTTP response line ' script-src 'self' 'unsafe-inline';'
Ignoring unknown HTTP response line ' style-src 'self' 'unsafe-inline';'
HTTP body length: (625)
GlobalProtect login returned authentication-source=LOCAL
POST https://xxx-xxx.xxx.io/ssl-vpn/getconfig.esp
Got HTTP response: HTTP/1.1 200 OK
Date: Mon, 27 Aug 2018 15:56:30 GMT
Content-Type: application/xml; charset=UTF-8
Content-Length: 1626
Connection: keep-alive
ETag: "2bbbd-1f3-5a72047f"
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
X-FRAME-OPTIONS: DENY
Strict-Transport-Security: max-age=31536000;
X-XSS-Protection: 1; mode=block;
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self';
Ignoring unknown HTTP response line ' script-src 'self' 'unsafe-inline';'
Ignoring unknown HTTP response line ' style-src 'self' 'unsafe-inline';'
HTTP body length: (1626)
Tunnel timeout (rekey interval) is 180 minutes.
Idle timeout is 180 minutes.
TCP_INFO rcv mss 1360, snd mss 1360, adv mss 1460, pmtu 1500
No MTU received. Calculated 1422 for ESP tunnel
POST https://xxx-xxx.xxxx.io/ssl-vpn/hipreportcheck.esp
Got HTTP response: HTTP/1.1 200 OK
Date: Mon, 27 Aug 2018 15:56:30 GMT
Content-Type: application/xml; charset=UTF-8
Content-Length: 107
Connection: keep-alive
ETag: "2bbc0-6a6-5a72047f"
X-Content-Type-Options: nosniff
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Security-Policy: default-src 'self'
Expires: Thu, 19 Nov 1981 08:52:00 GMT
X-FRAME-OPTIONS: DENY
Strict-Transport-Security: max-age=31536000;
X-XSS-Protection: 1; mode=block;
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self';
Ignoring unknown HTTP response line ' script-src 'self' 'unsafe-inline';'
Ignoring unknown HTTP response line ' style-src 'self' 'unsafe-inline';'
HTTP body length: (107)
Gateway says HIP report submission is needed.
WARNING: Server asked us to submit HIP report with md5sum 6097578a4cf144d77aab40121ac38119.
VPN connectivity may be disabled or limited without HIP report submission.
You need to provide a --csd-wrapper argument with the HIP report submission script.
Parameters for incoming ESP: SPI 0xc918fd85
ESP encryption type AES-128-CBC (RFC3602) key 0xdbd208f7fb56379ce7c7c9a4afdf2f67
ESP authentication type HMAC-SHA-1-96 (RFC2404) key 0xae020d10daa6229640ba6eadffa5c46e6cd70078
Parameters for outgoing ESP: SPI 0x3050fc07
ESP encryption type AES-128-CBC (RFC3602) key 0x51f9e5cf3cebd260a3d0bd72eeb858a9
ESP authentication type HMAC-SHA-1-96 (RFC2404) key 0xab9b722294e681dfb26cdf49dd985fdf349c976c
Send ESP probes
Connected as 192.168.2.227, using SSL, with ESP in progress
Received ESP packet of 84 bytes
Accepting later-than-expected ESP packet with seq 1 (expected 0)
ESP session established with server
Received ESP packet of 84 bytes
Accepting expected ESP packet with seq 2
Received ESP packet of 84 bytes
Accepting expected ESP packet with seq 3
ESP tunnel connected; exiting HTTPS mainloop.
Sent ESP packet of 100 bytes
No work to do; sleeping for 10000 ms...
Sent ESP packet of 100 bytes
No work to do; sleeping for 6000 ms...
Send ESP probes for DPD
No work to do; sleeping for 5000 ms...
Received ESP packet of 84 bytes
Accepting expected ESP packet with seq 4
No work to do; sleeping for 10000 ms...
Sent ESP packet of 100 bytes
No work to do; sleeping for 9000 ms...
^CPOST https://xxx-xxx.xxx.io/ssl-vpn/logout.esp
SSL negotiation with xxx-xxx.omniex.io
Matched peer certificate subject name 'xxx-xxx.xxx.io'
Connected to HTTPS on xxx-xxx.xxx.io
Got HTTP response: HTTP/1.1 200 OK
Date: Mon, 27 Aug 2018 15:56:48 GMT
Content-Type: application/xml; charset=UTF-8
Content-Length: 259
Connection: keep-alive
ETag: "2bbc4-69f-5a72047f"
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
X-FRAME-OPTIONS: DENY
Strict-Transport-Security: max-age=31536000;
X-XSS-Protection: 1; mode=block;
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self';
Ignoring unknown HTTP response line ' script-src 'self' 'unsafe-inline';'
Ignoring unknown HTTP response line ' style-src 'self' 'unsafe-inline';'
HTTP body length: (259)
Logout successful

[ERROR] empty "portal:portal-userauthcookie" cookie

Hi there!
I've been struggling quite a bit and I've reached the next point where I can't move forward.
Apparently the portal cookie is empty. I have looked at the XML response and it comes with string "empty".
Does anyone have any idea where the problem may be?

(I'm not running dockerized yet)
28-08-2021 (13 58 09)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.