Page 1 of 1

[MAKING PROGRESS] CmapServer does not authenticate to LDAP

Posted: Thu Feb 24, 2011 12:53 pm
by camerongoble
Hello all,

Using cmapserver 5.04, 1 GB of RAM on an Ubuntu Linux 10.04 server.

I recently had to reorganize my LDAP directory from scratch. (Note to future sysadmins: sometimes you think you're making the right choice of structures when you're really not.) Ugh. The structural changes were significant, so I'm re-installing cmapserver from scratch as well. I still have all the old settings and maps safely tucked away.

Anyway, cmapserver is now unable to authenticate to LDAP using the new structure. It seems like cmapserver isn't even binding correctly to search the LDAP tree, but I can't tell exactly. I've poured through the logs and I don't recognize anything untoward, though to be honest I'm not sure precisely what I'm seeing.

I think I've set the appropriate lines for users and groups in serverconfig. I know the DNs are correct because I can bind and query the LDAP server on a command line using the same values.

I can authenticate only with the cmap_admin credentials I made when first installing cmapserver if I set the login type to regular or both -- that's the built-in administrator for admin tools. If I set the login type to ldap only, I cannot authenticate at all with any credentials. That includes with the CMapTools software or view any concept maps with a web browser.

If I go into CMapTools as the built-in admin, I can remove all the old permissions on my maps, but when I try to add new users by browsing LDAP, I am asked for a login and password before the directory will search. I have tried every login and password I can think of -- LDAP administrator login included -- but nothing will search the tree. This is why I think there's a binding problem.

Here's the relevant LDAP entries in the serverconfig. Just to clarify:
*The vmail account is used by other web apps to bind. It certainly works for them.
* I've tried specifying vmail by both DN and UID. Neither works.
* The ip entry "ldap" resolves in DNS to the right location. I can ping it from the cmapserver box and do command line queries with "ldap" as the specific hostname.

Code: Select all

# LDAP Configuration for Permissions
#
# These settings enable the CmapServer to use an LDAP directory for user
# authentication when defining permissions for folders.
# Authentication mode: standard permissions, LDAP permissions, or both
# If this line is missing or blank, then standard permissions is assumed
# Valid values: authentication.standard
#               authentication.ldap
#
# Example (for both): user.authentication = authentication.standard,authentication.ldap
#
user.authentication=authentication.standard,authentication.ldap

#user.authentication=authentication.standard
# User ID of the root folder administrator for an LDAP-enabled server.
# This User ID should match an entry in the LDAP server.
#
ldap.root.folder.account=vmail

# Password of the root folder administrator for an LDAP-enabled server.
# This password should match the password stored in the LDAP server.
#
# IMPORTANT: Once the server is launched, the password will be encrypted.
# To replace the encrypted password: shutdown the server, remove the
# encrypted_<some random characters>\\= (no quotes) completely,
# type in the new password for the value, then save this file and launch the
# CmapServer again. All passwords that were replaced in this file will again
# be encrypted once the CmapServer has been launched.
#
ldap.root.folder.password=encrypted_z6lE3arjKfmW+jNgfrDVA24QJg5BdTdO1wcfLE\=

# IP address or hostname of the LDAP server
#
# Example: ldap.user.directory.ip = myhost.mydomain.com
#
ldap.user.directory.ip=ldap

# Port number of the LDAP server
#
ldap.user.directory.port=389

# Protocol to use for communication with the LDAP server.
# If a secure mode is selected, the certificates from the PKI
# settings above will be used, if they have been specified.
# Valid values: normal, tls, or ssl
#
# Example: ldap.user.directory.connection.mode=normal
ldap.user.directory.connection.mode=normal

# DN of the container where individual users are stored
#
# Example: ldap.user.directory.usersBaseDN = ou=People,dc=mydomain,dc=com
#
ldap.user.directory.usersBaseDN=ou\=Users,domainName\=seeyourselfteaching.com,o\=domains,dc\=seeyourselfteaching,dc\=com

