How to configure hashicorp vault v1.2.3 to restrict login based on membership in an LDAP group? - ldap

active directory LDAP configuration:
Key Value
--- -----
binddn CN=BindVault,OU=my-ou,DC=ad,DC=xyz,DC=net
case_sensitive_names true
certificate n/a
deny_null_bind true
discoverdn false
groupattr memberOf
groupdn DC=ad,DC=xyz,DC=net
groupfilter (&(objectClass=person)(sAMAccountName={{.Username}}))
insecure_tls false
starttls true
tls_max_version tls12
tls_min_version tls12
token_bound_cidrs []
token_explicit_max_ttl 0s
token_max_ttl 0s
token_no_default_policy true
token_num_uses 0
token_period 0s
token_policies []
token_ttl 0s
token_type default
upndomain n/a
url ldaps://ldaps.ad.xyz.net:636
use_pre111_group_cn_behavior true
use_token_groups true
userattr cn
userdn DC=ad,DC=xyz,DC=net
This works ok, in that when a user logs in, the query returns the groups that the user is a member of, and policies can be mapped to groups.
The problem is with users who are not a member of any ldap policy groups. Currently, these users are able to log in, but are denied access to everything because they are not assigned any policies. I would prefer that they can't log in at all.

It looks like there is an open pull request that will add a filter for users that can be used to allow access to only specified LDAP users. The pull request has passed all the automated checks and is awaiting review so will hopefully be added soon.

I think I found the solution, I added the userfilter in the auth/ldap/config and configured it like this :
userfilter=“(&(objectClass=user)({{.UserAttr}}={{.Username}})(memberOf=cn=MySelectedGroup,cn=Users,dc=test,dc=com))”
So change the memberOf= at the end so that it matches your ldap group.
Have a nice day :)

Related

Keycloak cannot propagate user-group mappings from LDAP into user-group mappings

I am trying to setup User Federation from a LDAP server to Keycloak. I managed to import all the users and groups respectively from LDAP server, however, the user-group (group tab in Users section) doesn’t show the actual mapped groups, although I can see those users presenting in the groups listed in Members tab in Groups section…
I went through all article in Keycloak forum/Jira ticket/Mail list and I did find a ticket describing the exact issue that I am experiencing now (https://lists.jboss.org/pipermail/keycloak-user/2018-February/013076.html) and Marek has also replied to that as well, however, I still couldn't figure out what configuration I set incorrectly just by the information provided in the post.
Could anyone please help me out? Thanks ahead!
User-Group
Group
User Configuration
Group Mapper Configuration
Thanks,
Chance
Looks like the issue was in LDAP server. The problem only exists when I import the users from FreeIPA DB. However, when I try to federate to an AD server, the user-group information just comes along with the users without any additional modification!
Below is the configuration I have used in the successful case. Hopefully it will help others who encounter with a similar issue. Thanks everyone for the attention.
[User Federation Provider Settings]
Enabled: ON (Default)
Console Display Name :
Priority: 0 (Default)
Import Users : ON (Default)
Edit Mode : READ_ONLY
Sync Registrations : OFF (Default)
Vendor : Active Directory (This is important. Once I switch to AD, instead of FreeIPA, the issue is gone)
Username LDAP attribute: sAMAccountName
RDN LDAP attribute : cn
UUID LDAP attribute : objectGUID
User Object Classes : person, organizationalPerson, user (You should check what Object Class the server is currently configured and adjust accordingly)
Connection URL : ldap://:389 (If you are using ldaps, the port is 636)
Users DN : <the scope includes all your users you would like to import, e.g. OU=User,DC=example,DC=com)
Bind Type: simple
Enable StartTLS: OFF (Default)
Bind DN:
Bind Credential:
Custom User LDAP Filter: <You can leave it blank if you don't want to filter. However, if you would like to filter something, for example, users from a specific group, you can run a filter such as (&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=CN=,OU=,DC=example,DC=com)) >
Search Scope: Subtree (It the users after under one level of Users DN, you can choose "One level" option)
Validate Password Policy: OFF (Default)
Trust Email: OFF (Default)
Use Truststore SPI: Only for ldaps
Connection Pooling: On
The rest of setting leave it blank.
You need to configure a group-ldap-mapper as well
[Group Mapper]
Name:
Mapper Type: group-ldap-mapper
LDAP Groups DN : <Where are the groups of this tree saved. For example, OU=Group,DC=example,DC=com>
Group Name LDAP Attribute : cn
Group Object Classes : group
Preserve Group Inheritance: ON
Ignore Missing Groups: OFF (Default)
Membership LDAP Attribute : member
Membership Attribute Type: DN
Membership User LDAP Attribute: sAMAccountName
LDAP Filter : <You can leave it blank if you don't want to filter any group>
Mode: READ_ONLY
User Groups Retrieve Strategy: LOAD_GROUPS_BY_MEMBER_ATTRIBUTE
Member-Of LDAP Attribute: memberOf
Mapped Group Attributes:
Drop non-existing groups during sync: ON

