how to make ocserv do totp 2FA?

Wang Jian larkwang at gmail.com
Mon May 18 12:52:14 PDT 2015


2015-05-19 1:49 GMT+08:00 Wang Jian <larkwang at gmail.com>:
> 2015-05-19 0:52 GMT+08:00 Nikos Mavrogiannopoulos <nmav at gnutls.org>:
>> On Mon, 2015-05-18 at 22:46 +0800, Wang Jian wrote:
>>> Hi,
>>>
>>> I am evaluating VPN with 2FA (w/ TOTP) supports inhouse.
>>>
>>> Currently, we use openvpn to do static 2FA (w/ shared client certificate), but
>>> it's not easy for hundreds of employee scale, and configuration file got leaked
>>> easily (actually happened). So this time, we do want to use a solution with less
>>> client setup effort.
>>> OpenConnect server and client are good starting point, coz openconnect &
>>> anyconnect clients all support 2FA.
>>>
>>> Although multiple factor authentication support is available for
>>> ocserv long ago,
>>> I can't find docs about how to make static password + totp work for ocserv.Is it
>>> possible?
>>> Obviously, the current ocserv auth backends don't support such setup. But if I
>>> can make client send username, password and 2nd password, I can hack a backend
>>> to do password & totp code auth for inhouse use. Anyone can help me out?
>>
>> Hi,
>>  I would be surprised if you couldn't use the PAM backend to require two
>> passwords, a static and TOTP. If you can make your login in your system
>> to ask 2FA then you can do ocserv as well (for HOTP/TOTP at least, U2F
>> is another story).
>
> I will try. My question is: when pam prompt for second password, how ocserv
> trigger it in client's UI?
>
> The way user inputs just one password which is concat(password, totp) is not I
> am looking at.
>

Ok, I write a simple pam-python script to test.

#/etc/pam.d/ocserv
auth    required        pam_krb5.so
auth    required        pam_python.so /etc/ocserv/pam/pam_totp.py

That is, authenticate using kerberos first, then check totp code.

#/etc/ocserv/pam/pam_totp.py
def pam_sm_authenticate(pamh, flags, argv):
    try:
        username = pamh.get_user()
    except pamh.exception:
        username = None

    if username == None:
        return pamh.PAM_USER_UNKNOWN

    prompt = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Please enter your code")
    try:
        resp = pamh.conversation(prompt)
    except pamh.exception:
        return pamh.PAM_SYSTEM_ERR
    if resp.resp == '6666':
        return pamh.PAM_SUCCESS
    else:
        return pamh.PAM_USER_UNKNOWN

With this setup, Cisco anyconnect android client will ask username, password and
password again. If all information is correct, the vpn connection is established
successfully.

But OpenConnect android client will fail immediately after prompting
for and get first
password. According to log, I think it's because OC android client
uses first password
directly for second prompt, and fails.

That is the very question I ask at first.



More information about the openconnect-devel mailing list