# DN of the container where groups are stored
#
# Example: ldap.user.directory.groupsBaseDN = ou=Groups,dc=mydomain,dc=com
#
ldap.user.directory.groupsBaseDN=ou\=Groups,domainName\=seeyourselfteaching.com,o\=domains,dc\=seeyourselfteaching,dc\=com

# Name of the attribute which holds the user's ID
#
ldap.user.directory.userAttr=uid

# Name of the attribute which holds the group's ID
#
ldap.user.directory.groupAttr=cn
And here's a log snippet in which I started the server, browsed to the tomcat web page, and tried to log in with a set of credentials from the LDAP directory:

Code: Select all

(CLASS: nlk.acl.directory.ldap.LDAPUserDirectory METHOD: getUserDN LINE: 588)
LDAPUserDirectory: unable to lookup user DN with anonymous access, will not try again
(CLASS: nlk.acl.directory.ldap.LDAPUserDirectory METHOD: getUserDN LINE: 589)
javax.naming.AuthenticationNotSupportedException: [LDAP: error code 48 - anonymous bind disallowed]
        at com.sun.jndi.ldap.LdapCtx.mapErrorCode(Unknown Source)
        at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
        at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
        at com.sun.jndi.ldap.LdapCtx.connect(Unknown Source)
        at com.sun.jndi.ldap.LdapCtx.<init>(Unknown Source)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(Unknown Source)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(Unknown Source)
        at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(Unknown Source)
        at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(Unknown Source)
        at us.ihmc.net.ssl.SSLInitialContextFactory.getContext(SSLInitialContextFactory.java:171)
        at us.ihmc.net.ssl.SSLInitialContextFactory.getInitialContext(SSLInitialContextFactory.java:93)
        at nlk.acl.directory.ldap.LDAPHelper.bind(LDAPHelper.java:63)
        at nlk.acl.directory.ldap.LDAPUserDirectory.getUserDN(LDAPUserDirectory.java:569)
        at nlk.acl.directory.ldap.LDAPUserDirectory.bind(LDAPUserDirectory.java:511)
        at nlk.acl.directory.ldap.LDAPUserDirectory.authenticateUser(LDAPUserDirectory.java:142)
        at nlk.base.LDAPAuthenticator.authenticateUser(LDAPAuthenticator.java:24)
        at nlk.acl.NewCmapACLManager.checkPermission(NewCmapACLManager.java:148)
        at nlk.acl.NewCmapACLManager.checkPermission(NewCmapACLManager.java:37)
        at nlk.resio.ServletHelper.checkPermissions(ServletHelper.java:1888)
        at nlk.htmlview.HtmlView.generateHtmlFolderView(HtmlView.java:157)
        at nlk.resio.SBReadResourceServlet.doGet(SBReadResourceServlet.java:563)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
        at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Unknown Source)

Re: CmapServer does not authenticate after rebuilding LDAP

Posted: Fri Feb 25, 2011 5:21 pm
by jlott
Since anonymous binds are not allowed by your LDAP server, the CmapServer is not able to lookup a user's DN via an anonymous query. However, it will still make two attempts to bind, by trying to guess the correct format for the userId:
1) try binding with the plain userId, e.g. "vadmin"
2) try binding with the assumed DN based on the configuration file, e.g. "uid=vadmin,ou=Users,domainName=seeyourselfteaching.com,o=domains,dc=seeyourselfteaching,dc=com"

Since both attempts are failing, it appears that:
option (1) may not be allowed by your server, e.g. it requires the full DN to bind
option (2) may not be constructing the correct DN for your user

Here are some potential solutions:
a) adjust the ldap parameters in serverconfig.txt so that the user's DN is constructed correctly (may not be possible depending on your LDAP structure)
b) on the LDAP server, enable anonymous access to lookup DNs
c) on the LDAP server, configure it to allow "plain" binds (e.g. just the userId, rather than the full DN)

James

