Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which parameter is used for authentication in LDAP

Tags:

ldap

In case of LDAP authenticaion, what are the parameters that are generally used for authentication. I guess using DN would be a headache for users logging in via ldap because it is too large to remember. How is the option of using uid or sAMAccountName for authentication where in my implementation, I retrieve the dn of the corresponding uid or sAMAccountName and proceed to authentication.

Am I going the right track?

like image 525
ashokadhikari Avatar asked Aug 30 '12 05:08

ashokadhikari


People also ask

What authentication does LDAP use?

There are two options for LDAP authentication in LDAP v3 – simple and SASL (Simple Authentication and Security Layer). Anonymous authentication: Grants client anonymous status to LDAP. Unauthenticated authentication: For logging purposes only, should not grant access to a client.

What is basic authentication LDAP?

Basic Authentication is simple and most widely used authentication mechanism in HTTP based services or APIs. The client sends HTTP requests with the Authorization HTTP header that contains the word Basic word followed by a space and a base64-encoded string username:password .


2 Answers

In LDAP, a connection or session can be authenticated. When an LDAP client makes a new connection to an LDAP directory server, the connection has an authorization state of anonymous. The LDAP client can request that the authorization state be changed by using the BIND request.

A BIND request has two forms: simple and SASL. Simple uses a distinguished name and a password, SASL uses one of a choice of mechanisms, for example, PLAIN, LOGIN, CRAM-MD5, DIGEST-MD5, GSSAPI, and EXTERNAL - all of which except for GSSAPI and EXTERNAL are too weak to use in production scenarios or mission-critical areas.

To Use the simple BIND, construct a BIND request and transmit it to the LDAP directory server. The LDAP directory server will respond with a BIND response in which is contained a result code. The result code is an integer, anything other zero indicates that the BIND request failed. If the result code is zero, the BIND request succeeded and the session authorization state has been changed to that of the distinguished name used in the BIND request.

Each subsequent BIND request on the same connection/session causes the authorization state to be set to anonymous and each successive successful BIND request on the same connection/session causes the authorization state to be set to the authorization state associated with the authentication ID, which is the distinguished name in the case of the simple BIND, but might be something else entirely where SASL is used - modern professional quality servers can map the incoming names to different DNs.

Whichever language is used, construct a BIND request, transmit it to the server, and interpret the response.

Update:

If the distinguished name is not known, or is too cumbersome (often the case with web application users who don't know how they are authenticated and would not care if they did know), the LDAP application should search the directory for the user. A successful search response always contains the distinguished name, which is then used in a simple BIND.

The search contains at a minimum, the following:

  • base object: a distinguished name superior to the user, for example, dc=example,dc=com
  • a scope: base level, one level below base, or subtree below base. For example, if users are located subordinate to ou=people,dc=example,dc=com, use base object ou=people,dc=example,dc=com and a scope of one-level. These search parameters find entries like: uid=user1,ou=people,dc=example,dc=com
  • a filter: narrows down the possible search results returned to the client, for example (objectClass=inetOrgPerson)
  • a list of requested attributes: the attributes from an entry to return to the client. In this case, use 1.1, which means no attributes and returns on the DN (distinguished name), which is all that is required for the simple BIND.

see also

the links in the about section here

like image 197
Terry Gardner Avatar answered Nov 23 '22 21:11

Terry Gardner


LDAP servers only understand LDAP queries; they don't have "usernames" like you and I are used to.

For LDAP, to authenticate someone, you need to send a distinguished name of that person's (or entity's) entry in LDAP; along with their password.

Since you mentioned sAMAccountName I am assuming you are working with Active Directory. Active Directory allows anonymous binds - this means you can connect to it without providing any credentials; but cannot do any lookups without providing credentials.

If you are using python-ldap and Cython (and not IronPython which has access to the various .NET APIs that make this process very easy); then you follow these steps.

Typically you use a pre-set user that has appropriate rights to the tree, and connect to the directory with that user first, and then use that user's access for the rest of the authentication process; which generally goes like this:

  1. Connect to AD with the pre-set user.
  2. Query active directory with the pre-set user's credentials and search for the distinguished name based on the sAMAccountName that the user will enter as their "username" in your form.
  3. Attempt to connect again to Active Directory using the distinguished name from step 2, and the password that the user entered in their form.
  4. If this connection is successful, then the user is authenticated.

So you need two main things:

  1. The login attribute (this is the "username" that LDAP understands)
  2. A LDAP query that fetches information for your users

Following is some rough code that can do this for you:

AD_USER = 'your super user'
AD_PASSWORD = 'your super user password'

AD_BIND_ATTR = 'userPrincipalName' # this is the "login" for AD
AD_URL = "ldap://your-ad-server"
AD_DN = "DC=DOMAIN,DC=COM"
AD_LOGIN_ATTR = 'sAMAccountName' # this is what you user will enter in the form
                                 # as their "login" name,
                                 # this is what they use to login to Windows

# A listing of attributes you want to fetch for the user
AD_ATTR_SEARCH = ['cn',
                  'userPrincipalName',
                  'distinguishedName',
                  'mail',
                  'telephoneNumber','sAMAccountName']

def _getbinduser(user):
    """ This method returns the bind user string for the user"""
    user_dn = AD_DN
    login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
    attr_search = AD_ATTR_SEARCH

    conn = ldap.initialize(AD_URL)
    conn.set_option(ldap.OPT_REFERRALS,0)
    conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)
    try:
        conn.bind(AD_USER,AD_PASSWORD)
        conn.result()
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        # Exit the script and print an error telling what happened.
        sys.exit("LDAP Error (Bind Super User)\n ->%s" % exceptionValue)
    try:
        result = conn.search_s(user_dn,
                               ldap.SCOPE_SUBTREE,
                               login_attr, attr_search)
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        # Exit the script and print an error telling what happened.
        sys.exit("LDAP Error (Search)\n ->%s" % exceptionValue)

    # Return the user's entry from AD, which includes
    # their 'distinguished name'
    # we use this to authenticate the credentials the
    # user has entered in the form
    return result[0][1]

def authenticate(user,password):

    bind_attr = AD_BIND_ATTR
    user_dn = AD_DN
    login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
    data = _getbinduser(user)

    if len(data) == 1:
        return None

    # Information we want to return from the directory
    # for each user, season to taste.

    info = {}
    info['name'] = data['cn'][0]
    info['email'] = data['mail'][0]
    try:
        info['phone'] = data['telephoneNumber'][0]
    except KeyError:
        info['phone'] = 'Not Available'

    conn = ldap.initialize(Config.AD_URL)
    conn.set_option(ldap.OPT_REFERRALS,0)
    conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)

    try:
        # Now we have the "bind attribute" (LDAP username) for our user
        # we try and connect to see if LDAP will authenticate
        conn.bind(data[bind_attr][0],password)
        conn.search(user_dn,ldap.SCOPE_SUBTREE,login_attr,None)
        conn.result()
        return info
    except (ldap.INVALID_CREDENTIALS,ldap.OPERATIONS_ERROR):
        return None
like image 37
Burhan Khalid Avatar answered Nov 23 '22 21:11

Burhan Khalid