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.
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/*
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:
<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:
<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
.
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.
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.
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.
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.
<login-config>
<!--
<auth-method>BASIC</auth-method>
<realm-name>Appway</realm-name>
-->
<!--
<auth-method>CLIENT-CERT</auth-method>
-->
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login</form-login-page>
<form-error-page>/login</form-error-page>
</form-login-config>
</login-config>
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:
<?xml version="1.0" encoding="UTF-8"?>
<user version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="user.xsd">
<lastName>Muster</lastName>
<firstName>Peter</firstName>
<password>5df3e02868f70e83765a3ce71c3f493f</password>
<expires/>
<lastLogin>2006-05-18 16:00:28</lastLogin>
<status>ACTIVE</status>
<type>LOCAL</type>
<memberOf>
<role id="Administrator"/>
<role id="User"/>
<group id="Controlling"/>
<group id="AccountOpening"/>
</memberOf>
<preferences>
<preference name="priorities.Countries" value="CH|DE|US"/>
<preference name="priorities.Currencies" value="1"/>
<preference name="language" value="de"/>
<preference name="adminmode" value="on"/>
</preferences>
</user>
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
- 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. - 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
). - If the request is a login request, the user object is update with the current date as last login date.
- The user object is updated with the roles the user belongs to according to the roles reported by the HTTP request object.
- The information in the user object is written to the database (creating an account if needed).
- 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
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:
- An FNZ-specific JAAS login module for the Java application server (see the JAAS Login Module section below).
- The NmLoginServiceAdpater Extension(see the NmLoginServiceAdapter Extension section below).
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:
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:
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:
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="appway"
userClassNames="com.nm.auth.jaas.NmUserPrincipal"
roleClassNames="com.nm.auth.jaas.NmRolePrincipal"
/>
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.
<!-- basic user registry -->
<basicRegistry id="basic" realm="customRealm" />
<!-- library with Nm JAAS login modules -->
<library id="nm-jaas-login-modules">
<file name="${shared.resource.dir}/nm-jaas-login-modules-<version>.jar" />
</library>
<!-- JAAS login module -->
<jaasLoginModule id="appway" className="com.nm.auth.jaas.WebSphereJmxLoginModule" controlFlag="REQUIRED" libraryRef="nm-jaas-login-modules">
<options debug="false" />
</jaasLoginModule>
<!-- web application login context -->
<jaasLoginContextEntry id="system.WEB_INBOUND" name="system.WEB_INBOUND" loginModuleRef="appway, hashtable, userNameAndPassword, certificate, token" />
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:
module add --name=com.nm.auth.jaas \
--dependencies=javax.api,org.picketbox \
--resources=/path/to/nm-jaas-login-modules-<version>.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:
<?xml version='1.0' encoding='UTF-8'?>
<module xmlns="urn:jboss:module:1.1" name="com.nm.auth.jaas">
<resources>
<resource-root path="nm-jaas-login-modules-<version>.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.picketbox"/>
</dependencies>
</module>
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":
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="com.nm.auth.jaas.JBossJmxLoginModule" flag="required" module="com.nm.auth.jaas">
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="debug" value="false"/>
</login-module>
<!-- other login modules -->
</authentication>
</security-domain>
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
:
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:
Ldap {
com.nm.auth.jaas.LdapLoginModule required
debug="true"
config="<path>/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.
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:
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:
- 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.
- 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.
- 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>
- 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).
- 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.
- 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 byrole.\<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.
[...]
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:
type.objectGUID = GUID
type.objectSID = SID
When using the XML configuration format:
<attributeType name="objectGUID" type="GUID"/>
<attributeType name="objectSID" type="SID"/>
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:
Appway {
com.nm.auth.jaas.NmLoginModule required
debug="true"
url="http://localhost/weblistener/anonymous/listener/LoginService"
secret="abcdef";
};
LDAP Directory as authentication system:
Appway {
com.nm.auth.jaas.LdapLoginModule required
debug="true"
config="<path>/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>).
<Realm
className="org.apache.catalina.realm.JAASRealm"
debug="1"
appName="Appway"
userClassNames="com.nm.auth.jaas.NmUserPrincipal"
roleClassNames="com.nm.auth.jaas.NmRolePrincipal"
/>
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:
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:
<web-app>
[...]
<filter>
<filter-name>UserFilter</filter-name>
<filter-class>com.nm.filter.UserFilter</filter-class>
</filter>
[...]
<filter-mapping>
<filter-name>UserFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
[...]
<security-constraint>
<web-resource-collection>
<web-resource-name>Front End</web-resource-name>
<url-pattern>/stages/*</url-pattern>
<url-pattern>/views/*</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>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>
<login-config>
<!--
<auth-method>BASIC</auth-method>
<realm-name>Appway</realm-name>
-->
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login</form-login-page>
<form-error-page>/login</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description>Users</description>
<role-name>User</role-name>
</security-role>
<security-role>
<description>Administrators</description>
<role-name>Administrator</role-name>
</security-role>
</web-app>
Configuration file 'ldap.properties'
Active Directory example
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
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 totrue
. See Synchronization for more information.
<ldap>
<directory name="foo">
...
</directory>
<directory name="bar" recursive="false">
...
</directory>
</ldap>
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:
<directory name="foo">
<schema type="ActiveDirectory" />
...
</directory>
For Microsoft ActiveDirectory, the following schema definition can be used:
<schema type="ActiveDirectory" />
For Novell eDirectory, the following schema definition can be used:
<schema type="eDirectory" />
For directories of other LDAP vendors, the schema has to be defined explicitly. The attribute "type" then has to be set to "Custom".
<schema type="Custom">
<property name="attribute.uid" value="uid"/>
<property name="attribute.lastName" value="sn"/>
<property name="attribute.firstName" value="givenName"/>
<property name="attribute.groupMembership" value="memberOf"/>
<property name="attribute.member" value="uniqueMember"/>
<property name="attribute.objectClass" value="objectClass"/>
<property name="attribute.userAccountControl" value=""/>
<property name="attribute.picture" value=""/>
<property name="objectClass.user" value="person"/>
<property name="objectClass.group" value="groupOfUniqueNames"/>
</schema>
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.
<server address="10.0.1.100" port="389" ssl="false" timeout="10"/>
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.
<directory name="foo">
...
<loginPattern pattern="{USERID}@mydomain.local" context="dc=mydomain,dc=local" />
...
</directory>
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:
// LDAP login with a Windows NT Domain name
<loginPattern pattern="MYDOMAIN\{USERID}" context="dc=mydomain,dc=local" />
// LDAP login with an LDAP distinguished name
<loginPattern pattern="uid={USERID},ou=users,dc=mydomain,dc=local" context="dc=mydomain,dc=local" />
// LDAP login with web username
<loginPattern pattern="{USERID}" context="dc=mydomain,dc=local" />
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:
<directory name="foo">
...
<username>appwaysync@mydomain.local</username>
<password>something-secure-123</password>
...
</directory>
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:
<roleMapping role="User" dn="cn=AppwayUsers,ou=groups,dc=mydomain,dc=local"/>
<roleMapping role="Administrator" dn="cn=AppwayAdmins,ou=groups,dc=mydomain,dc=local"/>
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.
<groupMapping group="TeamAlpha" dn="cn=TeamAlpha,ou=teams,dc=mydomain,dc=local"/>
<groupMapping group="TeamBeta" dn="cn=TeamBeta,ou=teams,dc=mydomain,dc=local"/>
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.
<preferenceMapping preference="ldap.dn" attribute="distinguishedName"/>
<preferenceMapping preference="ldap.name" attribute="displayName"/>
<preferenceMapping preference="ldap.initials" attribute="initials"/>
<preferenceMapping preference="ldap.email" attribute="mail"/>
Every preference mapping must specify the name of an LDAP attribute (attribute "attribute") and the name of an Appway user preference (attribute "preferenece").
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:
<syncOptions
deleteUsers="true" disableUsers="false"
updateGroups="true" updateRoles="true"
updateLocalUsers="false" deleteLocalUsers="false" disableLocalUsers="false"
updatePictures="false"
/>
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
<ldap>
<directory name="mydomain.local">
<schema type="ActiveDirectory"/>
<server address="172.16.0.153" port="389" ssl="false" />
<server address="10.0.2.36" port="636" ssl="true" timeout="15"/>
<username>AppwayServiceAccount@mydomain.local</username>
<password>changeit</password>
<loginPattern pattern="{USERID}@mydomain.local"
context="dc=mydomain,dc=local" />
<roleMapping role="User"
dn="cn=AppwayUsers,ou=Groups,dc=mydomain,dc=local"/>
<roleMapping role="Administrator"
dn="cn=AppwayAdmins,ou=Groups,dc=mydomain,dc=local"/>
<groupMapping group="Management"
dn="cn=Management,ou=Groups,dc=mydomain,dc=local"/>
<preferenceMapping preference="ldap.email" attribute="mail"/>
<preferenceMapping preference="ldap.name"
attribute="displayName"/>
<preferenceMapping preference="ldap.dn"
attribute="distinguishedName"/>
</directory>
<syncOptions deleteUsers="true"
disableUsers="false"
updateLocalUsers="false"
deleteLocalUsers="false"
disableLocalUsers="false"
updateGroups="true"
updateRoles="true"
updatePictures="false"
/>
</ldap>
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:
sync.user = ENC(wzckqF5LE_XpalyHNiwoQkGu3WMl8rNlJLUPWFMzWXY)
sync.password = ENC(emI-BkYplIvi7nSafx_P8vVAxXT2zxIPNBCjvvPnthw)
Example configuration in ldap.xml:
<directory ...>
<username>ENC(wzckqF5LE_XpalyHNiwoQkGu3WMl8rNlJLUPWFMzWXY)</username>
<password>ENC(emI-BkYplIvi7nSafx_P8vVAxXT2zxIPNBCjvvPnthw)</password>
</directory>