Re: CmapServer does not authenticate after rebuilding LDAP

Posted: Mon Feb 28, 2011 1:44 pm
by camerongoble
Thanks for your reply, James.

Good advice. I worked on it this morning and the same problem occurs, though. It doesn't seem to make a difference if I use a plain uid or a fully distinguished name in serverconfig.txt.

I wonder if the issue is the LDAP server itself. (I don't recall if I mentioned this: I'm using Ubuntu's OpenLDAP package.) I edited the configuration to allow for anonymous binds, restarted the LDAP server, restarted CMapServer... and still no luck.

So I'm working on Solution B: set up the server to allow anon logins. But still, I'm confused on two counts:

First, the LDAP server is (I thought) configured to bind anonymously, yet CMapServer says in the logs that it isn't. I also can't bind with it using ldapsearch unless I specify a user. If we can put this one issue to rest, I think it'll be the breakthrough I need to move on under my own power.

Here's my slapd.conf -- I tried to bold the bits that I thought were relevant, but the forum markup doesn't do it that way. So here's the whole shebang:

Code: Select all

#
# File generated by iRedMail (2011.02.08.21.53.53):
#
# Version:  0.6.1
# Project:  http://www.iredmail.org/
#
# Community: http://www.iredmail.org/forum/
#

# Schemas.
include     /etc/ldap/schema/core.schema
include     /etc/ldap/schema/corba.schema
include     /etc/ldap/schema/cosine.schema
include     /etc/ldap/schema/inetorgperson.schema
include     /etc/ldap/schema/nis.schema
# Integrate Amavisd-new.
include     /etc/ldap/schema/amavis.schema
# Schema provided by iRedMail.
include     /etc/ldap/schema/iredmail.schema

# Where the pid file is put. The init.d script will not stop the
# server if you change this.
pidfile     /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile    /var/run/slapd/slapd.args

# TLS files.
TLSCACertificateFile /etc/ssl/certs/iRedMail_CA.pem
TLSCertificateFile /etc/ssl/certs/iRedMail_CA.pem
TLSCertificateKeyFile /etc/ssl/private/iRedMail.key

# Modules.
modulepath  /usr/lib/ldap
moduleload  back_bdb

[b]# Disallow bind as anonymous.
# disallow    bind_anon

# Uncomment below line to allow binding as anonymouse.
allow bind_anon_cred[/b]

#
# Specify LDAP protocol version.
#require     LDAPv3
allow       bind_v2

# Log level.
#   -1:     enable all debugging
#    0:     no debugging
#   128:    access control list processing
#   256:    stats log connections/operations/results
loglevel    0

#
# Access Control List. Used for LDAP bind.
#
# NOTE: Every domain have a administrator. e.g.
#   Domain Name: 'seeyourselfteaching.com'
#   Admin Name: mail=postmaster@seeyourselfteaching.com, domainName=seeyourselfteaching.com, o=domains,dc=seeyourselfteaching,dc=com
#

#
# Set permission for LDAP attrs.
#
access to attrs="userPassword,mailForwardingAddress"
    by anonymous    auth
    by self         write
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users        none

[b]access to attrs="cn,sn,telephoneNumber"
    by anonymous    auth
    by self         write
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users        read[/b]

# Domain attrs.
access to attrs="objectclass,domainName,mtaTransport,enabledService,domainSenderBccAddress,domainRecipientBccAddress,domainAdmin,domainGlob$
    by anonymous    auth
    by self         read
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users        read
# User attrs.
access to attrs="employeeNumber,homeDirectory,mailMessageStore,mail,accountStatus,userSenderBccAddress,userRecipientBccAddress,mailForwardi$
    by anonymous    auth
    by self         read
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users        read

[b]#
# Set ACL for vmail/vmailadmin.
#
access to dn="cn=vmail,dc=seeyourselfteaching,dc=com"
    by anonymous                    auth
    by self                         write
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users                        none
access to dn="cn=vmailadmin,dc=seeyourselfteaching,dc=com"
    by anonymous                    auth
    by self                         write
    by users                        none[/b]

#
# Allow users to access their own domain subtree.
# Allow domain admin to modify accounts under same domain.
#
access to dn.regex="domainName=([^,]+),o=domains,dc=seeyourselfteaching,dc=com$"
    by anonymous                    auth
    by self                         write
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by dn.regex="mail=[^,]+@$1,o=domainAdmins,dc=seeyourselfteaching,dc=com$" write
    by dn.regex="mail=[^,]+@$1,ou=Users,domainName=$1,o=domains,dc=seeyourselfteaching,dc=com$" read
    by users                        none

[b]#
# Enable vmail/vmailadmin.
#
access to dn.subtree="o=domains,dc=seeyourselfteaching,dc=com"
    by anonymous                    auth
    by self                         write
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by dn.regex="mail=[^,]+,ou=Users,domainName=$1,o=domains,dc=seeyourselfteaching,dc=com$" read
    by users                        read
access to dn.subtree="o=domainAdmins,dc=seeyourselfteaching,dc=com"
    by anonymous                    auth
    by self                         write
    by dn.exact="cn=vmail,dc=seeyourselfteaching,dc=com"   read
    by dn.exact="cn=vmailadmin,dc=seeyourselfteaching,dc=com"  write
    by users                        none[/b]

#
# Set permission for "cn=*,dc=seeyourselfteaching,dc=com".
#
access to dn.regex="cn=[^,]+,dc=seeyourselfteaching,dc=com"
    by anonymous                    auth
    by self                         write
    by users                        none
#
# Set default permission.
#
access to *
    by anonymous                    auth
    by self                         write
    by users                        read

#######################################################################
# BDB database definitions
#######################################################################

database    bdb
suffix      dc=seeyourselfteaching,dc=com
directory   /var/lib/ldap/seeyourselfteaching.com

rootdn      cn=namma,dc=seeyourselfteaching,dc=com
rootpw      {SSHA}LsbGlge55mDmUMXJPjUYGb2N9nI3FxRN

sizelimit   1000
cachesize   1000

#
# Set directory permission.
#
mode        0700
#
# Default index.
#
index objectClass                                   eq,pres
index uidNumber,gidNumber,uid,memberUid,loginShell  eq,pres
index homeDirectory,mailMessageStore                eq,pres
index ou,cn,mail,surname,givenname,telephoneNumber  eq,pres,sub
index nisMapName,nisMapEntry                        eq,pres,sub

#
# Index for mail attrs.
#
# ---- Domain related ----
index domainName,mtaTransport,accountStatus,enabledService  eq,pres,sub
index domainAliasName    eq,pres,sub
index domainMaxUserNumber eq,pres
index domainAdmin,domainGlobalAdmin,domainBackupMX    eq,pres,sub
index domainSenderBccAddress,domainRecipientBccAddress  eq,pres,sub
# ---- Group related ----
index accessPolicy,hasMember,listAllowedUser   eq,pres,sub
# ---- User related ----
index mailForwardingAddress,shadowAddress   eq,pres,sub
index backupMailAddress,memberOfGroup   eq,pres,sub
index userRecipientBccAddress,userSenderBccAddress  eq,pres,sub
The second confusing issue is that CMapServer is configured to bind with the existing vmail account anyway which has read ACL permissions on everything in the relevant tree. Yet I still get this error in the CmapServer logs: [LDAP: error code 50 - Insufficient Access Rights].

It's like CMapServer isn't using the specified user to bind with anyway, so it tries anonymous and gets refused.

Any more thoughts? I'm banging my head against the wall, here, and I really appreciate your trying to help.
-Cameron

Re: CmapServer does not authenticate after rebuilding LDAP

Posted: Mon Feb 28, 2011 5:25 pm
by jlott
First I'd like to clarify that the CmapServer only accepts plain userIds, not full DNs, whether in the serverconfig.txt configuration file, or through the CmapTools client's authentication dialog. The CmapServer tries to lookup and/or make an estimated guess at the full DN based on the plain userId.

Also, note that the CmapServer does not have the notion of a "LDAP administrative account". It binds to the LDAP server using the credentials of the user who is currently accessing the CmapServer. The "ldap.root.folder.account" parameter specifies the LDAP user who should have ADMIN permission on the CmapServer's root folder. However, it is not used for binding to LDAP on behalf of other users.

From looking at your LDAP configuration, it appears that the full DN for the "vmail" account is:
cn=vmail,dc=seeyoutselfteaching,dc=com

I believe there may be some issues with your configuration in serverconfig.txt:
ldap.root.folder.account=vmail
ldap.user.directory.userBaseDN=ou=Users,domainName=seeyourselfteaching.com,o=domains,dc=seeyourselfteaching,dc=com
ldap.user.directory.userAttr=uid

Given this configuration, the CmapServer will not be able to authenticate the "vmail" user, for two reasons:
1) the vmail account is not under the subtree "ou=Users,domainName=seeyourselfteach.com,o=domains..."
2) the vmail account's DN uses the "cn" attribute, rather than the "uid" attribute specified above

