LDAP 1.6

This document applies to LDAP Connector 1.6. This version authenticates only against one LDAP or Active Directory server at a time. If you have more servers and want to be authenticated against all of them, stay at LDAP Connector 1.4 until this limitation is removed.

Magnolia LDAP Connector module is Enterprise only. The module is a standard JAAS login module, which connects to any LDAP V3 supported directory service. This module is useful when deploying Magnolia in large intranet environments where an enterprise-grade user management infrastructure already exists. With the JAAS standard support you can meet single sign-on requirements or connect to legacy LDAP/ADS directory servers.

Download

The LDAP module is available in the add-ons folder of the Enterprise Edition bundle. You can also download the module from Magnolia Store or Nexus repository.

Installing

To install the module, see the general module installation instructions.

The location of your ldap.properties file is configurable. You can place the file in an alternative location if you want. Add a new property jndi.ldap.config in the magnolia.properties file and set its value to a relative or absolute path to the webapp, or use ${magnolia.home}.

Uninstalling

See the general module uninstalling instructions and advice.

Groups and roles

LDAP typically mirrors the organization structure. If your company has Marketing, HR and Legal departments you would create marketing, hr and legal groups in your LDAP system, then assign employees to those groups. Just like LDAP groups, Magnolia groups are used to organize users into larger units. Examples of default Magnolia groups are editors and publishers which correspond to the responsibilities users have in the content approval workflow.

Magnolia also has roles. A role grants a user permission to do something. For example, the editor role grants the permission to edit content and the publisher role grants the permission to approve content for publishing. The permissions a role grants are configured with access control lists (ACL). A role can be assigned directly to an individual user or to a group.

Resolving

When the LDAP Connector module authenticates a user using the LDAP server it also tries to find out what groups and roles the user belongs to. This is called resolving. Since role is the element that grants the permission to do something, you need to use a resolver class that resolves at least roles. You can optionally also resolve groups.

Resolver type

What is managed in LDAP

What is managed in Magnolia

Role resolver

Roles
Users

Roles

Group resolver

Groups
Users

Roles
Groups

Group resolving

The groupResolverClass fetches group names from the LDAP server and matches them with groups in Magnolia. The match must be an exact name match: an editors group in LDAP must match an editors group in Magnolia. When you use a group resolver you have to define groups in LDAP and in Magnolia.

The resolver implementation differs depending on which LDAP product you use. Magnolia provides ready-made group resolvers for Active Directory and OpenLDAP.

Best practice: If you use LDAP groups to assign user permissions then create one name-matching group per user role in Magnolia and add one or more Magnolia roles reflecting the needed permissions to that group. This minimizes the amount of groups needed in Magnolia.

Magnolia role

Magnolia group

LDAP group

LDAP user

editor
workflow-base

editors

editors

jsmith
eallen
cappleton

publisher
workflow-base

publisher

publishers

bleroy
dmillet
vrobbins

Role resolving

The roleResolverClass works just like group resolving but it only resolves roles. A role resolver fetches role names for the authenticated user from LDAP and matches them to roles in Magnolia. If you use the default role names (editor, publisher etc.) provided by Magnolia you save some effort. For example, create an editor role in LDAP because the name already exists in Magnolia. However, you can create any custom roles you need.

NameResolver interface

NameResolver is an interface that allows you to create your own resolver implementation. Magnolia does not provide ready-made resolver classes for every possible LDAP product. If you need to connect to a new product, write your own class. For example, if no resolver class for OpenLDAP existed you would have to provide your own. Write a class that implements the NameResolver interface. The interface enforces you to implement the methods that are needed to fetch group names from that particular server.

Available LDAP Modules

  1. LDAPAuthenticationModule : this module can be used to authenticate against any LDAP directory. You would use this together with MagnoliaGroupResolver and MagnoliaRoleResolver (users replicated in the JCR repository) or with specific NameResolver implementations to resolve groups and roles for your LDAP users.
  2. ADAuthenticationModule : a specialized version of the LDAPAuthenticationModule for Active Directory.

Configuration

The LDAP configuration defines how Magnolia can find the LDAP server and what it should resolve.

ldap.properties and ad.properties

Property

Description

java.naming.provider.url

A fully qualified URL to your LDAP server.

java.naming.security.authentication

Password encryption type: none, simple or DIGEST-MD5

java.naming.security.principal

Optional. Identity of the principal to be authenticated. Use an appropriate DN/CN for your LDAP server.

initialSearchAttributes

This string is used to build an initial search against the server, for example CN=Users,dc=example,dc=com.

groupResolverClass