No LDAP Groups being associated with Gerrit

I am trying to set up a gerrit instance that communicates with our LDAP server.
I can login with ldap credentials but then I don't see any groups when I navigate to My -> Groups. I tried using the "groupMemberPatter" variable but I did get an error saying that the LDAP backend doesn't support it. This is my ldap and auth configuration:
[auth]
type = ldap
[ldap]
server = ldap://ldapserverip
accountBase = DC=myorg,DC=local
accountPattern = (&(objectClass=person)(sAMAccountName=${username}))
groupBase = OU=DevGroups,DC=myorg,DC=local
groupPattern = (&(objectClass=group)(cn=${groupname}))
fetchMemberofEagerly = true
groupName = cn
username = CN=MyFirst MyLast,CN=Users,DC=myorg,DC=local
accountMemberField = memberOf
referral = follow
groupsVisibleToAll = true
localUsernameToLowerCase = true
I do have the password in the secure.config file and it seems that it makes the queries because it does allow a user to log in. I'm just having trouble getting the actual groups.
I'm not very familiar with LDAP or Active Directory but I was looking at our Active Directory through the Apache Directory Studio and I can indeed see a tree that looks like this:
Root
|- DC=myorg,DC=local
|- CN=Users
| |- CN=FirstName1 LastName1
| |- CN=FirstName2 LastName2
| | - ..
| | - CN=FirstName3 LastName3
|- OU=DevGroups
|- CN=Group1
|- CN=Group2
|- ..
|- CN=Group20
When I open the a group entry I can see the
objectClass=group
objectCategory=CN=Group,CN=Schema,CN=Configuration,DC=myorg,DC=local
The cn seems to be the group name
It does have a number of "member" fields that list users
The sAMAccountName is also the group name
If I look at a user they have
objectClass=person
cn=First Last
ojbectCategory= cn=Person,CN=Schema,CN=Configuration,DC=myorg,DC=local,
sAMAccountName=FirstLast.
They have a number of memberOf fields that list the cn,ou,dc,dc.
So if the user querying is working and it seems to be using a base and then searching from there and using the account pattern to fill in the username I would imagine that the same would hold for find the list of groups that a user belongs to.
The way I expect this to work is when a user logs in with their LDAP credentials, they should see their same LDAP groups when they look at their groups through the gerrit interface. I'm not sure if this is correct though. I'm also somewhat confused how gerrit actually uses these variables in queries. If anyone has any ideas or can point me in the right direction, I'd appreciate it.
I do realize there were some other Gerrit/LDAP related questions here and other places but they mostly seemed to focus on just getting a user logged in, which I can do, the groups are were I'm having an issue.
The My -> Groups page only lists internal groups; it does not include groups in external systems like LDAP.

Openshift - multiple auth providers