The ldap.root.folder.account must be under the "userBaseDN" subtree.

If the users are in a flat hierarchy underneath the "userBaseDN", and the "userAttr" is set correctly, then the CmapServer should be able to construct the correct DN without needing anonymous access, e.g.
- ou=Users,domainName=seeyourselfteaching.com,o=domains,dc=seeyourselfteaching,dc=com
---- uid=jsmith
---- uid=jdoe
---- uid=....

The CmapServer uses the following pattern to construct the full DN:
"<userAttr>=<userId>,<userBaseDN>"

If your users are not in a flat hierarchy, but rather in subtrees below the "userBaseDN", then the CmapServer will have to lookup the user DN's, which requires anonymous access to your LDAP server's "dn" and <userAttr> attributes. For OpenLDAP, the anonymous access rule should be something like:

access to attrs=dn,<userAttr>
by anonymous read

To test that your LDAP server is allowing anonymous access, you should be able to do:
ldapsearch -h <host> -x -b "<userBaseDN>" "(<userAttr>=<userId>)" dn
(this is the same query that the CmapServer uses to lookup a user's DN)

James

Re: CmapServer does not authenticate after rebuilding LDAP

Posted: Mon Feb 28, 2011 8:52 pm
by camerongoble
Wow! Outstanding explanation, James. Thank you so much for being thorough and clear. You've eliminated some fundamental misunderstandings that I had about how CMapServer works.

I'm not in a position right now to put this new knowledge into action, but I'm excited to at the first opportunity. Thank you again!

Re: CmapServer does not authenticate after rebuilding LDAP

Posted: Tue Mar 01, 2011 12:58 pm
by camerongoble
Finally making progress on this! Thanks for the great information again, James. (Here's something fun: look at the URL on the title to your response, specifically the post number. "1337" indeed, you l33t d00d.)

I've got user authentication working from LDAP now, and I'm 99% happy with it. The LDAP structure comes from iRedMail, a turnkey Linux email solution with a pre-configured LDAP backend. The accounts use a "mail=someone@domain.com,dc=domain,dc=com" DN structure, so CMap has to be set to read the mail attribute for authentication. The uid is buried inside the account and I can't seem to make cmapserver see it. Kind of a bummer, as I'd prefer cleaner names, but it's 99% closer to perfect login than I was before. No complaints, but if you have ideas...

Groups are the next work to do now. iRedMail sets up groups in LDAP too, so I hope to take advantage of those. It reflects groups in two ways: there is a memberofGroup attribute in all the user accounts, and that lists the groups in another OU, which also use the mail= attribute in the DN.

The ultimate goal is to manage one single account in LDAP for all my email, cmap, and misc web application needs. I think I'm very close, and you've helped me out a lot, James. I'm very grateful!
-Cameron