RabbitMQ LDAP Authentication issue - rabbitmq

I have configured my RabbitMQ server to use LDAP authentication and tag users using advanced.config file.
my current config is something like:
Rabbitmq.conf
auth_ldap.servers.1 = DC001.mydomain.net
auth_ldap.servers.2 = DC002.mydomain.net
auth_ldap.use_ssl = true
auth_ldap.port = 636
auth_ldap.dn_lookup_attribute = userPrincipalName
auth_ldap.dn_lookup_base = DC=mydomain,DC=net
advanced.config
[{rabbitmq_auth_backend_ldap,
[
{vhost_access_query, {in_group, "cn=RabbitUsers-${vhost},OU=Security Groups,DC=mydomain,DC=net"}},
{tag_queries, [ {administrator, {in_group, "CN=RabbitAdmins,OU=Security Groups,DC=mydomain,DC=net"}},
{management, {in_group, "CN=RabbitAdmins,OU=Security Groups,DC=mydomain,DC=net"}}]}
]
}].
this works, but I must login users in the form or myuser#mydomain.net and password.
if I change the dn_lookup_attribute to SAMAccountName I can login using the form mydomain\myuser, but authorization with tag_queries doesn't work; my guess is that it tries to match the fully qualified username (domain\user) with the list of usernames only that are members of those groups.
I've read in the documentation, and I see in the logs, that there are two new variables ad_domain and ad_user that can be used instead of username, but I don't get where I should indicate those in order to have the ldap_plugin to use them...
could anyone provide some sample?

I answered this question on the mailing list:
https://groups.google.com/d/topic/rabbitmq-users/Dby1OWQKLs8/discussion
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.

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

Getstream.io throws exception when using the "to" field

I have two flat Feed Groups, main, the primary news feed, and main_topics.
I can make a post to either one successfully.
But when I try to 'cc' the other using the to field, like, to: ["main_topics:donuts"] I get:
code: 17
detail: "You do not have permission to do this, you got this error because there are no policies allowing this request on this application. Please consult the documentation https://getstream.io/docs/"
duration: "0.16ms"
exception: "NotAllowedException"
status_code: 403
Log:
The request didn't have the right permissions or autorization. Please check our docs about how to sign requests.
We're generating user tokens server-side, and the token works to read and write to both groups without to.
// on server
stream_client.user(user.user_id).create({
name: user.name,
username: user.username,
});
Post body:
actor: "SU:5f40650ad9b60a00370686d7"
attachments: {images: [], files: []}
foreign_id: "post:1598391531232"
object: "Newsfeed"
text: "Yum #donuts"
time: "2020-08-25T14:38:51.232"
to: ["main_topics:donuts", "main_topics:all"]
verb: "post"
The docs show an example with to: ['team:barcelona', 'match:1'], and say you need to create the feed groups in the panel, but mention nothing about setting up specific permissions to use this feature.
Any idea why this would happen? Note that I'm trying to create the new topics (donuts, all) which don't exist when this post is made. However, the docs don't specify that feeds need to be explicitly created first - maybe that's the missing piece?
If you haven’t already tried creating the feed first, then try that. Besides that, the default permissions restrict a user from posting on another’s feed. I think it’s acceptable to do this if it’s a notification feed but not user or timeline.
You can email the getstream support to change the default permissions because these are not manageable from the dashboard.
Or you can do this call server side as an admin permissions.

sending memberships in web2py cas

