Authentication and Authorization

Introduction

Standard J2EE security mechanisms are used to control access to resources (Java Server Pages, images, CSS style sheets etc.) as described by the Java Servlet 2.3 specification. The word "resource" usually means "URL", because this is how content is protected: the application defines security constraints to access certain URLs.

The first part of this guide describes the security configuration from this perspective. This part is focused on the configuration of the web application and not on any application server related aspects. It only covers security aspects the web application is responsible for (according to the Java Servlet Specification). It is more a documentation than a guide, because the application is preconfigured with reasonable security constraints.

The second part of this guide concentrates on setting up authentication and authorization for different scenarios. It describes how to use JAAS in order to authenticate against the Platform's internal user database or against an LDAP directory, and it ends with an example step-by-step configuration for Apache Tomcat.

Who should read this document

This document is intended for system administrators who need to install the application and set up authentication and authorization. As a standard J2EE web application, the application does not handle authentication and authorization itself. This is in the responsibility of the application server hosting the application.

Readers of this document should be familiar with the Java Servlet Specification, especially with the sections about security. In addition to this, they should have basic knowledge of JAAS.

References

Title Link
Java Servlet 2.3 Specification http://download.oracle.com/otndocs/jcp/7840-servlet-2.3-spec-oth-JSpec/
JAAS Login Module Developers Guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASLMDevGuide.html

Table 1: References

Terminology

Application

The term "application" refers to our web application. It is usually packaged as a single WAR file (web application archive). In addition to the main application, there may be a couple of extensions packaged as standalone entities (usually JAR files). Examples are Adapters or Login Modules.

Application Server

The term "application server" refers to J2EE compliant application servers (IBM WebSphere, BEA WebLogic, JBoss etc.) as well as servlet containers (Apache Tomcat etc.).

Authentication Provider

The term "authentication provider" refers to systems like Active Directory, NT Domains, Radius or general LDAP directories. These systems are used by the application server to verify user credentials. Most of these systems are installed as network services and accessed via TCP/IP. Application servers usually need some kind of driver to access a provider. This component is called an "authentication provider connector" or simply a "connector."

Authentication and Authorization Process

This section describes the authentication and authorization process. This description is not specific to this application, but common to all web applications conforming to the servlet specification.

Note: In this process, there are two authentication steps. From the user's perspective, authentication is performed between him and the application server. The protocol or "handshake" here is called Authentication Mechanism or HTTP Authentication in this guide. It is standardized in the servlet specification. But usually the application server does not verify the authentication credentials itself. Instead it forwards these credentials to an authentication provider. This second step is not standardized and therefore application server and vendor specific. However, there are standard technologies like JAAS which are supported by most application servers in some way for this second authentication.

1259033448448_security.png

Figure 1: Authentication and Authorization process

It is in the responsibility of the web application to define the security constraints to be applied by the application server hosting the web application.

Step 1: On web application deployment, the application server loads the security descriptions from the web application's deployment descriptor file /WEB-INF/web.xml which is located in the web application archive.

