Trusted authentication framework

Last modified by Thomas Mortagne on 2024/02/12 00:05

cogA generic XWiki authentication service based on pluggable adapters to provide trusted authentication from external sources
TypeJAR
Category
Developed by

Denis Gervalle

Active Installs20
Rating
0 Votes
LicenseGNU Lesser General Public License 2.1

Installable with the Extension Manager

Description

A generic XWiki authentication service based on pluggable adapters to provide trusted authentication from external sources.

This extension bridges the old XWikiAuthService with the new component architecture of XWiki. It aims to ease the development of trusted authenticators by using configurable adapter components, that bridge the effective trusted authentication with a generic authenticator. Out of the box, you get user creation, configurable user properties synchronization and group membership synchronization.

Some default adapters will be provided over time, actually starting with a reimplementation of the headers authenticator.

Trusted authenticator API

The general behavior of the trusted authentication is:

  • If persistent store is trusted and not null, return the already authenticated user
  • getUserId() from the adapter:
    • if user is null,
      • if persistent store is trusted on missing authentication and not null, return the already authenticated user
      • else clear the persistent store and return with public access
    • else compute the user profile reference from getUserName(), replacing some characters based on the xwiki.authentication.trusted.userProfileReplacements configuration and applying character case changes based on xwiki.authentication.trusted.userProfileCase
    • if user is found in persistence store, return that authenticated user
    • else, check user for existance:
      • if the user exists, synchronize user properties and group membership
      • else create user and synchronize group membership
      • stores the authenticated user to persistence store and returns it

Currently, it is mandatory that getUserId() and getUserName() returns the exact same value. In a future version it is expected that only getUserId() be unique, and getUserName() a more meaningful value that allow duplicates.

General configuration

xwiki.cfg file

#-# Replace the default XWikiAuthService authentication
xwiki.authentication.authclass=org.xwiki.contrib.authentication.XWikiTrustedAuthenticator

#-# Define the hint of the TrustedAuthenticationAdapter that should be used for providing the effective
#-# trusted authentication. This parameter is mandatory.
#-# Here is an example for the HeadersTrustedAuthenticationAdapter:
xwiki.authentication.trusted.adapterHint=headers

#-# Define the hint of the AuthenticationPersistenceStore that will be used to persist authentication between
#-# requests. The default is to use the SessionAuthenticationPersistenceStore, which will store authentication
#-# information into the Servlet container session.
#-# Another option is to use the CookieAuthenticationPersistenceStore (hint: cookie), that will store the
#-# information into an encrypted cookie. The cookie prefix, domain, path and encryption is customizable using the
#-# same configuration as the standard authentication services (xwiki.authentication.cookieprefix,
#-# xwiki.authentication.cookiepath, xwiki.authentication.cookiedomains and xwiki.authentication.encryptionKey)
# xwiki.authentication.trusted.persistenceStoreHint=session

#-# By default, the persistence store is not trusted and only used to optimize the synchronization process.
#-# If the authentication process is time-consuming, you can improve performance by trusting the authentication
#-# provided by the persistence store and avoid requesting the external authentication with every request.
#-# To do this, uncomment the following line:
# xwiki.authentication.trusted.isPersistenceStoreTrusted=true

#-# If the authentication process is not time-consuming, but authentication is not provided with every request,
#-# you can also keep the above setting commented and trust the authentication provided by the persistence store
#-# only when a request is made without authentication, allowing some persistence but still
#-# giving the priority to the external authentication when provided. This allow a smoother experience especially
#-# when user switching occurs in the same browser.
#-# To trust the persistance store when external authentication is missing, uncomment the following line:
# xwiki.authentication.trusted.isPersistenceStoreTrustedOnMissingAuthentication=true

#-# Set the cookie Time To Live in seconds to keep persistence between browser restart.
#-# The default is to use a session cookie. This setting is only used with the Cookie persistence store.
#-# Here is an example using a 1 day TTL, which means the persistence is kept for 1 day after last response.
#-# When combined with the parameter above, this can also keep the authentication for a longer period than
#-# the one of the external authenticator. Make sure you understand the security trade-off.
# xwiki.authentication.trusted.persistenceStoreTTL=84600

