Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several improvements for gp-okta.py #19

Merged
merged 30 commits into from
May 21, 2020
Merged

Conversation

coldcoff
Copy link
Contributor

@coldcoff coldcoff commented Jul 8, 2019

Hello @arthepsy,

please have a look at this pull request.

I had asked @aclindsa to merge in his fork (as my work was based on his fork and he alreday has a PR against your repository open). But he asked me to bring the changes to your attention as now 15 of the 17 commits are from me, and as I might be able to answer most of your questions / comments better than him. Both of us don't want to maintain a permanent fork and we would like to bring our enhancements "back home" to you in your original repository (aclindsa#1 (comment)). Also this might be one more step towards @dlenski's wish for one-script-to-rule-them-all (see: dlenski/openconnect#122 (comment)).

Please test, have a close look and feel free to ask every question or comment that comes to your mind reg. our changes. I'll try to address everything until it hopefully gets merged ;-)

Thank you and best regards

@coldcoff

aclindsa and others added 17 commits June 4, 2019 14:04
This appears to be required for my VPN
This fixes Issue arthepsy#17 raised by @lvml.

(Note that if you need to specify a client certificate for the `vpn_url`, then most probably
you will also need to give the same certificate to the final `openconnect` call with `--certificate` via the `openconnect_args`)
…te VPN setups.

The first authn call only returns the `sessionToken`, with the redirect later one gets the `stateToken` and afterwards need to do the authn call again for full authentication (and mfa).
  - new option `vpn_url_cert`
  - new option `okta_url_cert`
- rename client certificate option to `client_cert` from `cert`
- totp: comment out ABCDEFGHIJKLMNOP secrets, default to not set (so you get asked)
- grab and display prelogin errors (for example: client certificate needed or such)
- new option `openconnect_certs` that points to a file to collect all given and collected server certificates, will be given to the final openconnect call (inspired by nicklans fork, thank you). If it is not set it will be a temp file.
- check all redirect and parsed urls if they point to an expected domain (either `okta_url` or `vpn_url`)
- learn `gateway` from getconfig call, if not set/overridden by config file
…A in Okta.

Just insert your YubiKey and press the blinking button, when asked to do so.
Needs `fido2` packages to work (`pip install fido2`).
coldcoff and others added 3 commits September 3, 2019 10:30
…arameters for getconfig.esp (found in OpenConnect source code and docs)
Although not advertised as such, Symantec VIP Access is based on TOTP and
there is an open-source implementation for provisioning the tokens and
obtaining the TOTP secret at http://github.com/dlenski/python-vipaccess
@coldcoff
Copy link
Contributor Author

Any news? Can this be please be merged? We have it here in production for months without problems.

@nootanghimire
Copy link

Just confirming I needed this fork in order to make it working! Having this merged would be awesome! (cc @arthepsy)

Thanks heaps for making it!

…eways fetched from the portal - useful to see what values the 'gateway' option can take
gp-okta.py Show resolved Hide resolved
@coldcoff coldcoff mentioned this pull request May 8, 2020
gp-okta.py Outdated
ftype = 'totp'
if ftype not in ['totp', 'sms']:
if ftype not in ['totp', 'sms', 'webauthn']:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add push to this list? It was missed in #14.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, please test.

log('saml-username (2): {0}'.format(saml_username))
log('prelogin-cookie (2): {0}'.format(prelogin_cookie))

if (not userauthcookie or userauthcookie == 'empty') and prelogin_cookie != 'empty':

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small request: for some reason my GP server works with the prelogin_cookie but not the userauthcookie. Can the token to use be an option that is set in the config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or some preference setting? Could you please send a patch that is working on your side, then I can test here as well.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure I will polish it up a bit tomorrow and send it. sorry to hijack your PR but this is the smoothest experience for using GP out of the few options there are :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wrong, for some reason it wasn't working yesterday but it is working fine now.

The next thing is that my server requires a HIP report, so I need to be able to pass --csd-wrapper=hipreport.sh to openconnect at the end.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(FYI I woke up and realized I can add that to the openconnect command in the config file... maybe something to consider adding to the README)

@arthepsy arthepsy merged commit ba14b46 into arthepsy:master May 21, 2020
@arthepsy
Copy link
Owner

arthepsy commented May 21, 2020

I merged the pull request, but this completely broke our company's VPN in two ways, e.g.:

[INFO] Discarding 'vpn_url', as concrete gateway is given and another_dance = 0
..
[DEBUG] https://GW/ssl-vpn/prelogin.esp

Issue is, our company's GW are named, not full URLs (same as for example gateway "Manual ..", which is not a valid URL).

redirect form: unexpected url found ('https', u'gw.DOMAIN.TLD') != (u'https', u'vpn.DOMAIN.TLD')

Errors out, because gateway URL is different than VPN url.

Will investigate how to fix those issues.

@arthepsy
Copy link
Owner

@coldcoff could You please explain, is this really required and is correct? Seems wrong to me:

        cmd = cmd.format(username, cookie_type,
               'https://{0}'.format(gateway) if conf.get('another_dance', '').lower() in ['1', 'true'] else conf.get('vpn_url'))

i.e, really, openconnect should connect to gateway_url (I renamed it) if another_dance = 1? Maybe it's meant to check for non-empty gateway_url not another_dance?

It fails for my company's VPN, but then again, I think I don't have a setup, where I can test this, because authenticating directly to our gateway, gives GlobalProtect gateway does not exist.

@arthepsy
Copy link
Owner

Fixed 1st issue (retaining this pull request features) in 2a1fb94, by using gateway_url. Also, while there, fixed gateway list retrieval.

@arthepsy arthepsy mentioned this pull request May 21, 2020
@arthepsy
Copy link
Owner

Fixed 2nd issue in b5dffd6, by only warning about unexpected URL.

@cardonator
Copy link

cardonator commented May 21, 2020

@arthepsy when you have these fixes in a PR let me know. I couldn't use the "dance" in this on my VPN, either. I had to hard code one of the gateways.

Also, does the dance randomly pick the second gateway? The official client does something to try to figure out what the best option is.

@arthepsy
Copy link
Owner

@cardonator these fixes are in master right now. You can test them out. Right now I'll only add features, e.g., removing "bug.*" and adding openconnect_fmt, so regardless of openconnect version, anything can be fixed in config. This will fix compatibility with openconnect 8.05+. Will also work on auto-detecting it. Anyhow, go ahead and test right now.

What do You mean "hard code one of the gateways"?

If with dance You mean another_dance, in this pull request, I'm not sure, as I can't test it. For me, it worked before and now works with another_dance=0. My company's VPN dance is like this: portal -> okta -> gateway (acts as portal).

Official clients works detects which gateway to use by "priorities" (by getting config from portal) defined by administrator. They actually are in SAML responses.

@cardonator
Copy link

cardonator commented May 21, 2020

Okay, thanks for the info. I have to specify one of the gateways returned by the portal in order to connect prior to your changes. Right now, there is an issue on line 685 because in Python 3 gateways.keys() returns a dict_keys object which doesn't support pop.

Traceback (most recent call last):
  File "./gp-okta.py", line 841, in <module>
    sys.exit(main())
  File "./gp-okta.py", line 782, in main
    gateway_url = choose_gateway_url(conf, gateways)
  File "./gp-okta.py", line 686, in choose_gateway_url
    gateway_host = gateways.keys().pop()
AttributeError: 'dict_keys' object has no attribute 'pop'

If I fix that issue by casting it to a list, it does select one of the gateways but the dance still fails for some reason with

POST https://gateway/global-protect/getconfig.esp
Got HTTP response: HTTP/1.1 512 Custom error
Unexpected 512 result from server

It tries to do the Okta dance again after that and then fails on putting in the login credentials:

Enter login credentials
Username: fgets (stdin): Resource temporarily unavailable

If I add the second dance config, I get this instead:

[ERROR] okta redirect form (2): unexpected url found ('https', 'portalhost') != ('https', 'gateway')

If I add a value to the gateway config parameter of one of the gateways that is returned from the portal, then I am able to connect without issues.

@arthepsy
Copy link
Owner

Yes, I haven't tested compatibility for Python2/Python3 with latest commits. Will do that after I implement few features (working on them now).

So, do I understand correctly that except Python3 issue, when You change gateway = name in config, all is fine? If so, it's same for my company and is expected. I use only vpn_url and gateway, no other options. Or I misunderstood something?

@cardonator
Copy link

No that's exactly right. MY portal is weird because it does have a set of gateways that imply they need to do the okta dance. But if the behavior you understand is having the gateway specified, that use case does work for me as long as I have the push functionality (that you have gratefully merged in :) )

@arthepsy
Copy link
Owner

Actually, gateway is required for piping to openconnect command, e.g., it does something like this: printf "<cookie>\n<gateway>" | openconnect .... You can manually check what's required, by running openconnect command and pasting in line-by-line. Then You'll see where and why it could fail.

P.S. I'll commit new features and fixes in few minutes.

@cardonator
Copy link

Okay, thanks. I'll move this conversation to a new issue if I have more comments.

@arthepsy
Copy link
Owner

@cardonator #21.

@coldcoff
Copy link
Contributor Author

@coldcoff could You please explain, is this really required and is correct? Seems wrong to me:

        cmd = cmd.format(username, cookie_type,
               'https://{0}'.format(gateway) if conf.get('another_dance', '').lower() in ['1', 'true'] else conf.get('vpn_url'))

i.e, really, openconnect should connect to gateway_url (I renamed it) if another_dance = 1? Maybe it's meant to check for non-empty gateway_url not another_dance?

It fails for my company's VPN, but then again, I think I don't have a setup, where I can test this, because authenticating directly to our gateway, gives GlobalProtect gateway does not exist.

This is basically line 929? The reasoning is/was:
If we dance twice already in python then the final openconnect destination to connect to should be the gateway. not the portal. We did all in gp-okta.py and can direct openconnect directly to the gateway, including the credentials needed.

Note that a portal does not need to offer any gateway capabilities, although often both functionalities run on the very same machine, under different paths.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

prelogin.response: "Valid client certificate is required"
6 participants