I am fairly new to using Web2py and am trying to get CAS authorisation working from one server(web2py instance) to another. Specifically I am trying to understand whether I can assign a role to a user on the cas_provider and then query this on the consumer app?
I have managed to create users on the CAS and log them in on the consumer app, but I would like to show them fields of a database that are dependent on their membership to specific groups. I have a workaround where I have created the groups and memberships in the consumer app, but really I would like to do all this on the CAS to avoid having to make changes in two places every time I add a new user.
In my research online I am getting the impression that CAS may restrict sending membership due to security concerns, but I don't really understand why that should be the case, as it is already sending sensitive information, apparently securely?
Any advice would be very helpful, as the CAS part of web2py seems under-documented for beginners like me.
Thanks.
When logging in via CAS, web2py Auth does not provide any built-in facility for checking roles/permissions in the CAS provider app. However, nothing stops you from accessing and querying the CAS provider app database via the DAL. Something like:
import os
cas_db_folder = os.path.join(request.folder, '..', 'appname', 'databases')
cas_db = DAL(cas_db_connection_string, folder=cas_db_folder', auto_import=True)
Now you can query the cas_db.auth_user, cas_db.auth_group, and cas_db.auth_membership tables to get user roles.
As an alternative, if you have a simple set of roles, you might consider storing them in the auth_user table as extra fields (you could store them in a list:string field or as a set of boolean fields). If you set up the same set of extra fields in the auth_user tables in both the CAS provider app and the CAS consumer app, the values of those fields will be copied from the provider to the consumer. Note, the fields must be set to readable for the CAS provider to pass them to the consumer. Also, to ensure the fields are updated in the consumer app after an update in the provider app, be sure to set auth.settings.update_fields in the consumer app (it should be a list of field names that you want to make sure get updated, included "email").
Adding extra fields doesn't seem to work correctly. I have added the exact same fields to the CAS and consumer app but the consumer doesn't take the values from the CAS. I can't see what the problem is, as the email and username all go across fine. I can see that the fields are created on the Consumer app but they are not populated from the CAS. They just have 'none' entires.
Here is the CAS code:
db.define_table(
auth.settings.table_user_name,
#User Fields for them to fill in
Field('first_name', length=128, required=False, default=''),
Field('last_name', length=128, required=False, default=''),
Field('username', length=128, required=False, default='', unique=True),
Field('email', length=128, required=False, default='', unique=True),
Field('company', length=256, default=''),
Field('address', length=256, default=''),
Field('city', length=128, default=''),
Field('postcode', length=128, default=''),
Field('country', length=128, requires=IS_IN_SET(COUNTRIES)),
Field('password', 'password', length=512, required=False, readable=False, label='Password'),
#Fields that are for administration purposes
Field('date_created', type= 'datetime', default = request.now, requires = IS_DATETIME(format=('%d-%m-%Y %H-%M-%S GMT')), writable=False),
Field('server_added', type='boolean', writable=False, readable=False, default='False'),
Field('admin_role', type='boolean', writable=False, readable=False, default='False'),
Field('temp_user', type='boolean', writable=False, readable=False, default='False'),
#Fields for web2py internal purposes
Field('registration_key', length=512, writable=False, readable=False, default=''),
Field('reset_password_key', length=512, writable=False, readable=False, default=''),
Field('registration_id', length=512, writable=False, readable=False, default=''),
#This last line states what should be exposed when referencing the table
format='%(username)s : %(email)s')
#Setting up Validators
member = db[auth.settings.table_user_name] # get the custom_auth_table
member.first_name.requires = \
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
member.last_name.requires = \
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
member.password.requires = [IS_STRONG(min=5, special=0, upper=0), CRYPT()]
member.email.requires = [
IS_EMAIL(error_message=auth.messages.invalid_email),
IS_NOT_IN_DB(db, 'auth_user.email')]
member.username.requires = IS_NOT_IN_DB(db, 'auth_user.username')
Here is Consumer code:
#Use the CAS for authentication
auth = Auth(db, cas_provider = 'http://xxxxxxxxxxxxxxxx')
service = Service()
plugins = PluginManager()
#Add additional field to Auth to accept the ADMIN flag
auth.settings.extra_fields['auth_user']= [
Field('admin_role', type='boolean'),
Field('postcode', length=128, default='')]
## create all tables needed by auth if not custom tables
auth.define_tables(username=False, signature=False)

Gerrit + LDAP = LDAP authentication unavailable Tuleap

I have been trying to setup gerrit to work with LDAP authentication. I read documentation numerous time some link do not work to the examples documentation pulled from tuleap on subject comes up with different solutions and explanations I have found three different configurations for ldap.inc from tuleap this is very confusing lacking explanation too.
So i am stuck with this problem. I have spent hours reading and trying to sort this out. Can someone tell me what am I doing wrong? here is my
ldap.inc
<?php
// LDAP server(s) to query for more information on Tuleap users and
// for authentication.
// You may use a comma-separated list if there are several servers available
// (leave blank to disable LDAP lookup).
// To specify secure LDAP servers, use 'ldaps://servername'
$sys_ldap_server = 'techhub.lt';
// To enable LDAP information on Tuleap users, also define the DN
// (distinguised name) to use in LDAP queries.
// The ldap filter is the filter to use to query the LDAP directory
// (%name% are substituted with the value from the user table)
$sys_ldap_dn = 'dc=techhub,dc=lt';
// For LDAP systems that do not accept anonymous binding, define here
// a valid DN and password:
$sys_ldap_bind_dn = "cn=admin,dc=techhub,dc=lt";
$sys_ldap_bind_passwd = "pass";
// LDAP authentication:
// Tuleap only supports authentication with a attempt to bind with LDAP server
// with a DN and a password.
// As the DN is usually long (eduid=1234,ou=people,dc=tuleap,dc=com) people
// usually authenticate themself with a login. So we need to first look
// for the DN that correspond to the given login and once found attempt to bind
// with the given password.
// In order to autenticate successfully users you need to properly
// User login (authentication 1st step)
$sys_ldap_uid = 'uid';
// User unique identifier. It's probably not the uid (or login) because it
// may change. This is a value that never change whatever happens to the
// user (even after deletion). It correspond to ldap_id field in user table
// in database.
// (authentication 2st step)
$sys_ldap_eduid = 'eduid';
// User common name
$sys_ldap_cn = 'cn';
// User email address
$sys_ldap_mail = 'mail';
// Specific DN to look for people
// You may use more than one DN separated by ; if you want to use several branches.
// Example : 'ou=People, dc=st, dc=com ; ou=Extranet, dc=st, dc=com'
$sys_ldap_people_dn = 'ou=people,dc=techhub,dc=lt';
// Filter used to look for user. It should cover a wide selection of
// fields because it's aim to find a user whatever it's given (email, name,
// login, etc).
$sys_ldap_search_user='(|(uid=%words%)(cn=%words%)(mail=%words%))';
// By default tooltip search is using ($sys_ldap_cn=%words%*) search filter (Hardcoded)
// You can change for a more sophisticated search
// $sys_ldap_tooltip_search_user='(&(|(sn=%words%*)(givenName=%words%*)(uid=%words%*))(!(givenName=BoiteVocale))(uid=*))';
// By default tooltip search attrs are $sys_ldap_cn and $sys_ldap_uid (Hardcoded)
// You can choose the attributes the search will retrieve
// $sys_ldap_tooltip_search_attrs='uid;sn;givenName';
// On account creation, what it the default user status (A, R, ...)
$sys_ldap_default_user_status = 'A';
// Enable LDAP based authentication for SVN by default for new projects
$sys_ldap_svn_auth = 1;
// Enable LDAP daily synchronization
$sys_ldap_daily_sync = 1;
// Enable usage of LDAP for people management. For instance autocompletion on
// user list, automatic creation of users not already referenced in the forge.
$sys_ldap_user_management = 1;
// Enable ldap group management.
// This allows to mirror a LDAP group defined in LDAP directory within the forge
// Doesn't work yet with only works with OpenLDAP compatible directories yet.
$sys_ldap_grp_enabled = 1;
// Specific DN where the user groups are
$sys_ldap_grp_dn = 'ou=groups,dc=techhub,dc=lt';
// Field that reprsent group name
$sys_ldap_grp_cn = 'cn';
// Field that indicate the membership of a user in a group
$sys_ldap_grp_member = 'uniquemember';
?>
AND gerrit.conf
[gerrit]
basePath = git
canonicalWebUrl = http://techhub.lt:2401/
[database]
type = H2
database = db/ReviewDB
[sendemail]
smtpServer = localhost
[container]
user = root
javaHome = /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.45.x86_64/jre
[sshd]
listenAddress = *:29418
[httpd]
listenUrl = http://*:2401/
[cache]
directory = cache
[auth]
type = LDAP
[ldap]
server = ldap://techhub.lt
accountBase = ou=people,dc=cro,dc=techhub,dc=lt
groupBase = ou=group,dc=cro,dc=techhub,dc=lt
accountFullName = cn
That's 2 different problems.
Do you manage to authenticate with LDAP accounts on gerrit ?
If yes, I think the problem comes from "$sys_ldap_eduid = 'eduid';" parameter in tuleap ldap config. This attribute should be the unique identifier of one's account in ldap (either you have such an attribute of you can use 'uid' as a fallback.

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.