#-# By default, when the authentication fails, we fallback to the next authentication module (the default XWiki one, or a custom one)
#-# To prevent this fallback, and to return public access instead, uncomment:
# xwiki.authentication.trusted.isAuthoritative=true

#-# Define the class name of the XWikiAuthService implementation to fallback to.
#-# By default, the default XWikiAuthService implementation is used.
#-# Don't uncomment this setting if you don't customize it since doing so would have a negative performance impact.
#-# Only applicable if the previous parameter is false.
# xwiki.authentication.trusted.fallbackAuthenticator=com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl

#-# Define the letter case transformation to apply on usernames provided by the adapter
#-# to create the name of the user profile page. This letter case transformation is done first, before the
#-# replacements defined in the next parameter. The default is to lowercase the username.
#-# Possible transformation are: lowercase (default), uppercase, titlecase, none
# xwiki.authentication.trusted.userProfileCase=none

#-# Define characters or substring replacements to be applied on the username provided by the adapter after
#-# the above case transformation, to create the name of the user profile page. Replacement are of the form
#-# find=replace and separated by pipes. The default is to not make any replacement
#-# Before the introduction of this parameter, the default was different, you can reactivate it by uncommenting:
# xwiki.authentication.trusted.userProfileReplacements=.==|@=_

#-# Mapping between XWiki group name and external authentication role name.
#-# Mapping are separated with the pipe character, and the same XWiki group can be mapped multiple times to
#-# different external roles.
# xwiki.authentication.trusted.groupsMapping=XWiki.XWikiGroupA=groupA|XWiki.XWikiGroupB=groupB|XWiki.XWikiGroupA=groupAbis

#-# Mapping between XWiki users property name and external user property names.
# xwiki.authentication.trusted.propertiesMapping=email=mail|first_name=givenname|last_name=sn