The descriptor states the resources to be protected from unauthorized access. The borders of this protected sections are defined by one or more URL pattern, e.g. /admin/*. Together with the URL pattern, the descriptor specifies security roles such as "Administrator." Only members of this role are granted access to the resources in the corresponding protected section. There may be multiple protected sections covering different parts of the web application and guarded by different security role settings.

It is also in the responsibility of the web application to specify the HTTP authentication mechanism to be used by the application server and the user, e.g. "HTTP Basic Authentication".

Step 2: The unauthenticated user is accessing a resource of the web application.

The application server uses the authentication information from the deployment descriptor to perform the authentication with the user. It may send the browser an instruction to display a dialog box to enter user name and password (HTTP Basic Authentication). Or it may use a login form defined by the web application to gather user name and password (Form Based Authentication).

Step 3: The application server gets the authentication credentials from the user.

Step 4: The application server is responsible for verifying the users credentials (authentication). The implementation of this process is application server and vendor specific. The web application has no knowledge on how authentication is performed.

Step 5: The application server has to be configured to use an authentication provider. It may use an application server internal user database or access any kind of external system. Usually an application server needs some kind of "driver" or "connector" to access the authentication service. Most application servers are shipped with some predefined connectors to authentication providers, e.g. authentication using an LDAP Directory or NT Domain. In addition to this, most application servers define an API to write custom authentication extensions. In Tomcat for instance, such extensions are written by extending the class org.apache.catalina.realm.RealmBase. Many application servers also support JAAS login modules (either directly or by using an adapter).

In the authentication process the application server must verify user name and password. In the case of JAAS, this information is passed to the login module(s). The login module runs authentication against the external system and returns the result to the application server. In addition to this, the login module is also supposed to return the roles the user is member in.

JAAS is much more powerful than simply authenticating users using user name and password. Only a subset of JAAS functionality is used to perform authentication in the web application scenario.

If authentication fails, an error code is sent back to the browser (401 - Authentication required). Depending on the browsers configuration, it may retry accessing the resource. This will restart the hole authentication process.

If authentication is successful, the application server verifies that the user is authorized to access the requested resource (authorization). The roles the authentication user is member in are compared with the security roles defined in the deployment descriptor for the protected section the resource belongs to.

If authorization fails, an error code is sent back to the browser (403 - Forbidden).

Step 6: If authorization is successful, the user is authenticated and authorized to access the protected resource and the request is forwarded to the web application.

The web application may query the request object for information about the authenticated user. For this purpose, class HttpServletRequest defines a set of methods to access the user name or to check for membership in security roles. This allows the web application to implement fine grained services like enforcing additional web application internal security constraints.

Protected Resources

The web application has 3 protected sections:

  • Internal Workspace
  • Administration
  • Web Listeners

Access to all sections requires the user to be a member in a security role. By default, this roles are named "User" and "Administrator." The chapter "Security Roles" describes the procedure to rename this roles if needed.

Internal Workspace Section

The Internal Workspace section requires a user to be member of the security role "User". This section covers the following paths:

  • /internal/*
  • /weblistener/user/*
In order to allow a public application to work, each servlet must be bound to two endpoints: one for the /internal version and the other for the standard version. If you create a public page and your application is set to internal only, the standard url does not trigger any authentication, therefore, you are not redirected to the login page. To solve this, you can set the `nm.window.start` configuration property in Studio (System Configuration > Configuration Properties) to the following value REDIRECT:/internal to ensure all requests are redirected to the internal url even if coming from non-internal sources.

Administration Section

The Administration requires a user to be member of the security role "Administrator". This section covers the following paths:

  • /admin/*
  • /webdav/*
  • /weblistener/admin/*

Web Listeners

The Listeners (web service interfaces) require a user to be member in at least one of the security roles "Administrator" or "User". This section covers the following paths:

  • /listener/*
  • /accessor/*
  • /weblistener/everybody/*

Unprotected Resources

All other resources are not protected by security constraints. They usually contain static web resources like images and style sheets.

  • /img/*
  • /css/*
  • /js/*
  • /weblistener/anonymous/*
  • ...

Some resources are protected by application-specific dynamic access control mechanisms. URL-based access to Script Functions, Resources and Screens for example may be controlled by Access Policies.

Configuration

Protected sections are defined in the web applications deployment descriptor:

Copy
<security-constraint>
   <web-resource-collection>
      <web-resource-name>Workspace</web-resource-name>
      <url-pattern>/internal/*</url-pattern>
      <url-pattern>/weblistener/user/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>User</role-name>
   </auth-constraint>
</security-constraint>

<security-constraint>
   <web-resource-collection>
      <web-resource-name>Appway Administration</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
      <url-pattern>/webdav/*</url-pattern>
      <url-pattern>/weblistener/admin/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>Administrator</role-name>
   </auth-constraint>
</security-constraint>

<security-constraint>
   <web-resource-collection>
      <web-resource-name>Listeners</web-resource-name>
      <url-pattern>/listener/*</url-pattern>
      <url-pattern>/accessor/*</url-pattern>
      <url-pattern>/weblistener/everybody/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>User</role-name>
      <role-name>Administrator</role-name>
   </auth-constraint>
</security-constraint>

Security Roles

Configuration

Security roles have to be declared in the deployment descriptor (web.xml) of the web application. By default, the application uses two security roles named "Administrator" and "User". The default configuration looks as follows:

Copy
<security-role>
   <description>Appway Users</description>
   <role-name>User</role-name>
</security-role>

<security-role>
   <description>Appway Administrators</description>
   <role-name>Administrator</role-name>
</security-role>

Renaming Security Roles

There may be situations where the default names of the security roles may not be used:

  • The roles "Administrator" or "User" are already in use to control access to another application
  • The names "Administrator" or "User" are reserved for application server or authentication provider internal purposes
  • The authentication provider returns complex roles names, e.g. LDAP paths like cn=Administrator,ou=Department1,dc=domain,dc=local

Some application servers support dynamic renaming or mapping of security roles. This way, the authentication provider may report a role "Admin" and the application server maps this to "Administrator" when processing authorization. But in cases where this is not possible, it may be necessary to rename a security role. To rename a security role, the web applications deployment descriptor as well as the Platform configuration have to be modified.

Note: If Advanced Permissions are not licensed on your Platform installation, correctly reassign permissions to the new name used for the Admin by deleting the file at [DataHome]/data/cluster/clusterfiles/appway/security/conf and restarting the environment.

Change Deployment Descriptor (web.xml)

The deployment descriptor web.xml is located in the directory WEB-INF in the root directory of the web application archive. Changes to the deployment descriptor usually require redeployment of the web application in the application server. To rename the security roles in the deployment descriptor, change the values of the role-name nodes in the two sections security-role and the two sections security-constraint.

Attention: Modifying the deployment descriptor file will invalidate the digital signature of the web application archive. Therefor, application servers may reject to install the web application. A work-around for this problem is to manually remove all signature information from the archive or to re-sign the archive.

Change Configuration

Some web application interfaces are enhanced with special functions depending on the membership in security roles. Users in the role "Administrator" may enable the administration tool bar in the front end for instance. If the security roles have been renamed, the application has to be configured to use the new role names. The properties used to store the names of the security roles are nm.auth.roles.administrator and nm.auth.roles.user. See the "Configuration and Licensing Guide" for details on how to change configuration settings.

Copy
nm.auth.roles.administrator = NmSuperUser
nm.auth.roles.user = NmBasicUser

Authentication Mechanisms

The authentication mechanism to use is defined by the web application in the deployment descriptor web.xml, not by the servlet container. However, most authentication mechanisms require the user name and password to be transmitted in clear text. Securing transmission (e.g. by using HTTPS) is in the responsibility of the application server and has nothing to do with the web application itself. Read the documentation of your application server on how to secure transmission.

Form Based Authentication

By default, the web application uses Form Based Authentication. The deployment descriptor contains all necessary configurations and a login form page is included in the web application. See the "Screen Editor Guide" on how to customize the login screen.

Form-basedLogin.png

Figure 2: Login form for Form Based Authentication

HTTP Basic Authentication

The web application is prepared to support HTTP Basic Authentication. The user's web browser will display a dialog box prompting for a user name and a password.

BasicLogin.png

Figure 3: Dialog box for HTTP Basic Authentication

To switch to Basic Authentication, the deployment descriptor has to be modified. The file web.xml is located in the directory WEB-INF in the web application archive. Uncomment the section about HTTP Basic Authentication and comment the Form Based Authentication section.

Copy
<login-config>
   <!--
   &lt;auth-method&gt;BASIC&lt;/auth-method&gt;
   &lt;realm-name&gt;Appway&lt;/realm-name&gt;
   -->
   <!-- 
   &lt;auth-method&gt;CLIENT-CERT&lt;/auth-method&gt;
   -->
   &lt;auth-method&gt;FORM&lt;/auth-method&gt;
   &lt;form-login-config&gt;
      &lt;form-login-page&gt;/login&lt;/form-login-page&gt;
      &lt;form-error-page&gt;/login&lt;/form-error-page&gt;
   &lt;/form-login-config&gt;
&lt;/login-config&gt;

Other Authentication Mechanisms

There are other authentication mechanisms beside HTTP Basic Authentication and Form Based Authentication. No other mechanisms have been tested with the web application, but the Java Servlet 2.3 specification explicitly mentions authentication using client certificates. Some browsers or application servers may also support vendor specific mechanisms. Please read the servlet specification and the documentation of your application server on how to enable other mechanisms. From the web applications point of view, using another authentication mechanism should not be a problem.

Scope

The authentication mechanism to be used is defined per web application. It is possible for other web applications on the same application server to use different authentication mechanisms. However, it is not possible to specify different authentication mechanisms for different protected sections within one single web application, e.g. using HTTP Basic Authentication for the Front End and Form Based Authentication for the Administration.

Logout

When using Form Based Authentication, the web application supports a logout action. Logout simply invalidates the current user session. With HTTP Basic Authentication, the web application can not force a logout, since the browser automatically logs in again using the cached user credentials. In this case, the user has to close all browser windows to logout. Therefore, logout buttons are displayed only if the web application discovers that Form Based Authentication is used.

Note: Some application servers do not properly communicate the authentication mechanism to the web application. In order to force the application to display a logout button, the configuration property `nm.logoutbutton.force` can be set to `true`.

User Database

User Database

The application has an internal user database. This database is needed to store user information that is usually not accessible from within a web application since there is no API in the Java Servlet 2.3 specification to query information like first name or last name from an external authentication provider. The database stores the following types of information:

  • user meta information like last name, first name or preferences
  • security information like password or account status

User meta information is used in the Front End. Most of the information can be managed by the user itself using the preferences screen. Other information is maintained by the web application, e.g. last login date. If there is no external authentication provider, this internal user database can be used instead. If it is used as authentication provider, passwords have to be saved in the user database. If an external authentication provider is used, no passwords are stored.

Passwords are never stored in clear text. Instead, a hash value of the password is stored.
Property Description
User Name User id (Login)
Last Name Last name of the user
First Name First name of the user
Preferences Preference settings like language or priority lists (e.g. for currencies)
Last Login Date of last login in the format "yyyy-MM-dd HH:mm:ss"
Password Hash value of the password
Account Type LOCAL or REMOTE
Account Status ACTIVE or DISABLED
Expiration Date Date of expiration in the format "yyyy-MM-dd HH:mm:ss". Empty if the account does never expire.
Roles List of comma separated role names
Groups List of comma separated group names

Table 2: User Information

The user database is stored in the file system in the directory %NM_DATA_HOME%/users. There exists an XML file for every user. The name of the file consists of the user name followed by the file extension .xml. Special characters in the user name are encoded.

Example user XML file:

Copy
<?xml version="1.0" encoding="UTF-8"?>
&lt;user version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="user.xsd"&gt;
   &lt;lastName&gt;Muster&lt;/lastName&gt;
   &lt;firstName&gt;Peter&lt;/firstName&gt;
   &lt;password&gt;5df3e02868f70e83765a3ce71c3f493f&lt;/password&gt;
   &lt;expires/&gt;
   &lt;lastLogin&gt;2006-05-18 16:00:28&lt;/lastLogin&gt;
   &lt;status&gt;ACTIVE&lt;/status&gt;
   &lt;type&gt;LOCAL&lt;/type&gt;
   &lt;memberOf&gt;
      &lt;role id="Administrator"/&gt;
      &lt;role id="User"/&gt;
      &lt;group id="Controlling"/&gt;
      &lt;group id="AccountOpening"/&gt;
   &lt;/memberOf&gt;
   &lt;preferences&gt;
      &lt;preference name="priorities.Countries" value="CH|DE|US"/&gt;
      &lt;preference name="priorities.Currencies" value="1"/&gt;
      &lt;preference name="language" value="de"/&gt;
      &lt;preference name="adminmode" value="on"/&gt;
   &lt;/preferences&gt;
&lt;/user&gt;

The user database can be maintained using the Management Console.

User Filter

The application has an HTTP request filter called User Filter processing every request accessing the web application. Follow these steps

  1. Get the name (user id) of the current user. Depending on the configuration setting nm.auth.userid.useprincipal one of the methods request.getRemoteUser() or request.getUserPrincipal().getName() is used.
  2. Try to find a user account in the internal database matching the given user name, converted to upper case. The information from the database is copied into an object of class com.nm.data.User . If there is no account for the current user, create an empty user object and fill it with the following information: user id, account type (REMOTE) and account status (ACTIVE).
  3. If the request is a login request, the user object is update with the current date as last login date.
  4. The user object is updated with the roles the user belongs to according to the roles reported by the HTTP request object.
  5. The information in the user object is written to the database (creating an account if needed).
  6. The user object is registered as thread-local variable in the current thread and in the current users HTTP session (attribute name: user.object). All subsequent processing units like servlets or JSPs may use this object to query information about the current user.

This filter guarantees that there is a user account in the internal database for every authenticated user accessing the application, no matter what authentication provider is used.

Using Appway as Authentication Provider

We do not recommend using local users for authentication. Instead, installations should always use an external user management system or identity provider, such as Microsoft ActiveDirectory or single sign-on solutions.

In order to use Appway as an authentication provider, you need a connector to pass a user name and a password to the Platform. This requires two components to play together:

The NmLoginServiceAdpater extension implements and registers a login service as Java MBean (JMX). The JAAS login module receives user name and password from the Java application server and passes these credentials to the JMX login service. For this to work, JMX support must be enabled in the Platform:

Copy
nm.jmx.enabled = true

This configuration property can be changed at any time and does not require a restart of the Platform.

The login service will verify the credentials. It checks whether there is a local user with the given user name, whether this user account is enabled and has not expired, and whether the given password is correct. Passwords of local users are never stored in clear text. Instead, passwords are always salted and hashed. FNZ Studio 2022.2.1 and greater use Argon2id as a password hashing algorithm.

If the credentials are valid, the login service returns the user ID and a list of security roles to the JAAS login module, which will pass this information back to the Java application server for finalizing the authentication process and starting the authorization process.

JAAS Login Module

The JAAS login module is a kind of plugin for the Java application server. It gets the user name and password entered by the user and must forward these credentials to the Platform for verification. We provide JAAS login modules for Tomcat, WebSphere Liberty, and JBoss EAP. JAAS login modules are identified by their fully qualified Java class names:

  • For Tomcat: com.nm.auth.jaas.JmxLoginModule
  • For WebSphere Liberty: com.nm.auth.jaas.WebSphereJmxLoginModule
  • For JBoss EAP: com.nm.auth.jaas.JBossJmxLoginModule

All JAAS login modules are bundled in one JAR file nm-jaas-login-modules-<version>.jar. FNZ Studio 2022.2.1 and greater require at least version 2.0.0. Support for WebSphere Liberty and JBoss EAP was added in version 2.1.0.

Installation and configuration of the JAAS login module depend on the Java application server and are described in the following sections.

Common to all JAAS login modules is a "debug" option which is set to false by default. If set to true, the login module will print debug messages to the application server's main log file. This can help analyze authentication problems.

Tomcat

Installation

Copy the JAR file nm-jaas-login-modules-<version>.jar into the directory ${TOMCAT_HOME}/lib.

Configuration

Create a JAAS configuration file ${DATA_HOME}/conf/jaas.conf.

Add the following content to this file:

Copy
appway {
   com.nm.auth.jaas.JmxLoginModule required
      debug="false";
};

Take note of the JAAS application name "appway" on the first line.

Open Tomcat's main configuration file ${TOMCAT_HOME}/conf/server.xml and add or update the <Realm> settings:

Copy
&lt;Realm className="org.apache.catalina.realm.JAASRealm" 
       appName="appway"
       userClassNames="com.nm.auth.jaas.NmUserPrincipal"
       roleClassNames="com.nm.auth.jaas.NmRolePrincipal"
/&gt;

Note that the value of XML attribute "appName" must match the name of the JAAS application in jaas.conf.

WebSphere Liberty

Installation

Copy the JAR file nm-jaas-login-modules-<version>.jar into the directory $WLP_HOME/usr/shared/resources.

Configuration

Add the following configuration to $WLP_HOME/usr/servers/defaultServer/server.xml in the <server> section.

Copy
<!-- basic user registry -->
&lt;basicRegistry id="basic" realm="customRealm" /&gt;

<!-- library with Nm JAAS login modules -->
&lt;library id="nm-jaas-login-modules"&gt;
    &lt;file name="${shared.resource.dir}/nm-jaas-login-modules-&lt;version&gt;.jar" />
&lt;/library&gt;

<!-- JAAS login module -->
&lt;jaasLoginModule id="appway" className="com.nm.auth.jaas.WebSphereJmxLoginModule" controlFlag="REQUIRED" libraryRef="nm-jaas-login-modules"&gt;
    &lt;options debug="false" /&gt;
&lt;/jaasLoginModule&gt;

<!-- web application login context -->
&lt;jaasLoginContextEntry id="system.WEB_INBOUND" name="system.WEB_INBOUND" loginModuleRef="appway, hashtable, userNameAndPassword, certificate, token" /&gt;

Do not forget to replace the <version> placeholder with the actual version of the JAAS login modules library.

JBoss EAP

Installation

The JAR file with the login modules must be installed as a JBoss module.

Using the JBoss CLI:

Start $JBOSS_HOME/bin/jboss-cli.sh and enter the following command:

Copy
module add --name=com.nm.auth.jaas \
           --dependencies=javax.api,org.picketbox \
           --resources=/path/to/nm-jaas-login-modules-&lt;version&gt;.jar

Manual installation:

Create a directory $JBOSS_HOME/modules/com/nm/auth/jaas/main and put nm-jaas-login-modules-<version>.jar in it. Create a new file module.xml in the same directory with the following content:

Copy
<?xml version='1.0' encoding='UTF-8'?>
&lt;module xmlns="urn:jboss:module:1.1" name="com.nm.auth.jaas"&gt;
    &lt;resources&gt;
        &lt;resource-root path="nm-jaas-login-modules-&lt;version&gt;.jar"/>
    &lt;/resources&gt;
    &lt;dependencies&gt;
        &lt;module name="javax.api"/&gt;
        &lt;module name="org.picketbox"/&gt;
    &lt;/dependencies&gt;
&lt;/module&gt;

Configuration

Open $JBOSS_HOME/standalone/configuration/standalone.xml and find the configuration for the subsystem jboss:domain:security.

Add a <login-module> element into the <authentication> section for security domain "other":

Copy
&lt;subsystem xmlns="urn:jboss:domain:security:2.0"&gt;
   &lt;security-domains&gt;
       &lt;security-domain name="other" cache-type="default"&gt;
           &lt;authentication&gt;

               &lt;login-module code="com.nm.auth.jaas.JBossJmxLoginModule" flag="required" module="com.nm.auth.jaas"&gt;
                   &lt;module-option name="password-stacking" value="useFirstPass"/&gt;
                   &lt;module-option name="debug" value="false"/&gt;
               &lt;/login-module&gt;

               <!-- other login modules -->

           &lt;/authentication&gt;
       &lt;/security-domain&gt;

If you only want to use Appway as an authentication system, you can remove other login modules that already exist in this security domain.

NmLoginServiceAdapter Extension

All the JAAS login modules try to connect to the JMX-based login services implemented in the NmLoginServiceAdapter Extension. FNZ Studio 2022.2.1 and greater require NmLoginServiceAdapter Extension version 2.0.0 or higher.

Beside enabling JXM support in the Platform, there are no further configurations required for this extension.

Case-Sensitive vs. Case-Insensitive User Names

By default, the login service will perform a case-insensitive search when looking for a user ID which matches the given user name. If a user has the user ID "Alice", this user can login as "Alice", "alice", "ALICE", or any other combination of uppercase and lowercase letters.

This behavior can be changed by setting the extension configuration property nm.auth.loginservice.caseinsensitive to false:

Copy
nm.auth.loginservice.caseinsensitive = false

Note that, while you can configure the login service to perform a case-sensitive search, this does not allow you to have two or more user IDs which only differ in case like "Alice" and "alice". User IDs must always be unique independent of uppercase/lowercase writing.

The Platform is also case-preserving with user IDs. Even if case-insensitive matches are enabled (default) and a user with the user ID "Alice" can, therefore, log in with user name "alice", the Platform will use the actual user ID "Alice" to refer to this user after it has been authenticated. The user name "alice" entered during authentication is no longer used.

Using an LDAP Directory as Authentication Provider

We provide two LDAP-related software components: The LDAP Login Module (LdapLoginModule) for JAAS and the LDAP Synchronization Adapter (LdapSyncAdapter) extension.

Both components can use the same configuration file. Some aspects within the configuration may be relevant only for one or the other component.

There are two different configuration file formats:

  • Java properties file ldap.properties This file format is supported by all versions of the LDAP Login Module and the LDAP Synchronization Adapter. It is a simple list of properties with one property (name = value) per line. See section 8.1.3.1 and section 8.2.2.1 for more information. Chapter 12 contains example configuration files for Microsoft ActiveDirectory and Novell eDirectory.
  • XML file ldap.xml This file format is supported only by newer versions of the LDAP Login Module (released after August 2015) and the LDAP Synchronization Adapter (since version 2.0). The advantage of this configuration file format is that it supports multiple LDAP directories. See chapter 13 for a description of this configuration file format.

LDAP Login Module

Class: com.nm.auth.jaas.LdapLoginModule The LDAP Login Module can be used to authenticate against Microsoft Active Directory, Novell eDirectory or other LDAP Directories. The old Active Directory Login Module shipped with Nm'4.5 is not supported anymore.

Protocol

The LDAP Login Module uses LDAP (Version 3) to communicate with one or more LDAP directory servers.

Installation

The login modules are packaged as a JAR file NmJAASLoginModules.jar. Please read the documentation of your application server on how to install JAAS login modules.

Configuration

Example JAAS configuration file:

Copy
Ldap {
   com.nm.auth.jaas.LdapLoginModule required
      debug="true"
      config="&lt;path&gt;/ldap.properties";
}
Parameter Description Default value
debug Enable/disable login module debug output. Debug output is written to standard output stream. false
config Path to the ldap.properties or ldap.xml configuration file. An example of config="<path>/ldap.properties" is config=" ../../DataHome/conf/ldap.properties". -

Table 6 : Login Module configuration parameters

Some additional configuration parameters have been added in NmJAASLoginModules version 2.3.0:

Parameter Description Default value
requiredRoles Optional comma-separated list of roles. A user must be a member of ALL of these roles before he or she is allowed to login. -
sufficientRoles Optional comma-separated list of roles. A user must be a member of AT LEAST ONE of these roles before he or she is allowed to login. The special value "ANY" can be used to match any role. -
additionalRoles Optional comma-separated list of roles. If a user has been able to login, these roles are added unconditionally. -
Note: The LDAP Login Module currently does not support optional PAM configuration options.

Configuration file "ldap.properties"

The configuration file "ldap.properties" is used by the LDAP Login Module to get information about directory servers and security role mappings. The same configuration file is used by the LDAP Synchronization Adapter which can be used to synchronize the internal user database with the LDAP directory (see below). Properties used only by the LDAP Synchronization Adapter start with "sync." and are omitted in this section.

Copy

server.default.port = 389

server.default.timeout = 10

server.default.ssl = false

server.1.address = 127.0.0.1

login.1.pattern = {USERID}@domain.local

login.1.context = dc=domain,dc=local

recursive = true

role.1.name = User

role.1.dn = cn=Nm5Users,ou=Groups,ou=Company,dc=domain,dc=local

role.2.name = Administrator

role.2.dn = cn=Nm5Admins,ou=Groups,ou=Company,dc=domain,dc=local

group.1.name = FrontOffice

group.1.dn = cn=Nm5FrontOffice,ou=Groups,ou=Company,dc=domain,dc=local

[...]

attribute.uid = sAMAccountName

attribute.groupMembership = memberOf

attribute.member = member

attribute.objectClass = objectClass

objectClass.user = user

objectClass.group = group

Parameter Description Default value
server.default.port Default TCP port of an LDAP directory server 389
server.default.timeout Default timeout for connections to an LDAP directory server 10
server.default.ssl Default setting whether to use LDAP (false) or LDAPS (true). false
server.<S>.address Host name or IP address of LDAP directory server <S> (where <S> can be 1,2,3 ...) -
server.<S>.port TCP port of LDAP directory server <S> value of server.default.port
server.<S>.timeout Timeout for connections to LDAP directory server <S> value of server.default.timeout
server.<S>.ssl Switch between LDAP (false) and LDAPS (true) value of server.default.ssl
login.<L>.pattern Login name pattern <L> (where <L> can be 1,2,3 ...) -
login.<L>.context Login context <L> -
recursive Whether or not to process groups in groups true
role.<R>.name Name of role <R> in Appway (where <R> can be 1,2,3 ...) -
role.<R>.dn Distinguished name of LDAP group mapped to role <R> in Appway -
group.<G>.name Name of group <G> in Appway (where <G> can be 1,2,3 ...) -
group.<G>.dn Distinguished name of LDAP group mapped to group <R> in Appway -
attribute.uid Name of the LDAP user object attribute containing the user id ("uid" for eDirectory, "sAMAccountName" for AD) uid
attribute.groupMembership Name of the LDAP user object attribute containing the distinguished names of groups the user is member in ("groupMembership" for eDirectory, "memberOf" for AD) groupMembership
attribute.member Name of the LDAP group object attribute containing the distinguished names of group members (users and other groups) member
attribute.objectClass Name of the LDAP object attribute containing the object type informations objectClass
objectClass.user Name of the LDAP object class for user objects ("person" for eDirectory, "user" for AD) person
objectClass.group Name of the LDAP object class for group objects ("groupOfNames" for eDirectory, "group" for AD) groupOfNames

Table 7: Configuration file properties

The placeholders \<S>, \<L>, \<R> and \<G> have to be replaced with positive integers. The numbering must be continuous. An example:

Copy

server.1.address = 10.0.0.21

server.2.address = 10.0.0.22

server.3.address = 10.0.0.133

server.3.port = 8389

server.3.ssl = true

server.4.address = 10.0.1.120

server.4.port = 8389

server.4.timeout = 20

If server 3 is deleted in the above example, the properties for server 4 have to be renamed to "server.3.address", "server.3.port" and "server.3.timeout". If this is not done, there is a hole in the chain and the configuration for server 4 is not found. Therefore, only 2 servers are used.

The configuration file "ldap.properties" can be modified at runtime. There is no need to restart the application server or redeploy the web application after a modification. On every login request, the time stamp of the configuration file is checked and if the file has been modified, it is reloaded.

Login Process

The login process in details:

  1. The login module tries to connect to the first server. If the server doesn't respond within the time specified by the timeout property, the next server is contacted. If none of the servers is accessible, authentication is aborted.
  2. If the login module can connect to a server, the first login pattern property is used to generate a login name. Within the login pattern, the placeholder "" is replaced with the user name provided by the user. The resulting login name and the password provided by the user are used to authenticate against the directory. If the login name is not accepted, the next login pattern is used to create a login name. If there are no more login patterns available, authentication is aborted.
  3. If a login name and password have been accepted, the login name is used to find the user object in the directory.
    • First, the login name is assumed to be the distinguished name of the user. The login module tries to load the user object using this distinguished name directly. This may work for some LDAP directories (eDirectory for instance), but not for others like Active Directory.
    • If the login name can't be used directly to find the user object, a search operation is performed in the directory. The search is a recursive search on the directory starting at the node defined by the login context property. If the login name build from login.3.pattern succeeded, login.3.context is used as context. The following LDAP search filter is used (If the search returns no results or more than one result, authentication aborted):
      <attribute.uid>={USERID}<attribute.objectCall>=<objectClass.user>
  4. Now, the user is considered authenticated. In most LDAP directories, login names are case insensitive (passwords are usually case sensitive). The login module will return the user name as it is spelled in the LDAP directory (saved in the user object attribute defined by the property attribute.uid).
  5. The login module needs to supply the security roles the user is member of. This is done in an iterative process. The attribute defined by attribute.groupMembership of the user object is supposed to contain the distinguished names of all LDAP groups the user is member of. All this groups are loaded. If the parameter "recursive" is set to "true" (default), these groups are again checked to be members of other groups. These newly found groups are added to the list and processed as well until no more groups are found. The result of this process is a list with all the groups the user is member of, either directly or by membership in a subgroup.
It is important that the group membership attribute used in this step contains distinguished names of the groups and not simple canonical names.
  1. The distinguished names of the groups then get compared to the role.\<R>.dn properties. If there is a match with a group, the role defined by role.\<R>.name is assigned to the user.
The distinguished names of the groups get matched using a case insensitive comparison. However, all other aspects like white spaces and LDAP path prefixes (ou, cn, dc etc.) must match exactly.

The result of this process is the users LDAP specific user name plus all the roles the user is member of. This information is returned to the application server.

LDAP Synchronization Adapter

If an external authentication provider is used, the application has no details about a user but the information provided by the application server through the methods of the HTTP request object: user name, user principal and role membership. The User Filter is using this information to insert and/or update user accounts in the internal user database. All other information like first name and last name needs to be maintained by the user itself using the preferences screen in the application.

Problems:

  • A user who has never logged into the application is not visible to other users. No one can forward document folders to this user.
  • If a user's name is changed in the external user database, this information is not updated in the user database.
  • If a user is deleted in the external user database, the user is not deleted in the user database. The user can not login anymore, but the resources of this user (e.g. document folders) are still in the database.

This problem can be solved using an Adapter to automatically synchronize the internal user database with the external user database from time to time. The LDAP Synchronization Adapter can be used to read user information from MS Active Directory (AD), Novell eDirectory or other LDAP directories and write it to the user database.

This is a one-way synchronization. Information is read from the LDAP directory and written to the internal user database. Therefore, the service account used to connect to the LDAP directory may be restricted to only have read privileges.

Installation

The LDAP Synchronization Adapter is shipped together with optional Module "LDAP/MS Active Directory Adapter".

Configuration

The LDAP Synchronization Adapter may use the same configuration file like the LDAP Login Module. Therefore, the most important configuration setting is the path to the configuration file "ldap.properties".

Parameter Description Default value
Text Text Text
jobName Name of the job used to register the synchronization job in the scheduler service. LDAP User Sync
jobSchedule Schedule used to trigger the synchronization job. The format is similar to cron job expressions. 0 0/15 * * * ? (every 15 minutes)
config Path to the "ldap.properties" configuration file. -

Table 8 : Configuration parameters

Configuration file "ldap.properties" (part 2)

The options prefixed with "sync." are used exclusively by the LDAP Synchronization Adapter.

Copy
[...]

sync.user = cn=nm4service,ou=Users,o=Company
sync.password = nm4passwd

sync.updateLocalUsers = false
sync.deleteLocalUsers = false
sync.deleteUsers = true
sync.updateGroups = true
sync.updateRoles = true

sync.mapping.1.attribute = mail
sync.mapping.1.preference = ldap.email

sync.mapping.2.attribute = displayName
sync.mapping.2.preference = ldap.name

[...]

Parameter Description Default value
sync.user Login name of the service account used to connect to the LDAP directory -
sync.password Password of the service account -
sync.updateLocalUsers If set to true, users of type "LOCAL" also get updated false
sync.deleteUsers If set to true, users get deleted if there is no corresponding account in the LDAP directory true
sync.deleteLocalUsers If set to true and sync.deleteUsers is set to true as well, users of type "LOCAL" get deleted too false
sync.updateGroups If set to true, group membership information is updated true
sync.updateRoles If set to true, role membership information is updated true
sync.mapping.<M>.attribute LDAP user object attribute name for attribute mappings (where <M> can be 1,2,3 ...) -
sync.mapping.<M>.preference Name of the user preference to save the value of attribute mapping <M> -

Table 9 : Configuration file properties

The configuration file "ldap.properties" can be modified at runtime. There is no need to restart the application server, redeploy the web application or restart the adapter after a modification.

Mapping of special Active Directory attributes

LDAP objects in Active Directory can contain attributes of special types like GUID (Globally Unique Identifier) or SID (Security Identifier). Values of such attributes require special decoding. When mapping such attributes to user preferences, the configuration must contain type definitions for these attributes.

For example, to map the attribute "objectGIUD" of type GUID and the attribute "objectSID" of type SID, the following configuration is required:

Copy
type.objectGUID = GUID
type.objectSID = SID

When using the XML configuration format:

Copy
&lt;attributeType name="objectGUID" type="GUID"/&gt;
&lt;attributeType name="objectSID" type="SID"/&gt;

Synchronization Process

Startup

During the startup phase, the adapter is registering a synchronization job with the job scheduler service (using the parameters "jobName" and "jobSchedule").

Synchronization

Every time, the synchronization job is triggered, the adapter initiates a new LDAP connection to the first LDAP server in the configuration (property "server.1.address"). If this server is not answering, the next server on the list is used. In order to login to the LDAP directory, the adapter uses a service account defined by the two properties "sync.user" and "sync.password". This account must have read privileges on all LDAP group objects referenced by the properties "role.<R>.dn" and "group.<G>.dn" and of course on the user objects. After establishing a connection, the adapter gets all information for the LDAP groups denoted by the "group.<G>.dn" and "role.<R>.dn" distinguished name properties. If the property recursive is set to true, the members of the groups get checked whether they are groups them self. All users which are member in at least one of the groups found in this step, get loaded from the LDAP directory.

The LDAP groups must contain the distinguished names of their members (users and other groups). Canonical names can not be resolved.

The user object attribute defined by the property "attribute.uid" is used as user id. The user object is expected to contain an attribute "sn" with the last name and an attribute "givenName" with the first name of the user. In addition to this, the user object is checked to contain the attributes defined by the "sync.mapping.<M>.attribute" properties. If the user contains such an attribute, its value is saved in the user's preferences using the name from the property "sync.mapping.<M>.preference". Next, the synchronization takes place. The link between the LDAP user and the user in the database is made using the user id (case insensitive):

  • Insert: A new account is created in the internal database for every user loaded from the directory but not present in the internal database. The following information is added to the user account: user id, last name (from attribute "sn"), first name ("givenName"), group and role membership and preference settings. The account type is set to "REMOTE".
  • Update: Users present in both LDAP directory and internal database are update in the internal database. Note: if a user account is of type "LOCAL", the property "sync.updateLocalUsers" is checked to decide, whether the account should be updated.
  • Delete: If the property "sync.deleteUsers" is set to true, users found only in the internal database but not in the LDAP directory get deleted from the internal database. Note: if a user account is of type "LOCAL", the property "sync.deleteLocalUsers" is checked to decide, whether it should be deleted.
  • Disable (since LdapSyncAdapter versions 5.0.2 and 7.0.3): If the property "sync.disableUsers" is set to true (default is false) and "sync.deleteUsers" is set to false, users found only in the internal database but not in the LDAP directory get disabled from the internal database. The user memberships to roles and groups are removed but the user information and preferences are kept. Note: if a user account is of type "LOCAL", the property "sync.disableLocalUsers" (default is false) is checked to decide, whether it should be disabled. Note also: when a disabled user becomes available again in the LDAP directory, the user is synchronized again as an active user with groups and roles.

Shutdown

During the shutdown phase, the adapter in unregistering the synchronization job in the scheduler server.

Debugging

The LDAP Synchronization Adapter uses the default log4j logging mechanisms provided by the application. After setting the level of the logger "com.nm.syncadapter.ldap.SyncJob" to "DEBUG", debug output is written to the file "%NM_DATA_HOME%/logs/debug.log".

Using other Authentication Providers

There are many application servers and even more authentication providers available. Describing all possible combinations regarding configuration of the authentication system is out of scope. However, there are some common hints how to get to the own systems working together.

Generic and Predefined Connectors

Read the documentation of your application server. Most application servers are shipped with a set of predefined connectors which allow to integrate external authentication providers. Most of these connectors are very generic (e.g. authentication against LDAP directory or against a relational database using JDBC) and need complex configuration. There may be problems using these generic connectors with your concrete authentication system, e.g. if your system is not a 100% standard compliant LDAP server.

Third-party Extensions

If there is no appropriate connector for your authentication provider (e.g. a Radius server), check if you can find third-party extensions for your application server.

JAAS Login Modules

Some application servers have connector adapters. Tomcat for instance has a JAASRealm allowing you to plug-in any JAAS compliant login module. Try to find a JAAS login module for your authentication provider, or write your own login module.

Custom Connector

Write your own connector. This step usually involves studying of the documentation of your application servers SDK or API.

Built-in User Database

Some application servers have built-in user databases (or even build-in LDAP directories). Read the documentation of your application server on how to enable and manage these.

Configuration Examples

Tomcat 7 and 8

Install JAAS Login Modules

Install the JAAS Login Modules into Tomcat. Place the JAR file "NmJAASLoginModules.jar" in the directory "%CATALINA_HOME%/common/lib".

Install Login Service Adapter

Install the Login Service Adapter into the application. Place the JAR file "NmLoginServiceAdapter.jar" in the directory "%NM_DATA_HOME%/adapters".

Configure JAAS

Create a JAAS configuration file "%CATALINA_BASE%/conf/jaas.conf". Internal database as authentication system:

Copy
Appway {
   com.nm.auth.jaas.NmLoginModule required
      debug="true"
      url="http://localhost/weblistener/anonymous/listener/LoginService"
      secret="abcdef";
};

LDAP Directory as authentication system:

Copy
Appway {
   com.nm.auth.jaas.LdapLoginModule required
      debug="true"
      config="&lt;path&gt;/ldap.properties";
};

Adapt the login module parameters to your environment. The JAAS application names ("Nm" in the above example file) can be chosen at will. You will have to specify the name you use here in step 3. You can place the file "jaas.conf" somewhere else or even give it another name. You will have to set the path to this file in step 4.

Configure Tomcat to use JAAS

Configure Tomcat to use a JAASRealm. Edit the file "%CATALINA_BASE%/conf/server.xml" and add the following section to the component hosting the web application (usually between <Host name="localhost"> and </Host>).

Copy
&lt;Realm
   className="org.apache.catalina.realm.JAASRealm"
   debug="1"
   appName="Appway"
   userClassNames="com.nm.auth.jaas.NmUserPrincipal"
   roleClassNames="com.nm.auth.jaas.NmRolePrincipal"
/&gt;

The value of parameter "appName" must match the JAAS application name in the JAAS configuration file "jaas.conf".

Configure JVM to enable JAAS on startup

Enable JAAS support when starting the JVM hosting the Tomcat Servlet Container. To enable JAAS you have to add a Java property to the command line when starting Tomcat. Edit the file "catalina.bat" in the directory "%CATALINA_BASE%/bin" and add the following line:

Copy
set JAVA_OPTS=%JAVA_OPTS% -Djava.security.auth.login.config=%CATALINA_BASE%/conf/jaas.conf

Deployment Descriptor

This is the default deployment descriptor for the web application:

Copy
&lt;web-app&gt;

   [...]

   &lt;filter&gt;
      &lt;filter-name&gt;UserFilter&lt;/filter-name&gt;
      &lt;filter-class&gt;com.nm.filter.UserFilter&lt;/filter-class&gt;
   &lt;/filter&gt;

   [...]

   &lt;filter-mapping&gt;
      &lt;filter-name&gt;UserFilter&lt;/filter-name&gt;
      &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
   &lt;/filter-mapping&gt;

   [...]

   &lt;security-constraint&gt;
      &lt;web-resource-collection&gt;
         &lt;web-resource-name&gt;Front End&lt;/web-resource-name&gt;
         &lt;url-pattern&gt;/stages/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/views/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/weblistener/user/*&lt;/url-pattern&gt;
      &lt;/web-resource-collection&gt;
      &lt;auth-constraint&gt;
         &lt;role-name&gt;User&lt;/role-name&gt;
      &lt;/auth-constraint&gt;
   &lt;/security-constraint&gt;

   &lt;security-constraint&gt;
      &lt;web-resource-collection&gt;
         &lt;web-resource-name&gt;Administration&lt;/web-resource-name&gt;
         &lt;url-pattern&gt;/admin/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/webdav/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/weblistener/admin/*&lt;/url-pattern&gt;
      &lt;/web-resource-collection&gt;
      &lt;auth-constraint&gt;
         &lt;role-name&gt;Administrator&lt;/role-name&gt;
      &lt;/auth-constraint&gt;
   &lt;/security-constraint&gt;

   &lt;security-constraint&gt;
      &lt;web-resource-collection&gt;
         &lt;web-resource-name&gt;Listeners&lt;/web-resource-name&gt;
         &lt;url-pattern&gt;/listener/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/accessor/*&lt;/url-pattern&gt;
         &lt;url-pattern&gt;/weblistener/everybody/*&lt;/url-pattern&gt;
      &lt;/web-resource-collection&gt;
      &lt;auth-constraint&gt;
         &lt;role-name&gt;User&lt;/role-name&gt;
         &lt;role-name&gt;Administrator&lt;/role-name&gt;
      &lt;/auth-constraint&gt;
   &lt;/security-constraint&gt;

   &lt;login-config&gt;
      <!--
      &lt;auth-method&gt;BASIC&lt;/auth-method&gt;
      &lt;realm-name&gt;Appway&lt;/realm-name&gt;
      -->
      &lt;auth-method&gt;FORM&lt;/auth-method&gt;
      &lt;form-login-config&gt;
         &lt;form-login-page&gt;/login&lt;/form-login-page&gt;
         &lt;form-error-page&gt;/login&lt;/form-error-page&gt;
      &lt;/form-login-config&gt;
   &lt;/login-config&gt;

   &lt;security-role&gt;
      &lt;description&gt;Users&lt;/description&gt;
      &lt;role-name&gt;User&lt;/role-name&gt;
   &lt;/security-role&gt;

   &lt;security-role&gt;
      &lt;description&gt;Administrators&lt;/description&gt;
      &lt;role-name&gt;Administrator&lt;/role-name&gt;
   &lt;/security-role&gt;

&lt;/web-app&gt;

Configuration file 'ldap.properties'

Active Directory example

Copy
server.default.port = 389
server.default.timeout = 10

server.1.address = 127.0.0.1

login.1.pattern = {USERID}@domain.local
login.1.context = dc=domain,dc=local

recursive = true

role.1.name = User
role.1.dn = cn=Nm5Users,ou=Groups,ou=Company,dc=domain,dc=local

role.2.name = Administrator
role.2.dn = cn=Nm5Admins,ou=Groups,ou=Company,dc=domain,dc=local

group.1.name = FrontOffice
group.1.dn = cn=Nm5FrontOffice,ou=Groups,ou=Company,dc=domain,dc=local

sync.user = nm5service@domain.local
sync.password = nm5passwd
sync.updateLocalUsers = false
sync.deleteLocalUsers = false
sync.disableLocalUsers = false
sync.deleteUsers = true
sync.disableUsers = false
sync.updateGroups = true
sync.updateRoles = true

sync.mapping.1.attribute = mail
sync.mapping.1.preference = ldap.email

sync.mapping.2.attribute = displayName
sync.mapping.2.preference = ldap.name

attribute.uid = sAMAccountName
attribute.groupMembership = memberOf
attribute.member = member
attribute.objectClass = objectClass

objectClass.user = user
objectClass.group = group

Novell eDirectory example

Copy
server.default.port = 389
server.default.timeout = 10

server.1.address = 127.0.0.1

login.1.pattern = cn={USERID},ou=Users,o=Company
login.1.context = ou=Users,o=Company

recursive = true

role.1.name = User
role.1.dn = cn=Nm5Users,ou=Groups,o=Company

role.2.name = Administrator
role.2.dn = cn=Nm5Admins,ou=Groups,o=Company

group.1.name = FrontOffice
group.1.dn = cn=Nm5FrontOffice,ou=Groups,o=Company

sync.user = cn=nm5service,ou=Users,o=Company
sync.password = nm5passwd
sync.updateLocalUsers = false
sync.deleteLocalUsers = false
sync.disableLocalUsers = false
sync.deleteUsers = true
sync.disableUsers = false
sync.updateGroups = true
sync.updateRoles = true

sync.mapping.1.attribute = mail
sync.mapping.1.preference = ldap.email

sync.mapping.2.attribute = displayName
sync.mapping.2.preference = ldap.name

attribute.uid = uid
attribute.groupMembership = groupMembership
attribute.member = member
attribute.objectClass = objectClass

objectClass.user = person
objectClass.group = groupOfNames

Configuration file 'ldap.xml'

The XML-based configuration file has the advantage that it supports multiple LDAP directories. This means that the LDAP Login Module can try to authenticate a user against multiple LDAP directories and that the LDAP Synchronization Adapter can synchronize users from multiple LDAP directories into the user database.

The LDAP Login Module and LDAP Synchronization Adapter can use the same configuration file. However, some parts of the configuration may apply only to one or the other component.

The content of the XML configuration file can be changed at run time. Neither the LDAP Synchronization Adapter nor Appway or Tomcat have to be restarted for changes to have an effect.

The following sections describe the structure of the XML configuration file.

Directories

The root element is <ldap>. It contains a sequence of <directory> elements:

  • Every directory represents an LDAP directory and must have a unique name. The name can be an arbitrary text, it does not have a functional impact.
  • The attribute recursive is used to control whether nested LDAP groups are processed, by default it is set to true. See Synchronization for more information.
Copy
&lt;ldap&gt;
   &lt;directory name="foo"&gt;
      ...
   &lt;/directory&gt;
   &lt;directory name="bar" recursive="false"&gt;
      ...
   &lt;/directory&gt;
&lt;/ldap&gt;

The configuration file must contain at least one directory. There is no upper limit. The order of the directory elements is not important, except for the handling of duplicate users (see below).

Schema

LDAP directories of different vendors usually have a different schema. This means that the names of the attributes in the LDAP objects are different from vendor to vendor. In order to extract information about users and groups, the login module and the adapter must know the names of the LDAP object classes for users and groups, and LDAP attribute names used by these classes.

The login module and adapter already contain schema definitions for Microsoft ActiveDirectory and Novell eDirectory. For other vendors, the schema has to be configured explicitly.

The schema is defined with a <schema> element inside the <directory> element. So every directory can have a different schema:

Copy
&lt;directory name="foo"&gt;
   &lt;schema type="ActiveDirectory" /&gt;
   ...
&lt;/directory&gt;

For Microsoft ActiveDirectory, the following schema definition can be used:

Copy
&lt;schema type="ActiveDirectory" /&gt;

For Novell eDirectory, the following schema definition can be used:

Copy
&lt;schema type="eDirectory" /&gt;

For directories of other LDAP vendors, the schema has to be defined explicitly. The attribute "type" then has to be set to "Custom".

Copy
&lt;schema type="Custom"&gt;
   &lt;property name="attribute.uid" value="uid"/&gt;
   &lt;property name="attribute.lastName" value="sn"/&gt;
   &lt;property name="attribute.firstName" value="givenName"/&gt;
   &lt;property name="attribute.groupMembership" value="memberOf"/&gt;
   &lt;property name="attribute.member" value="uniqueMember"/&gt;
   &lt;property name="attribute.objectClass" value="objectClass"/&gt;
   &lt;property name="attribute.userAccountControl" value=""/&gt;
   &lt;property name="attribute.picture" value=""/&gt;
   &lt;property name="objectClass.user" value="person"/&gt;
   &lt;property name="objectClass.group" value="groupOfUniqueNames"/&gt;
&lt;/schema&gt;

The schema definition is a set of name/value properties. There are eight properties for names of LDAP attributes and two properties for names of LDAP object classes.

Property Description ActiveDirectory eDirectory
attribute.uid Name of the LDAP attribute containing the user name (user id or uid). sAMAccountName uid
attribute.lastName Name of the LDAP attribute containing the last name of a user. sn sn
attribute.firstName Name of the LDAP attribute containing the first name of a user. givenName givenName
attribute.groupMembership Name of the LDAP attribute containing the list of groups a user is a member of. memberOf groupMembership
attribute.member Name of the LDAP attribute containing the list of users which are member of a group. member member
attribute.objectClass Name of the LDAP attribute containing the type an LDAP object has. objectClass objectClass
attribute.userAccountControl Name of LDAP attribute with user account control information. userAccountControl [not supported]
attribute.picture Name of LDAP attribute with an image of a user. thumbnailPhoto [unknown]
objectClass.user Name of the LDAP object class representing a LDAP user object. user person
objectClass.group Name of the LDAP object class representing a LDAP group object. group groupOfNames

Servers

Every directory must contain at least one <server> element. There is no upper limit on the number of server elements. The order of the server elements is important. The LDAP Login Module and the LDAP Synchronization Adapter will try to contact the LDAP servers in the order they are listed here.

Copy
&lt;server address="10.0.1.100" port="389" ssl="false" timeout="10"/&gt;

The attribute "address" is mandatory. It must contain an IP address or DNS name of a server hosting this LDAP directory.

For ActiveDirectory, add one server element for every domain controller at the local site.

The attribute "port" is optional. The default LDAP port is 389.

If the attribute "ssl" is set to "true", the extension will connect to the server using LDAPS instead of LDAP. You then probably should set the port to 636, the default port for LDAPS.

The attribute "timeout" is optional. The default value is 10 seconds. It is used to specify a connection timeout in seconds. The LDAP components will try to establish an LDAP (or LDAPS) connection to the first server. If it fails, it will try to contact the second server, and so on.

If the LDAP Login Module cannot reach any server of a directory, it simply continues with the next directory. If the LDAP Synchronization Adapter cannot reach at least one server of a directory, the complete synchronization process is aborted.

Authentication

LDAP Login Module

The LDAP Login Module gets the username and password from the application server. It then tries to connect to the LDAP servers with these credentials. Often, the LDAP username is slightly different from the web username. The user may login to the web application with a short name like "smith". But in order to connect to LDAP, a qualified name with a domain prefix or suffix, or even an LDAP distinguished name has to be used. So the LDAP login name could look like "MYDOMAIN\smith", "smith@mydomain.local", or "uid=smith,ou=users,dc=mydomain,dc=local".

The mapping from a web username to an LDAP username is configured with <loginPattern> elements. Every directory must contain at least one login pattern element.

Copy
&lt;directory name="foo"&gt;
   ...
   &lt;loginPattern pattern="{USERID}@mydomain.local" context="dc=mydomain,dc=local" /&gt;
   ...
&lt;/directory&gt;

The attribute "pattern" contains a placeholder "". This placeholder is replaced with the username entered by the user to generate an LDAP username. Other common login pattern examples:

Copy
// LDAP login with a Windows NT Domain name
&lt;loginPattern pattern="MYDOMAIN\{USERID}" context="dc=mydomain,dc=local" /&gt;

// LDAP login with an LDAP distinguished name
&lt;loginPattern pattern="uid={USERID},ou=users,dc=mydomain,dc=local" context="dc=mydomain,dc=local" /&gt;

// LDAP login with web username
&lt;loginPattern pattern="{USERID}" context="dc=mydomain,dc=local" /&gt;

If there are multiple login patterns, the LDAP Login Module will try the first login pattern. If authentication fails, it will continue with the second login pattern, and so on.

If it is able to connect to an LDAP server, it has to find the LDAP user object for the current user. It first tries to use the LDAP username as distinguished name. If it cannot retrieve an LDAP user object this way, it has to perform a search for the LDAP user object. The search is limited to the LDAP sub-tree specified with the second attribute "context" of the login pattern element.

LDAP Synchronization Adapter

The LDAP Synchronization Adapter always uses the same credentials to connect to an LDAP directory. Every directory therefore needs a <username> and a <password> element:

Copy
&lt;directory name="foo"&gt;
   ...
   &lt;username&gt;appwaysync@mydomain.local&lt;/username&gt;
   &lt;password&gt;something-secure-123&lt;/password&gt;
   ...
&lt;/directory&gt;

Mappings

There are three types of mappings:

  • Role mappings from an LDAP group to an Appway role
  • Group mappings from an LDAP group to an Appway group
  • Preference mappings from an LDAP user attribute to an Appway user preference

Mappings are always defined per directory.

Role Mappings

The following example shows two role mappings:

Copy
&lt;roleMapping role="User" dn="cn=AppwayUsers,ou=groups,dc=mydomain,dc=local"/&gt;
&lt;roleMapping role="Administrator" dn="cn=AppwayAdmins,ou=groups,dc=mydomain,dc=local"/&gt;

In most installations, there should be at least two mappings for user roles, one for the Appway role "User" and one for the Appway role "Administrator". Additional solution-specific role mappings may be added. There is no upper limit on the number of role mappings. The order of role mapping elements is not important.

Every role mapping must specify the name of an Appway role (attribute "role") and the distinguished name of an LDAP group (attribute "dn").

All users in the given LDAP group are loaded into the Appway database and become a member of the given Appway role. The same LDAP group may be used in multiple role mappings, e.g. if the members of an LDAP group should become members of multiple Appway roles.

Group Mappings

Group mappings work the same way as role mappings.

Copy
&lt;groupMapping group="TeamAlpha" dn="cn=TeamAlpha,ou=teams,dc=mydomain,dc=local"/&gt;
&lt;groupMapping group="TeamBeta" dn="cn=TeamBeta,ou=teams,dc=mydomain,dc=local"/&gt;

Group mappings have no meaning for the LDAP Login Module and are ignored.

Nested LDAP Groups

LDAP groups used in role mappings and group mappings may contain other LDAP groups. The LDAP Synchronization Adapter will collect all group members of all nested groups recursively. The LDAP Login Module also follows all LDAP groups in groups to collect all groups a user is a member of.

Preference Mappings

The LDAP Synchronization Adapter will by default synchronize the user id, first name, and last name of a user. Additional information can be synchronized and stored as user preferences in Appway.

Copy
&lt;preferenceMapping preference="ldap.dn" attribute="distinguishedName"/&gt;
&lt;preferenceMapping preference="ldap.name" attribute="displayName"/&gt;
&lt;preferenceMapping preference="ldap.initials" attribute="initials"/&gt;
&lt;preferenceMapping preference="ldap.email" attribute="mail"/&gt;

Every preference mapping must specify the name of an LDAP attribute (attribute "attribute") and the name of an Appway user preference (attribute "preferenece").

Best practice tip:

We suggest to prefix all LDAP-related user preferences with "ldap.". This helps to distinguish user preferences managed by the LDAP Synchronization Adapter from other user preferences.

The order of preference mapping elements is not important. Preference mappings have no meaning for the LDAP Login Module and are ignored.

Global synchronization options

The LDAP Synchronization Adapter needs some more settings which are not directory-specific. These settings are specified in a <syncOptions> element:

Copy
&lt;syncOptions 
   deleteUsers="true" disableUsers="false" 
   updateGroups="true" updateRoles="true" 
   updateLocalUsers="false" deleteLocalUsers="false" disableLocalUsers="false" 
   updatePictures="false"
/&gt;

All attributes a simple "true" or "false" as value. They have the following meaning:

Property Description
deleteUsers If set to "true" (default), Appway users of type "REMOTE" get deleted if they cannot be found in an LDAP directory. If set to "false", Appway users will not be deleted if they no longer exist in an LDAP directory.
disableUsers If set to true (default is false) and deleteUsers is set to false, users found only in the internal database but not in the LDAP directory get disabled from the internal database. The user memberships to roles and groups are removed but the user information and preferences are kept. Available since LdapSyncAdapter versions 5.0.2 and 7.0.3.
updateRoles If set to "true" (default), role mappings are executed. If set to "false", role mappings are only used to collect users which should be synchronized into the Appway user database, but their role membership is not changed.
updateGroups If set to "true" (default), group mappings are executed. If set to "false", group mappings are only used to collect users which should be synchronized into the Appway user database, but their group membership is not changed.
updateLocalUsers If set to "false" (default), Appway users of type "LOCAL" are not updated with information from an LDAP directory.
deleteLocalUsers If set to "false" (default), Appway users of type "LOCAL" are not deleted if they cannot be found in an LDAP directory.
disableLocalUsers If set to "false" (default), Appway users of type "LOCAL" are not disabled if they cannot be found in an LDAP directory. Available since LdapSyncAdapter versions 5.0.2 and 7.0.3.
updatePictures If set to "true", the extension will try to load a user photo from the LDAP directory and save it as avatar picture in Appway.

Example XML configuration file

Copy
&lt;ldap&gt;

   &lt;directory name="mydomain.local"&gt;

      &lt;schema type="ActiveDirectory"/&gt;

      &lt;server address="172.16.0.153" port="389" ssl="false" /&gt;
      &lt;server address="10.0.2.36" port="636" ssl="true" timeout="15"/&gt;

      &lt;username&gt;AppwayServiceAccount@mydomain.local&lt;/username&gt;
      &lt;password&gt;changeit&lt;/password&gt;

      &lt;loginPattern pattern="{USERID}@mydomain.local" 
                    context="dc=mydomain,dc=local" /&gt;

      &lt;roleMapping role="User" 
         dn="cn=AppwayUsers,ou=Groups,dc=mydomain,dc=local"/&gt;
      &lt;roleMapping role="Administrator" 
         dn="cn=AppwayAdmins,ou=Groups,dc=mydomain,dc=local"/&gt;
      &lt;groupMapping group="Management" 
         dn="cn=Management,ou=Groups,dc=mydomain,dc=local"/&gt;
      &lt;preferenceMapping preference="ldap.email" attribute="mail"/&gt;
      &lt;preferenceMapping preference="ldap.name" 
         attribute="displayName"/&gt;
      &lt;preferenceMapping preference="ldap.dn" 
         attribute="distinguishedName"/&gt;

   &lt;/directory&gt;

   &lt;syncOptions deleteUsers="true" 
                  disableUsers="false" 
                updateLocalUsers="false" 
                deleteLocalUsers="false" 
                disableLocalUsers="false" 
                updateGroups="true" 
                updateRoles="true" 
                updatePictures="false"
   /&gt;

&lt;/ldap&gt;

Encryption of LDAP configuration properties

Starting with LdapSyncAdapter extension version 2.1, the LDAP username and LDAP password stored in the configuration file (ldap.properties or ldap.xml) can be stored in an encrypted form. Encryption and decryption is based on the key service provided by the Appway core.

To enable support for encrypted username and password, a system administrator first has to create a new encryption key in the key service. The key must have the alias name "LdapSyncAdapter".

Next, the LDAP username and password have to be encrypted with this key. The encrypted values then have to be written into the configuration file. In order for the extension to detect that the values are encrypted, they must be wrapped with ENC(...).

Example configuration in ldap.properties:

Copy
sync.user = ENC(wzckqF5LE_XpalyHNiwoQkGu3WMl8rNlJLUPWFMzWXY)
sync.password = ENC(emI-BkYplIvi7nSafx_P8vVAxXT2zxIPNBCjvvPnthw)

Example configuration in ldap.xml:

Copy
&lt;directory ...&gt;
   &lt;username&gt;ENC(wzckqF5LE_XpalyHNiwoQkGu3WMl8rNlJLUPWFMzWXY)&lt;/username&gt;
   &lt;password&gt;ENC(emI-BkYplIvi7nSafx_P8vVAxXT2zxIPNBCjvvPnthw)&lt;/password&gt;
&lt;/directory&gt;