cisagov / ansible-role-openvpn

Ansible role to install an OpenVPN server and configure it to authenticate users certificates against FreeIPA.
Creative Commons Zero v1.0 Universal
8 stars 2 forks source link

Escape LDAP filter subjects #6

Closed felddy closed 4 years ago

felddy commented 4 years ago

🐛 Bug Report

Users who have parenthesis (and other characters) in their PIV subjects will break the LDAP lookup in verify-cn.py

To Reproduce

Steps to reproduce the behavior:

How to fix

This is the fix:

    import ldap.filter
# ...
def query_ldap(ldap_ordered_dn):
    """Query LDAP server and return True if user should be permitted."""
    con = ldap.initialize(LDAP_URI)
    con.sasl_gssapi_bind_s()
    # Convert realm into a base DN. e.g.; dc=cool,dc=cyber,dc=dhs,dc=gov
    realm_dn = ",".join([f"dc={x.lower()}" for x in REALM.split(".")])
    base_dn = f"cn=users,cn=accounts,{realm_dn}"
    vpngroup_dn = f"cn={VPN_GROUP},cn=groups,cn=accounts,{realm_dn}"
    logging.debug(f"Searching for user mapped to certificate: {ldap_ordered_dn}")
    escaped_dn = ldap.filter.escape_filter_chars(ldap_ordered_dn)
    rec = con.search_s(
        base_dn,
        ldap.SCOPE_SUBTREE,
        f"(ipaCertMapData=X509:<I>*<S>{escaped_dn})",
        attrlist=["memberOf"],
    )
    if len(rec) == 0:
        logging.warning("No matching certificate found in LDAP")
        logging.warning(f"Searched for: {ldap_ordered_dn}")
        return False

    if len(rec) > 1:
        logging.warning(f"More than 1 record found in LDAP.  Count: {len(rec)}.")
        return False

    user_dn, attribute_list = rec[0]
    logging.info(f"Found user in LDAP: {user_dn}")
    users_groups = attribute_list.get("memberOf")
    # Check to see if user is a member of the correct group
    permit_user = vpngroup_dn.encode("utf-8") in users_groups
    if permit_user:
        logging.info(f"User is member of {vpngroup_dn}")
    else:
        logging.warning(f"User IS NOT member of {vpngroup_dn}")
    return permit_user

This code is live on the production VPN host. Needs to be committed to the repo.