LDAP simple bind parameters - ldap

I am trying to use ldap for a flask application .
The app.config['LDAP_PROVIDER_URL'] = 'ldaps://appauth.corp.domain.com:636'
(I have replaced the domain for the original name here)
In another script in need the following ldap details
conn.simple_bind_s(
'cn=%s,ou=Users,dc=corp,dc=domain,dc=com' % username,
password
)
How do I find the OU,or can i ignore OU and drop it from above. Please let me know if other parameters are correct. I don't know LDAP

The general idea is that you bind as an application account with search privileges to locate the user account, e.g. by his email address, displayName, etc., and then use that DN to rebind using the password he supplied.

Related

Use sAMAcountName from ldap as username

I connected our active directory to keycloak (4.0.0.Beta1) and imported the users - this works fine.
But the username should be filled from sAMAccountName. So i changed the Username LDAP attribute to that.
But after clicking Synchronize all users i am getting this error in the console window:
8:20:13,372 ERROR [org.keycloak.storage.ldap.LDAPStorageProviderFactory] (default task-119) Failed during import user from LDAP: org.keycloak.models.ModelException: User returned from LDAP has null username! Check configuration of your LDA
mappings. Mapped username LDAP attribute: cn, user DN: CN=Mustermann Max,OU=Normung,OU=Mech,OU=Konstruktion,OU=Abteilungen,DC=company,DC=org, attributes from LDAP: {whenChanged=[2017037125253.0Z], whenCreated=[20140520092805.0
], mail=[Max.Mustermann#company.org], givenName=[Max], sn=[Mustermann], userAccountControl=[66048], pwdLastSet=[130750516258418527]}
at org.keycloak.storage.ldap.LDAPUtils.getUsername(LDAPUtils.java:113)
at org.keycloak.storage.ldap.LDAPStorageProviderFactory$3.run(LDAPStorageProviderFactory.java:521)
at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
at org.keycloak.storage.ldap.LDAPStorageProviderFactory.importLdapUsers(LDAPStorageProviderFactory.java:514)
at org.keycloak.storage.ldap.LDAPStorageProviderFactory.syncImpl(LDAPStorageProviderFactory.java:469)
at org.keycloak.storage.ldap.LDAPStorageProviderFactory.sync(LDAPStorageProviderFactory.java:407)
...
I tried some mappers (especially username) but with no luck. It seems that there are only a few attributes read from the ldap server (see attributes from LDAP:... in the output).
Namely: whenChanged, whenCreated, mail, givenName, sn, userAccountControl, pwdLastSet.
How can i get the sAMAcountName attribute as username?
I have just tested it in 4.1.0.Final and there it works when you change the Username LDAP attribute to sAMAccountName and additionally the
LDAP Attribute in the username mapper also to sAMAccountName.
I tried some mappers (especially username) but with no luck.
Your question suggest, that you already tried doing something in the username mappers. So you were definetly on the right track. Either there was a bug in your version, or the two fields didn't match correctly.
For me, it worked. Please find the below process:
1) In User Federation -> LDAP Provider -> There is a setting called "UserName LDAP Attribute". (as shown here ldap provider settings)
2) Select Mappers tab and edit "username" mapper and change to following settings: username mapper settings

How to change the default 'admin' username in Apache DS?

Long story short the security people at my company does not want us to use the default 'admin' username in Apache DS. Is there a way to change it without breaking anything? Also how to create an additional admin account that is a clone of the default 'admin' user? I couldn't find any documentation for this.
You can use Apache Directory Studio to do this:
Copy (Ctrl-C) entry uid=admin
Paste (Ctrl-V) into ou=system renaming the user entry on the way
Select cn=Administrators,ou=groups,ou=system
Add a member reference to the new user entry
Check you can successfully bind using the new user

OpenAM / OpenDJ custom username field works with less than 4000 users

I am currently working on a project that uses OpenAM 12.0.2 with OpenDJ 2.6
We had a requirement to make the username editable. So, we ended up creating a custom ldap attribute called loginId and updating OpenAM config to use this attribute instead of uid.
When I import less than 4000 users, login works fine. When I import 4000+ users login doesn't work for any user, even 1 of the first 4000 users in the directory.
I can manually ldapsearch for the users and they exist in the directory, but I can't login with any of them.
We get an "Authorization failed!!" error, which is different to the usual username/password doesn't match error.
If anyone could shed any light on this, I would appreciate it.
Thanks
Edit
Here is the attribute definition I am now using.
attributeTypes: ( 1.3.6.1.4.1.37238.2.9 NAME 'loginId' DESC 'username (that can be updated)' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'project schema')
I have rebuilt the indices and still having the same problem :(
That is probably because your instance of OpenDJ is configured to reject unindexed search request and you haven't defined and built an index for the loginID attribute.

LDAP Authentication failed: Invalid Credentials

In Gforge, when a new user tries to log in; the user is automatically registered by fetching data from LDAP. It works fine for other users but one particular user is not able to log in and gets the error LDAP Authentication failed: Invalid Credentials . I don't understand what could be the issue? Could you please help?
This is the search function I am using.
ldap_bind($ldap, $dn, $pw)
$dn = ldap_get_dn($ldap, $entry);
$entry = ldap_first_entry($ldap,$res);
$res=ldap_search($ldap, $sys_ldap_base,$sys_ldap_id_attribute . '=' . $id,
array());
If it works for some users but not for one specific user, then it's something to do with the LDAP configuration, or with the characters in that user's ID or pwd.
Is the failing user in a different org/OU? Do they have accent characters in their username or password? These things can cause compatibility issues between GForge and the LDAP server.
Does this user have a much longer user name than other users? There is a GForge config setting called "usernameregex" that governs the complexity and length of allowed user names. Even though LDAP logins result in automatic account creation, the validation of the user's unix name might fail due to the regex in place. The error noted above could certainly be the catch-all message when this happens.
The default setting is "^[a-z0-9_.-]{3,15}$". You can change the upper length limit by changing the 15 to something else. The unix_name field in the GForge database is TEXT, so it can be extremely long (1GB?).
In GForge 6.3.x and earlier, you can find that setting in /etc/gforge/gforge.conf. Change the value and then update the system using:
cd /opt/gforge/bin && php create_config_cache.php
In GForge 6.4 and later, you can use the gf-config utility to set the value. It will take effect right away:
/opt/gforge/bin/gf-config set "usernameregex" "new regex value"

Which parameter is used for authentication in 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?
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
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:
Connect to AD with the pre-set user.
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.
Attempt to connect again to Active Directory using the distinguished name from step 2, and the password that the user entered in their form.
If this connection is successful, then the user is authenticated.
So you need two main things:
The login attribute (this is the "username" that LDAP understands)
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
One small expansion on Terry's excellent comment. If you store all your users in the same part of the DIT, and use the same attribute to identify them, you can programmatically construct the DN, rather than searching for it.