#-# Dynamic role and group configurations.
#-#
#-# For some situations, the groupsMapping parameter is not sufficient, or cumbersome to use.
#-# Exact roles or groups might not be known in advance, or are to numerous, but they follow
#-# a regular pattern that we can take advantage of.
#-#
#-# roles and groups may have prefixes or suffixes (or both) that can be matched with each other,
#-# or more generally, they can be recognized using a regular expression.
#-#
#-# To do this, you will need to define a "dynamic role" configuration for each
#-# set of roles - set of groups mapping.
#-# These configurations are named, and you need to list these names in the following parameter,
#-# using "|" as a separator:
#-#
# xwiki.authentication.trusted.dynamicRole.configurations=employer|employeetype
#-#
#-# Then, you define each configuration. Here's an example which correspond to the above:
#-#
# xwiki.authentication.trusted.dynamicRole.configuration.employeetype.rolePrefix=employeetype_
# xwiki.authentication.trusted.dynamicRole.configuration.employeetype.groupPrefix=xwiki:XWiki.EmployeeType_
# xwiki.authentication.trusted.dynamicRole.configuration.employeetype.autocreate=false
# xwiki.authentication.trusted.dynamicRole.configuration.employer.rolePrefix=employer_
# xwiki.authentication.trusted.dynamicRole.configuration.employer.groupPrefix=xwiki:XWiki.Employer_
#-#
#-# More generally, here are the different supported configuration options:
#-#
#-# To be recognized by this configuration, the role must start with the following string:
#-# xwiki.authentication.trusted.dynamicRole.configuration.name.rolePrefix=employeetype_
#-#
#-# To be recognized by this configuration, the role must end with the following string:
#-# xwiki.authentication.trusted.dynamicRole.configuration.name.roleSuffix=_regular
#-#
#-# To be recognized by this configuration, the role must match the following regex:
#-# xwiki.authentication.trusted.dynamicRole.configuration.name.roleRegex=employeeType_(.*)
#-#
#-# Groups related to this configuration start with this string:
#-# xwiki.authentication.trusted.dynamicRole.configuration.employer.groupPrefix=xwiki:XWiki.Employer_
#-#
#-# Groups related to this configuration end with this string:
#-# xwiki.authentication.trusted.dynamicRole.configuration.employer.groupSuffix=_Regular
#-#
#-# Groups related to this configuration will be auto-created as needed (true is the default)
#-# xwiki.authentication.trusted.dynamicRole.configuration.employer.autocreate=true
#-#
#-# By default, to find out the group corresponding to a given role, rolePrefix and roleSuffix are
#-# replaced by groupPrefix and groupSuffix. If you defined a regex to match roles, you can override
#-# this behavior by defining by defining a replacement as follows. Make sure that the replacement
#-# still honors the defined group prefix and suffix!
#-# xwiki.authentication.trusted.dynamicRole.configuration.employer.replacement=xwiki:XWiki.EmployeeType_$1
#-#
#-# You can define both a role prefix and a role suffix and a regex, but they are all optional.
#-# Note: if you define a roleRegex *and* a prefix / a suffix, the role will need to match and
#-# the regex, and the suffix / prefix.
#-# You can define both a group prefix and a group suffix, but at least one should be specified,
#-# even if you have a role regex and a replacement because that's what will be used to find out
#-# which groups are related to this configuration. This requirement might be relaxed in the future
#-# if we ever introduce a groupRegex parameter to match groups with regexes. We haven't yet because
#-# this would prevent implementing the group lookup with a LIKE HQL operator, even if the current
#-# implement does not currently use this.
#-#
#-# As with the groupsMapping parameter, users will be automatically added to the relevant groups.
#-# Unlike with the groupsMapping parameter, groups will be automatically created if they don't exist,
#-# unless you explicitly disable this behavior with autocreate=false. And as with the groupsMapping
#-# parameter, the users will be automatically removed from groups.
#-# Empty groups won't be automatically deleted. We could provide an autodelete parameter for this in
#-# the future. If we ever do this, we will need to consider that the group history is useful to debug
#-# and that auto deleting groups could get in the way.
#-#
#-# Add new groups to field feature
#-#
#-# When automatically creating groups with the dynamic roles feature, it is sometimes desirable to keep
#-# tabs on them and add these groups to some fields.
#-#
#-# For instance, for `XWiki.Prj_` groups dynamically created fromĀ  project_ roles, we may want to add them to the ldap_group_mapping field in XWiki Preferences like this:
#-#
#-# XWiki.Prj_1=cn=project_1,ou=users,dc=xwiki,dc=com|XWiki.Prj_2=cn=project_2,ou=users,dc=xwiki,dc=com|XWiki.Prj_3=cn=project_3,ou=users,dc=xwiki,dc=com|XWiki.EmployeeType_other=cn=employeetype_other,ou=users,dc=xwiki,dc=com|XWiki.EmployeeType_other=cn=employeetype_XXX,ou=users,dc=xwiki,dc=com|XWiki.EmployeeType_XXX=cn=employeetype_XXX,ou=users,dc=xwiki,dc=com{}
#-#
#-# Given a configuration like the above, it could be achieved with a configuration like this:
#-#
## The page where to find the field in which to add the newly created group. This parameter is mandatory.
# xwiki.authentication.trusted.dynamicRole..addGroupToField.page=XWiki.XWikiPreferences
#-#
## The name of the field to update. This parameter is mandatory
# xwiki.authentication.trusted.dynamicRole..addGroupToField.propertyName=ldap_group_mapping
#-#
## The format of the value to add. This value is optional.
# xwiki.authentication.trusted.dynamicRole..addGroupToField.value={group.fullName}=cn={role},ou=users,dc=xwiki,dc=com
#
## {group.fullName}}} is replaced with the full group name (e.g. XWiki.Project_1) without the wiki part, {group.name} is replaced with the base name (e.g. Project_1), {group} is replaced with the full reference including the wiki name (e.g. xwiki:XWiki.Project_1), {role} is replaced with the role. The backslash is an escape character which can be escaped with itself.
## By default, {{{group.fullName}={role}}} is used.
#-#
#-# These additional parameters can be specified.
#-#
## The class name of the object containing the field to update. By default, the first object having the specified field will be used.
# xwiki.authentication.trusted.dynamicRole..addGroupToField.className=XWiki.XWikiPreferences
#-#
## If the previous parameter is specified, the number of the object containing the field to update.
## By default, the first object with the given class name will be used.
# xwiki.authentication.trusted.dynamicRole..addGroupToField.objectNumber=0
#-#
## The separator used to separate values in the field. By default, a pipe (|)
# xwiki.authentication.trusted.dynamicRole..addGroupToField.separator=|
#-#
## The regex used to match values in the field.
## If a capturing group named "group" is used, the matched part will be compared to / matched with the group being added. If a capturing group named "role" is used, the role will be matched. By default, ^(?<group>[^=]+)=[\s\S]* is used. This means that values beginning with the name of the group being created, immediately followed by an equal sign, will be matched. If no capturing group named "group" nor "role" is used, the extension won't complain but this is likely incorrect.
# xwiki.authentication.trusted.dynamicRole..addGroupToField.valueRegex=^(?<group>[^=])=.
#-#
#-# Parameters xwiki.authentication.trusted.dynamicRole..addGroupToField define a global configuration.
#-# An addGroupToField configuration specific to a given dynamic role configuration can be used like this:
#-#
# xwiki.authentication.trusted.dynamicRole.configuration.project.addGroupToField.page=...
# xwiki.authentication.trusted.dynamicRole.configuration.project.addGroupToField.propertyName=...
#-#
## and so on. They will override the parameters in the global configuration. By default, the global configuration
## will be used for any field that is not specifically defined.
#-#