The class responsible for resolvin groups assigned to a user. The class must implement the info.magnolia.jaas.sp.ldap.resolver.NameResolver interface.
Implementations:

  • info.magnolia.jaas.sp.ldap.resolver.MagnoliaGroupResolver
  • info.magnolia.jaas.sp.ldap.resolver.ADGroupResolver
  • info.magnolia.jaas.sp.ldap.resolver.OpenLDAPGroupResolver

roleResolverClass

The class responsible for resolving roles assigned to a user. The class must implement the info.magnolia.jaas.sp.ldap.resolver.NameResolver interface.
Implementations:

  • info.magnolia.jaas.sp.ldap.resolver.MagnoliaRoleResolver

adminUserDN

Distinguished name of an admin user who has permissions to search the tree defined in initialSearchAttributes.

adminUserPassword

Password of the admin user.

Name mapping (multiple properties)

Mapping between Magnolia-defined attributes and how these attributes are named in your specific LDAP installation.

Other properties are defined and documented in ldap.properties and ad.properties files.

jaas.config

(warning) If you run JBoss application server edit login-config.xml instead.

In WEB-INF/config/jaas.config file:

  1. Add the JCR authentication module as a first optional login module. This will allow to authenticate against the users only available in Magnolia.
  2. Add the LDAP authentication module as a requisite login module. Set skip_on_previous_success to skip this module if the previous module was successful.

For example, replace:

magnolia {
   info.magnolia.jaas.sp.jcr.JCRAuthenticationModule requisite;
   info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;
   };

With:

magnolia {
   info.magnolia.jaas.sp.jcr.JCRAuthenticationModule optional;
   info.magnolia.jaas.sp.ldap.LDAPAuthenticationModule requisite 
      skip_on_previous_success=true;
   info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;
   };

The first module is needed to be able to authenticate the superuser and anonymous users. Note that the second module could also be info.magnolia.jaas.sp.ldap.ADAuthenticationModule.

JBoss login-config.xml

For JBoss application server, edit login-config.xml as follows:

<application-policy name="magnolia">
   <authentication>
      <login-module code="info.magnolia.jaas.sp.jcr.JCRAuthenticationModule" 
                    flag = "optional" />
      <login-module code="info.magnolia.jaas.sp.ldap.LDAPAuthenticationModule" 
                    flag = "requisite">
          <module-option name="realm">admin</module-option>
          <module-option name="skip_on_previous_success">true</module-option>
          <module-option name="jndi.ldap.config">ldap.properties</module-option>
      </login-module>
      <login-module code="info.magnolia.jaas.sp.jcr.JCRAuthorizationModule" 
                    flag = "required" />
   </authentication>
</application-policy>

User manager

You also need to configure a UserManager:

  1. Add a new content node called external under Configuration > /server/security/userManagers.
  2. Under external, add a data node class with info.magnolia.jaas.sp.ldap.LDAPUserManager or info.magnolia.jaas.sp.ldap.ADUserManager as a value.
  3. Under external, add a data node realmName and set its value to external.
  4. (warning) Make sure the nodes under userManagers are ordered so that external is before admin but after system. Any other order may result in 401 errors (authentication failed) during activation/deactivation.

If you need to access more user properties than name, full name and language, extend info.magnolia.jaas.sp.ldap.LDAPAuthenticationModule#setEntity to push the desired properties into the Entity object, and the info.magnolia.cms.security.ExternalUserManager/info.magnolia.cms.security.ExternalUser pair to expose it.

(warning) If you are resolving roles or groups, add the allowCrossRealmDuplicateNames property under /server/security/userManagers/admin and set its value to true. This property allows you two create users with the same name in different realms when replicating LDAP/AD users in the repository. By default, Magnolia does not allow the same user name to be repeated. The allowCrossRealmDuplicateNames property is only available in Magnolia 4.5.9 and later.

Mapping LDAP Attributes

Before using the connector you will need to map Magnolia specific names with the attribute names used in your LDAP server, e.g. in Organization=o, "Organization" is a keyword for Magnolia and "o" refers to the attribute name as defined for the LDAP server.

Organization=o
OrganizationUnit=ou
CommonName=cn
Surname=sn
GivenName=givenname
uid=sAMAccountName
dn=dn
mail=mail
GroupId=memberOf
Password=pass
Language=language

Testing and validating LDAP Configuration

The magnolia-ldap-tester artifact is a self-contained executable jar which can be executed with:

java -jar magnolia-ldap-tester-<version>.jar <LoginModule class name> <config.properties> <username> <password>

<LoginModule class name> should be either info.magnolia.jaas.sp.ldap.LDAPAuthenticationModule or info.magnolia.jaas.sp.ldap.ADAuthenticationModule, depending on which one you're using in jaas.config (or login-config.xml with JBoss).

The tool simulates a user login with the given credentials and configuration, outputs the main results, and logs everything else in magnolia-ldap-tester.log.

A successful login attempt looks like this in the log:

INFO  i.m.jaas.sp.ldap.ConnectionFactory - Trying to log in as 
   cn=jsmith,dc=example,dc=com with a password.
DEBUG i.m.jaas.sp.ldap.ConnectionFactory - Login succeeded.
DEBUG i.m.j.s.l.Tester$MockSecuritySupport - Getting user jsmith from realm admin
INFO  info.magnolia.ldap.tool.LDAPTester - Login result: true
INFO  info.magnolia.ldap.tool.LDAPTester - Commit result: true
DEBUG info.magnolia.ldap.tool.LDAPTester - Subject:
DEBUG info.magnolia.ldap.tool.LDAPTester - User: null
INFO  info.magnolia.ldap.tool.LDAPTester - 
   Properties: {title=jsmith, 
   email=john.smith@example.com, 
   name=jsmith, 
   fullName=jsmith, 
   password=secret}
DEBUG info.magnolia.ldap.tool.LDAPTester - 
   State: {groupNames=[], 
   statusValue=1, 
   roleNames=[]}
INFO  info.magnolia.ldap.tool.LDAPTester - Group names: (none)
INFO  info.magnolia.ldap.tool.LDAPTester - Role names: (none)
DEBUG info.magnolia.ldap.tool.LDAPTester - AttributesMap

Do not expect to see any groups or roles assigned. The tester tool does not connect to Magnolia in any way. It connects to the LDAP. It is normal for group assignments handled in Magnolia to not show up.

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))

4 Comments

  1. using the 1.5.3 version had to set the AD property

    java.naming.referral=follow

    because using "ignore" the authentication process throws

    javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name 'dc=xxxx,dc=yyy'
     at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2866)
     at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2840)
     at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:147)
     at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:216)
     at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:189)
     at info.magnolia.jaas.sp.ldap.LDAPUserManager.getUser(LDAPUserManager.java:81)
     at info.magnolia.cms.security.DelegatingUserManager$5.delegate(DelegatingUserManager.java:114)
    ... 

    which according to the documentation http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html should not be considered as a problem in authentication, but rather an information that the result is partial.

    May be possible in future version of

    info.magnolia.jaas.sp.ldap.LDAPUserManager.getUser @ hasMore() line 

    trap and ingnore javax.naming.PartialResultException ?

    or read again "java.naming.referral" property and if set to "ignore" not re-throw.

    1. Hello Lorenzo,

      The problem is that Active Directory does not support the Manage Referral control.

      How you can see at http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html

      "When the LDAP service provider receives a referral despite your having set Context.REFERRAL to "ignore", it will throw a PartialResultException to indicate that more results might be forthcoming if the referral is followed. In this case, the server does not support the Manage Referral control and is supporting referral updates in some other way."

      "Windows Active Directory: Because Active Directory does not support the Manage Referral control, none of the examples in this lesson will work against Active Directory."

      We decided to solve issue by adding new configuration property allowPartialResults (Configuration-modules/ldap/config/allowPartialResults) MGNLLDAP-39.When property is set to true then hasMoreElements() and nextElement() methods are used. If property is set to false then hasMore() and next() are used.

      @hasMore() and @next() methods throws javax.naming.NamingException so also PartialResultException.

      @hasMoreElements() and @nextElement() doesn't throw this exception

      Fix is part of Magnolia LDAP module 1.6.1.

  2. Is it necessary to mark the password as reversible in Active Directory to work?

    Why kerberos is not supported?

    In ad.properties there is the following comment:

    ##########################################################################

    # Password encryption type

    # values supported by sun service provider:

    #                                          none

    #                                          simple (plain text)

    #                                          DIGEST-MD5

    #                                          **EXTERNAL

    #                                          **GSSAPI (Kerberos V5)

    # ** Not yet supported by magnolia LDAP login module

    ##########################################################################

    The method that does the authentication is:

      DirContext dirContext = new javax.naming.directory.InitialDirContext.InitialDirContext.InitialDirContext(env);

      log.debug("Login succeeded.");

    which uses java based mechanism defined in http://docs.oracle.com/javase/tutorial/jndi/ldap/sasl.html   ?

    So it seems to support kerberos. Why can't do that?

    1. Is it necessary to mark the password as reversible in Active Directory to work?

      There should not be necessary to use reversible password in Active Directory. Magnolia LDAP module itself doesn't need decrypt password from ldap context.

      Why kerberos is not supported?

      As you pointed, LDAP module use javax.naming.directory.InitialDirContext for authentication of user. So all mechanisms defined in http://docs.oracle.com/javase/tutorial/jndi/ldap/sasl.html should be supported.

      In ad.properties there is the following comment: ...

      It is reminiscent from an earlier version of the ldap module and it should be removed from sample ad.properties file. In past custom MagnoliaEncryptionHandlers were used for user authentication.