Duo Authentication Proxy - Cannot find username

I’m trying to set up a Duo Authentication Proxy server and while I’ve made some progress, I’ve just run into an issue I can’t find documented anywhere.

We’re using the proxy so we can use Duo for vSphere (6.7).

vSphere is set up with an identity source that has details for our active directory and points to our proxy. I can create the identity source and search for users and add them to roles in vSphere.

I tried logging in as myself (from that identity source) and was surprised to see it work but without the 2FA prompt.

I then found this: https://help.duo.com/s/article/4989?language=en_US

The behavior is exactly what I experienced. So I went ahead and set exempt_primary_bind=false and exempt_ou_1=[dn of our service account].

Then when I tried to log in, vSphere reported a generic “invalid credentials” message, and authproxy.log showed “Cannot find username”.

2020-11-17T12:03:09-0800 [duoauthproxy.modules.ad_client._ADServiceClientFactory#info] Starting factory <duoauthproxy.modules.ad_client._ADServiceClientFactory object at 0x0000014421FC5DF0>
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] S<-C LDAPMessage(id=1, value=LDAPBindRequest(version=3, dn='uid=<Service Account>,ou=applications,<Our Org>', auth='****', sasl=False), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.lib.log#info] Connection made between client: <vSphere IP>:48106 and the server section listening via <Duo Proxy IP>:389.
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C->S LDAPMessage(id=1, value=LDAPBindRequest(version=3, dn='uid=<Service Account>,ou=applications,<Our Org>', auth='****', sasl=False), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=1, value=LDAPBindResponse(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.lib.log#info] [Request from <vSphere IP>:48106] Exempt OU: uid=<Service Account>,ou=applications,<Our Org>
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=1, value=LDAPBindResponse(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] S<-C LDAPMessage(id=2, value=LDAPSearchRequest(baseObject='', scope=0, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_present(value='objectclass'), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] C->S LDAPMessage(id=2, value=LDAPSearchRequest(baseObject='', scope=0, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_present(value='objectclass'), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=2, value=L■■■■■■■■■■■■■■■■■■■■(objectName='', attributes=[('objectClass', ['top', 'ds-root-dse']), ('startupUUID', ['8726dbb1-7888-431e-a9c9-f83fdf0188d3']), ('startTime', ['20200531184959Z'])]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=2, value=L■■■■■■■■■■■■■■■■■■■■(objectName='', attributes=[('objectClass', ['top', 'ds-root-dse']), ('startupUUID', ['8726dbb1-7888-431e-a9c9-f83fdf0188d3']), ('startTime', ['20200531184959Z'])]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=2, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=2, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] S<-C LDAPMessage(id=3, value=LDAPSearchRequest(baseObject='ou=people,<Our Org>', scope=2, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=255, filter=LDAPFilter_and(value=[LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='objectClass'), assertionValue=BEROctetString(value='inetOrgPerson')), LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='uid'), assertionValue=BEROctetString(value='<My Username>'))]), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] C->S LDAPMessage(id=3, value=LDAPSearchRequest(baseObject='ou=people,<Our Org>', scope=2, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=255, filter=LDAPFilter_and(value=[LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='objectClass'), assertionValue=BEROctetString(value='inetOrgPerson')), LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='uid'), assertionValue=BEROctetString(value='<My Username>'))]), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=3, value=L■■■■■■■■■■■■■■■■■■■■(objectName='uid=<My Username>,ou=People,<Our Org>', attributes=[<Our Attributes>]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=3, value=L■■■■■■■■■■■■■■■■■■■■(objectName='uid=<My Username>,ou=People,<Our Org>', attributes=[<Our Attributes>]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=3, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=3, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.modules.ad_client._ADServiceClientFactory#info] Starting factory <duoauthproxy.modules.ad_client._ADServiceClientFactory object at 0x00000144221EE940>
2020-11-17T12:03:09-0800 [ldap_server_auto,1,<vSphere IP>] S<-C LDAPMessage(id=1, value=LDAPBindRequest(version=3, dn='uid=<My Username>,ou=People,<Our Org>', auth='****', sasl=False), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.lib.log#info] Connection made between client: <vSphere IP>:48108 and the server section listening via <Duo Proxy IP>:389.
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C->S LDAPMessage(id=4, value=LDAPBindRequest(version=3, dn='uid=<My Username>,ou=People,<Our Org>', auth='****', sasl=False), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=4, value=LDAPBindResponse(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.modules.ad_client._ADServiceClientFactory#info] Starting factory <duoauthproxy.modules.ad_client._ADServiceClientFactory object at 0x00000144221FB0A0>
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C->S LDAPMessage(id=5, value=LDAPBindRequest(version=3, dn='uid=<Service Account>,ou=applications,<Our Org>', auth='****', sasl=False), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=5, value=LDAPBindResponse(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C->S LDAPMessage(id=6, value=LDAPSearchRequest(baseObject='uid=<My Username>,ou=People,<Our Org>', scope=2, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_and(value=[LDAPFilter_or(value=[LDAPFilter_and(value=[LDAPFilter_equalityMatch(attributeDesc=L■■■■■■■■■■■■■■■■■■■■ion(value='objectClass'), assertionValue=LDAPAssertionValue(value='user')), LDAPFilter_equalityMatch(attributeDesc=L■■■■■■■■■■■■■■■■■■■■ion(value='objectCategory'), assertionValue=LDAPAssertionValue(value='person'))]), LDAPFilter_equalityMatch(attributeDesc=L■■■■■■■■■■■■■■■■■■■■ion(value='objectClass'), assertionValue=LDAPAssertionValue(value='inetOrgPerson')), LDAPFilter_equalityMatch(attributeDesc=L■■■■■■■■■■■■■■■■■■■■ion(value='objectClass'), assertionValue=LDAPAssertionValue(value='organizationalPerson'))])]), attributes=('sAMAccountName',)), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=6, value=L■■■■■■■■■■■■■■■■■■■■(objectName='uid=<My Username>,ou=People,<Our Org>', attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=6, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C->S LDAPMessage(id=7, value=LDAPUnbindRequest(), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.lib.log#info] [Request from <vSphere IP>:48108] Cannot find username
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=1, value=LDAPBindResponse(resultCode=49, errorMessage='Cannot find username'), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.modules.ad_client._ADServiceClientFactory#info] Stopping factory <duoauthproxy.modules.ad_client._ADServiceClientFactory object at 0x00000144221FB0A0>
2020-11-17T12:03:09-0800 [ldap_server_auto,1,<vSphere IP>] S<-C LDAPMessage(id=2, value=LDAPUnbindRequest(), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,1,<vSphere IP>] C->S LDAPMessage(id=8, value=LDAPUnbindRequest(), controls=None)
2020-11-17T12:03:09-0800 [duoauthproxy.lib.log#info] Closing the connection between the downstream application and the Authentication Proxy. Reason: Connection was closed cleanly: Connection done.
2020-11-17T12:03:09-0800 [duoauthproxy.modules.ad_client._ADServiceClientFactory#info] Stopping factory <duoauthproxy.modules.ad_client._ADServiceClientFactory object at 0x00000144221EE940>
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] S<-C LDAPMessage(id=4, value=LDAPSearchRequest(baseObject='', scope=0, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_present(value='objectclass'), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] C->S LDAPMessage(id=9, value=LDAPSearchRequest(baseObject='', scope=0, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_present(value='objectclass'), attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=9, value=L■■■■■■■■■■■■■■■■■■■■(objectName='', attributes=[('objectClass', ['top', 'ds-root-dse']), ('startupUUID', ['8726dbb1-7888-431e-a9c9-f83fdf0188d3']), ('startTime', ['20200531184959Z'])]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=4, value=L■■■■■■■■■■■■■■■■■■■■(objectName='', attributes=[('objectClass', ['top', 'ds-root-dse']), ('startupUUID', ['8726dbb1-7888-431e-a9c9-f83fdf0188d3']), ('startTime', ['20200531184959Z'])]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=9, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=4, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] S<-C LDAPMessage(id=5, value=LDAPSearchRequest(baseObject='ou=people,<Our Org>', scope=2, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_and(value=[LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='objectClass'), assertionValue=BEROctetString(value='inetOrgPerson')), LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='uid'), assertionValue=BEROctetString(value='<My Username>'))]), attributes=[b'userAccountControl', b'pwdAccountLockedTime']), controls=None)
2020-11-17T12:03:09-0800 [ldap_server_auto,0,<vSphere IP>] C->S LDAPMessage(id=10, value=LDAPSearchRequest(baseObject='ou=people,<Our Org>', scope=2, derefAliases=0, sizeLimit=0, timeLimit=0, typesOnly=0, filter=LDAPFilter_and(value=[LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='objectClass'), assertionValue=BEROctetString(value='inetOrgPerson')), LDAPFilter_equalityMatch(attributeDesc=BEROctetString(value='uid'), assertionValue=BEROctetString(value='<My Username>'))]), attributes=[b'userAccountControl', b'pwdAccountLockedTime']), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=10, value=L■■■■■■■■■■■■■■■■■■■■(objectName='uid=<My Username>,ou=People,<Our Org>', attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=5, value=L■■■■■■■■■■■■■■■■■■■■(objectName='uid=<My Username>,ou=People,<Our Org>', attributes=[]), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] C<-S LDAPMessage(id=10, value=LDAPSearchResultDone(resultCode=0), controls=None)
2020-11-17T12:03:09-0800 [_ADServiceClientProtocol (TLSMemoryBIOProtocol),client] S->C LDAPMessage(id=5, value=LDAPSearchResultDone(resultCode=0), controls=None)

Any ideas? I’m not sure why it’s showing “Cannot find username” or what part of the process is actually throwing that. Again, I can log in fine (without 2FA) if I leave out exemp_primary_bind and exempt_ou_1. Additionally, if I add exempt_ou_2 and set it to the DN of my username, I can log in again (with 2FA bypassed), so I believe I’m specifying the DN properly for exempt_ou_1.

Thanks

It seems that the error message is referring to not finding the Duo username among the default set of returned attributes from the LDAP search request.

I found that adding username_attribute=<Our Principal Attribute, user@org.domain> and at_attribute=<Our Principal Attribute, user@org.domain> seemsedto make it find my username and then attempt 2FA.

I guess the Duo default for username_attribute is “sAMAccountName” and for at_attribute it’s “userPrincipalName”. These either don’t exist in our LDAP or my service account doesn’t have access to them, I’m not sure. The attributes I pointed the config to have the actual unique usernames, so I think it should be fine.

However, with the 2FA attempt, nothing actually fired off a request to my phone with Duo on it. The logs show that it successfully finds the username, and then it spits out a preauth URL which I had to access from a browser.

I went through the Duo setup (which I have already done previously) and provided a phone number. Then it worked.

I don’t know if this impacted my previous Duo stuff in any way or not, or why it didn’t know that I already had Duo set up and attach the request to that.

So far it seems to be working, but with a messy initial setup for each user. Is it expected that I would have to dig into the logs and find the preauth URL and send it to the user?

vSphere simply spits out a generic “Invalid credentials”, and doesn’t redirect to or otherwise expose the Duo enrollment link.

Yes, if you are not actually using ad_client with Active Directory then you have to define the actual attributes for your LDAP directory, which you did.

All users of this integration must exist in Duo with a valid authenticator BEFORE logging in, because, as you already observed, the enrollment message can’t be displayed to the user in the vSphere UI.

From LDAP | Duo Security

This configuration doesn’t support inline self-service enrollment. You’ll need to create your users in Duo ahead of time using one of our other enrollment methods, like directory sync or CSV import. Read the enrollment documentation to learn more.

The problem is all of our users already do exist in Duo.

I don’t have access to our Duo Admin Panel (I have to go through a ticketing system to request the iKey, sKey, and API Hostname), but this has been a recurring problem in our deployments. Users have to keep re-enrolling in Duo every time a new application enables Duo, even though those same users (with the same exact user ID in the directory) are already enrolled in our (single) Duo instance.

Does Duo segregate enrollment for each application instance or something like that? If so, I don’t see a way for us to send enrollment emails to our users, as I don’t’ have access to our Duo Admin Panel.

I think you probably need to ask your Duo admin some questions…

  1. What format is used for the existing usernames in Duo?
  2. What is the username normalization setting for your LDAP application?

It may be that the username format vSphere sends to Duo is different from how they are already enrolled (like if vCenter sends the UID for a given user but that user is enrolled in Duo under their email address). Therefore, every authentication coming from vSphere is seen as a new Duo user.

There are a few options from the Duo service side:

  1. The Duo admin changes the username normalization setting on the LDAP application to try to get it to match (this would help if vCenter was sending the username as email but the users exist in in Duo with just the email prefix before the @ as the username).

  2. The Duo admin adds username aliases to the users representing the usernames sent from vSphere.

For our application (vSphere), it appears that it was a simple matter of choosing the attribute that does not include @ instead of the one that does. Or we could have requested normalization be enabled in our Admin Panel (we don’t have direct access).

However, we have other applications (that we don’t control) that behave differently. I’m not sure what they’re doing (I don’t control them).

There are 2 viable user ID values in our directory (with @ and without), yet somehow between most applications (tied to the attribute without @), our application (originally tied to the attribute with @) and some other applications (unknown configuration), we had 3 different enrollment processes per user.

It’s working for us now. It was simply a normalization / @ vs non-@ issue resulting in multiple accounts being created in Duo. I’m not responsible for those other applications and don’t have access to their configs, so I’m not going to worry about them.

Thanks