Activating a VPN connection without displaying the authentication dialog



Hello,

The company I work for uses Cisco AnyConnect and I have been using
NetworkManager with the OpenConnect plugin to connect to it for some time
now. Soon, however, they will be enabling SAML (for 2FA with Azure AD)
which is not supported in the OpenConnect plugin for NetworkManager.

I've written a Python script that does the initial handshake/2FA and obtains
the 3 secrets needed to connect - the cookie, gateway certificate hash and
the gateway address. I am sure these secrets are correct because I can
manually run openconnect, pass the secrets to it, and it successfully
connects. This is functional but not great with regards to 'user experience'.

I would like to programmatically configure a NetworkManager VPN connection
and activate it using the secrets I obtain via the manual handshake. The
problem I am facing is that I always get the VPN authentication dialog, even
though I set the secrets on the connection.

The question I have is: is there a way to tell NetworkManager that it can
skip the authentication step and just bring up the connection with the
secrets I already provided?

Here is the code I have come up with so far:

    import uuid
    import gi
    gi.require_version('NM', '1.0')
    from gi.repository import NM, GLib
    g_vpn_server = 'vpn.example.com'
    (cookie, gwcert) = do_saml_2fa(g_vpn_server)  # implemented elsewhere

    def create_profile(name: str) -> NM.SimpleConnection:
        profile = NM.SimpleConnection.new()
        s_con = NM.SettingConnection.new()
        s_con.set_property(NM.SETTING_CONNECTION_ID, name)
        s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4()))
        s_con.set_property(NM.SETTING_CONNECTION_TYPE, "vpn")

        s_ip4 = NM.SettingIP4Config.new()
        s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")

        s_vpn = NM.SettingVpn.new()
        s_vpn.set_property(
           'service-type',
           'org.freedesktop.NetworkManager.openconnect')

        s_vpn.add_data_item('protocol', 'anyconnect')
        s_vpn.add_data_item('gateway', g_vpn_server)
        s_vpn.add_data_item('cacert', '<redacted>')
        s_vpn.add_data_item('usercert', '<redacted>')
        s_vpn.add_data_item('userkey', '<redacted>')
        s_vpn.add_data_item('enable_csd_trojan', 'no')
        s_vpn.add_data_item('pem_passphrase_fsid', 'no')

        s_vpn.add_secret('autoconnect', 'yes')
        s_vpn.add_secret('save_passwords', 'no')

        profile.add_setting(s_con)
        profile.add_setting(s_ip4)
        profile.add_setting(s_vpn)

        return profile

    def handle_connection_activate(nm, res, loop):
        try:
            ret = nm.activate_connection_finish(res)
            print(ret)
        except Exception as e:
            print(f'ERROR: {e}')
        loop.quit()

    def handle_changes_saved(rc, res, data):
        remote_conn, loop = data
        ret = remote_conn.commit_changes_finish(res)
        print(f'CHANGES SAVED: {ret}')

        if ret:
            nm.activate_connection_async(
                remote_conn,
                None,
                None,
                None,
                handle_connection_activate, loop)
        else:
            loop.quit()

    def handle_connection_add_finish(nm, res, data):
        loop, cookie, gateway, gwcert = data
        ret = nm.add_connection_finish(res)
        print(f'{type(ret)} - {ret.get_path()}')
        s_vpn = ret.get_setting_vpn()
        s_vpn.add_secret('cookie', cookie)
        s_vpn.add_secret('gateway', gateway)
        s_vpn.add_secret('gwcert', gwcert)

        s_vpn.set_secret_flags('cookie', NM.SettingSecretFlags.NOT_SAVED)
        s_vpn.set_secret_flags('gateway', NM.SettingSecretFlags.NOT_SAVED)
        s_vpn.set_secret_flags('gwcert', NM.SettingSecretFlags.NOT_SAVED)

        print(ret.need_secrets(), ret.verify_secrets())
        ret.commit_changes_async(
            False,
            None,
            handle_changes_saved,
            (ret, loop))

    nm = NM.Client.new(None)
    p = create_profile('vpn-sso')
    print(p.verify_secrets(), p.verify())
    loop = GLib.MainLoop()
    nm.add_connection_async(
        p,
       True,
       None,
       handle_connection_add_finish,
       (loop, cookie, g_vpn_server, gwcert))
    loop.run()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]