For safety reasons, an incorrect configuration will make the authentication reject the authentication.

XWikiPreferences

While not recommended, it's also possible to put any of these configurations in the XWiki.XWikiPreferences object in the XWiki.XWikiPreferences page of the main wiki. Add a string field with the proper name to the class and put the value you want.

The fields names are not exactly the same, you have to change xwiki.authentication.trusted. prefix to trustedauth_:

xwiki.authentication.trusted.adapterHint -> trustedauth_adapterHint
...

For performance reasons, most parameters are cached at startup, so changing those parameters in the preferences is not sufficient, you also need to restart XWiki for them to be taken into account.

Troubleshoot

Debug log

<!-- Authentication debugging -->
<logger name="org.xwiki.contrib.authentication" level="trace"/>

See Logging in the Admnistration Guide for general information about logging in XWiki.

Prerequisites & Installation Instructions

We recommend using the Extension Manager to install this extension (Make sure that the text "Installable with the Extension Manager" is displayed at the top right location on this page to know if this extension can be installed with the Extension Manager).

You can also use the manual method which involves dropping the JAR file and all its dependencies into the WEB-INF/lib folder and restarting XWiki.

  • copy this xwiki-authenticator-trusted-api jar file into WEB_INF/lib/ (or install with EM for XWiki >6.1)
  • provide an authentication adapter component (or install one from another module in this repository)
  • setup xwiki.cfg

Release Notes

v1.8.3

The following translations have been updated with this release:

v1.8.2

v1.8.1

v1.8.0

v1.7.2

v1.7.1

v1.7.0

v1.6.2

v1.6.1

v1.6.0

v1.5.1

The following translations have been updated with this release:

v1.5.0

v1.4.0

v1.3.2

v1.3

No changes in the frameworks.

Fixes applied to headers adapters:

v1.2

Fixes applied to headers adapters:

v1.1

Fixes applied to adapters (if any):

v1.0.2

Fixes applied to adapters (if any):

Dependencies

Dependencies for this extension (org.xwiki.contrib.authentication:xwiki-authenticator-trusted-api 1.8.3):

  • org.xwiki.platform:xwiki-platform-oldcore 13.10
  • org.xwiki.contrib:authservice-backport-api 1.1.1

Get Connected