Does openshift (Origin or Enterprise) support multiple auth providers ?
eg 1. htpasswd (if not found ) 2. ldap
This link talks about various auth supported but can we use multiple
...
oauthConfig:
identityProviders:
- name: htpasswd_auth
challenge: true
login: false
mappingMethod: "claim"
...
- name: "my_ldap_provider"
challenge: true
login: true
mappingMethod: claim
provider:
...
Yes, you can specify multiple auth providers. Just make sure they have different names. You'll also want to be careful cases where their preferred usernames will collide. claim (like you have it) is a pretty safe default. See https://docs.openshift.com/enterprise/3.2/install_config/configuring_authentication.html#mapping-identities-to-users if you want to read up on alternatives.

How to unlock user on ApacheDS

I setup an ApacheDS with default password-policy enabled. For testing proposes I locked a simple User (objectClass=Person extended with some custom User-objectClass) by entering the wrong credentials a number of times. As I expected the user was locked (error msg: user was permanently locked).
The question now is: How to unlock the user again? Is there a better way then just deleting and adding again?
I tried the same with an extended user (objectClass=pwdPolicy) but no pwd* attributes were added when the user was locked.
More recently, I encountered the same problem at work. But, it seems that there is no answer on Internet. Finally,I found the answer by viewing this document:
Password Policy for LDAP Directories draft-behera-ldap-password-policy
At section 5.3.3: pwdAccountLockedTime
This attribute holds the time that the user's account was locked. A
locked account means that the password may no longer be used to
authenticate. A 000001010000Z value means that the account has been
locked permanently, and that only a password administrator can unlock
the account.
At section 5.2.12: pwdLockoutDuration
This attribute holds the number of seconds that the password cannot
be used to authenticate due to too many failed bind attempts. If
this attribute is not present, or if the value is 0 the password
cannot be used to authenticate until reset by a password
administrator.
Through above two section, we can assume that we should connect to ApacheDS server with administrator(by default: uid=admin,ou=system, password=secret ), and delete the user's userPassword attribute. By this way,the permanently locked user can be unlock.
I practiced this sulotion and it works well.
I suggest you should set value for pwdLockoutDuration attribute, in this case the user can not been permanently locked.
For more infomation:
ApacheDS password Policy
Use ApacheDS Studio and log in as admin, find the user, right-click and choose "Fetch->Fetch operational attributes". Now pwdAccountLockedTime is visible and you can delete it to unlocks the user
The answer by Mister's is perfect to unlock an account and if you want to set the pwdLockoutDuration for a single user (assuming the user has implemnted the objectClass pwdPolicy.
There is also a global config file found in:
ou=config
* ads-directoryServiceId=<default>
* ou=interceptors
* ads-interceptorId=authenticationInterceptor
* ou=passwordPolicies
Here we can set the default password policy:
As mine is just a test-server, I have completely disabled lockout via setting the ads-pwdlockout to FALSE. For more on configuring password policy read the official docs.
For reference, this is how you enable this on the server via java:
AuthenticationInterceptor authenticationInterceptor = new AuthenticationInterceptor();
PasswordPolicyConfiguration config = new PasswordPolicyConfiguration();
config.setPwdLockout(true);
authenticationInterceptor.setPwdPolicies(config);
Client methods can then be written, to enable/disable specific accounts, similar to:
public void disableUser(String dn) throws LdapException, UnsupportedEncodingException
{
Modification disablePassword = new DefaultModification(
ModificationOperation.REPLACE_ATTRIBUTE, "pwdAccountLockedTime","000001010000Z" );
connection.modify(dn,disablePassword);
}
public void enableUser(String dn) throws LdapException, UnsupportedEncodingException
{
Modification disablePassword = new DefaultModification(ModificationOperation.REMOVE_ATTRIBUTE, "pwdAccountLockedTime");
connection.modify(dn,disablePassword);
}

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.