Multi step Cisco Anyconnect auth in a single command
Ahmet Karalar
akaralar at gmail.com
Thu Nov 10 18:04:32 PST 2022
Thanks Daniel, --dump option wasn't documented so that was a missing
piece, and using your suggestions I was able to make progress.
Using --form-entry method I'm able to select the option I want in the
second auth method step. I didn't try the --token-secret suggestion,
simply because I feel that it is as sensitive as the password (correct
me if I'm wrong, I mostly don't know what I'm doing). So I didn't want
that secret to remain in my shell history or be visible to the
process. I hope that makes sense. I wanted to try the pksc file method
instead, but I couldn't quite figure out how to create the file
itself.
Above all, from what I understand my company does something weird: the
second auth method and the second auth password (totp) steps use the
same auth id, and the fields have the same name: both have "challenge"
as the auth id and the field has the name "answer". When I run this
command:
echo "$PASSWORD" | openconnect example.com --form-entry
main:username="$USERNAME" --form-entry main:group_list="$GROUP"
--passwd-on-stdin --form-entry challenge:answer=4
I expect openconnect to stop at the totp step so that I can enter it,
however what ends up happening is it continuously tries to enter the
same value I provided at the last --form-entry flag to the totp field,
and after a few failed attempts my account gets locked because of too
many failed attempts and openconnect exits.
Although I don't know C very well, I'm willing to send a PR (with some
guidance) if there is a sensible way to fix this. Below is the output
of --dump for the last 2 steps, I obfuscated some information and
deleted some headers, I hope that's not an issue.
Got HTTP response: HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Transfer-Encoding: chunked
Cache-Control: no-store
Pragma: no-cache
Connection: Keep-Alive
Date: Thu, 10 Nov 2022 18:54:19 GMT
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-XSS-Protection: 1
Content-Security-Policy: default-src 'self' 'unsafe-inline'
'unsafe-eval' data: blob:; frame-ancestors 'self'
X-Aggregate-Auth: 1
HTTP body chunked (-2)
< <?xml version="1.0" encoding="UTF-8"?>
< <config-auth client="vpn" type="auth-request" aggregate-auth-version="2">
< <opaque is-for="sg">
< <tunnel-group>$GROUP</tunnel-group>
< <auth-handle>$AUTH_HANDLE</auth-handle>
< <group-alias>$GROUP</group-alias>
< <config-hash>$CONFIG_HASH</config-hash>
< </opaque>
< <auth id="challenge">
< <title>Login</title>
< <message id="2" param1="Please select your second authentication
method [num]: 
1 - Okta Verify.
2 - Okta Verify Push.
3
- SMS Authentication.
4 - Google Authenticator.
Enter
'0' to abort.
" param2="">%s</message>
< <form>
< <input type="password" name="answer" label="Response:"></input>
< <input type="submit" name="Continue" label="continue"></input>
< </form>
< </auth>
< </config-auth>
Please select your second authentication method [num]:
1 - Okta Verify.
2 - Okta Verify Push.
3 - SMS Authentication.
4 - Google Authenticator.
Enter '0' to abort.
Response:
POST https://example.com/
> POST / HTTP/1.1
> Host: example.com
> User-Agent: Open AnyConnect VPN Agent v9.01
> Accept: */*
> Accept-Encoding: identity
> X-Transcend-Version: 1
> X-Aggregate-Auth: 1
> X-Support-HTTP-Auth: true
> Content-Type: application/xml; charset=utf-8
> Content-Length: 580
>
> <?xml version="1.0" encoding="UTF-8"?>
> <config-auth client="vpn" type="auth-reply" aggregate-auth-version="2"><version who="vpn">v9.01</version><device-id>mac-intel</device-id><capabilities><auth-method>single-sign-on</auth-method><auth-method>single-sign-on-v2</auth-method><auth-method>single-sign-on-external-browser</auth-method></capabilities><opaque is-for="sg">
> <tunnel-group>$GROUP</tunnel-group>
> <auth-handle>$AUTH_HANDLE</auth-handle>
> <group-alias>$GROUP</group-alias>
> <config-hash>$CONFIG_HASH</config-hash>
> </opaque><auth><password>4</password></auth></config-auth>
Got HTTP response: HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Transfer-Encoding: chunked
Cache-Control: no-store
Pragma: no-cache
Connection: Keep-Alive
Date: Thu, 10 Nov 2022 18:54:22 GMT
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-XSS-Protection: 1
Content-Security-Policy: default-src 'self' 'unsafe-inline'
'unsafe-eval' data: blob:; frame-ancestors 'self'
X-Aggregate-Auth: 1
HTTP body chunked (-2)
< <?xml version="1.0" encoding="UTF-8"?>
< <config-auth client="vpn" type="auth-request" aggregate-auth-version="2">
< <opaque is-for="sg">
< <tunnel-group>$GROUP</tunnel-group>
< <auth-handle>$AUTH_HANDLE</auth-handle>
< <group-alias>$GROUP</group-alias>
< <config-hash>$CONFIG_HASH</config-hash>
< </opaque>
< <auth id="challenge">
< <title>Login</title>
< <message id="2" param1="Enter the code for Google
Authenticator.
Enter '0' to abort.
"
param2="">%s</message>
< <form>
< <input type="password" name="answer" label="Response:"></input>
< <input type="submit" name="Continue" label="continue"></input>
< </form>
< </auth>
< </config-auth>
Enter the code for Google Authenticator.
Enter '0' to abort.
Response:
On Mon, Nov 7, 2022 at 8:02 PM Daniel Lenski <dlenski at gmail.com> wrote:
>
> On Fri, Nov 4, 2022 at 3:14 PM Ahmet Karalar <akaralar at gmail.com> wrote:
> >
> > Hello,
> >
> > I can connect to my company VPN (Cisco Anyconnect) using openconnect,
> > entering credentials as the CLI asks me, however I'd like to reduce
> > that to 1 step if possible. When authenticating, openconnect asks me:
> > - username
> > - password
> > - group
> > - second authentication method
> > - second authentication password (a TOTP)
> >
> > I know that I can pass the first 3 using CLI flags or a config file,
> > however I couldn't figure out how to select the second auth method and
> > then pass the second auth pass to the CLI. The second authentication
> > method form is a form with 4 values, of which I'd like to select
> > option 4 (TOTP auth), and then I'll enter the TOTP. I'm using a
> > password manager and I'll get the TOTP from there. Is there a way to
> > pass option 4 for the second auth method and then the second auth
> > password to openconnect, so that I can connect to the VPN using only a
> > single command?
>
> Likely yes. So, you've already got the following, right?
>
> echo "$PASSWORD" | openconnect -u "$USERNAME" --passwd-on-stdin
> --authgroup "$GROUP"
>
> Now, you'll need to use the `--form-entry` option to specify the
> second auth method (see
> https://www.infradead.org/openconnect/manual.html#opt-form-entry).
> First, start out by using `--dump` to extract the details of the
> second form, including the name of the form and the fields+values
> therein. That'll get you something like:
>
> echo "$PASSWORD" | openconnect -u "$USERNAME" --passwd-on-stdin
> --authgroup "$GROUP" --form-entry
> "${2FA_FORM_NAME}:${2FA_METHOD_FIELD_NAME}=${2FA_METHOD_FIELD_VALUE}"
>
> And then you'll need to specify `--token-mode=totp` and
> `--token-secret`
> (https://www.infradead.org/openconnect/manual.html#opt-token-mode) to
> tell OpenConnect how to fill in the TOTP field using your token.
>
> OpenConnect should in most cases automatically detect the field that
> is supposed to be filled with the token field value. If that *doesn't*
> work, then send us the complete output of `openconnect --dump` for
> that second form, and we'll figure out how it differs from the current
> expectations for a token field… or better yet submit a merge request
> to improve https://gitlab.com/openconnect/openconnect/blob/master/auth.c#L1004-1026).
>
> Daniel
More information about the openconnect-devel
mailing list