Introduction

This package supports using Shibboleth/SAML federated authentication for user
authentication to Foswiki, along with also being provided attributes thru SAML from
which to construct the user's wiki name and to provide group memberships for that user
that are either sent by their Identity Provider (IdP) or an additional attribute provider configured
into your Shibboleth Service Provider (SP). But you can also combine groups from Shib
with group memberships provided by a local LDAP server (i.e. what LdapContrib allows).
Thus, you can use both Shib-delivered attributes and LDAP group memberships for
access control.

ShibLdapContrib is a derivative of LdapContrib, with most of the LdapContrib code
and functionality retained (with exceptions noted below), and to use it,
you need the following bundle of related modules:

Requires Shibboleth Service Provider or similar SAML/SSO software on same server

The use of this module assumes that you have already installed and
appropriately configured a Shibboleth Service Provider (SP) (or similar
functioning software) on the same Foswiki server on which this (set of) modules
is being used. While this module can likely work with any authentication provider
that ends up populating environment variables that contain the values for this
module to process, it has only explicitly been tested with a Shibboleth SP.
That SP needs to be active for any Foswiki URL paths for which you want
authentication and authorization to be provided by this module.
And that SP needs to be configured to appropriately populate the various
environment variable names that you subsequently choose to configure this module to
look for and use for the:

user's login name

user's wiki name (can specify multiple attributes to be combined into wiki name)

user's email address

user's group memberships

Supports underlying LdapContrib functionality, in particular using LDAP groups, as well as Shib-delivered groups

Note that the group membership capabilities and group name manipulation mirror similar
options that LdapContrib provides (this set of modules is a derivative of LdapContrib,
and retains almost all the code and configuration options that LdapContrib provides).
You can choose to use Shib/SAML delivered group names or not, you can choose to normalize
those names (standard wikiname normalization logic) or not, and you can choose to specify
a set of regular expressions to reformat the group names provided. And you can choose if
a Shib-delivered group name for a given person is allowed to match with (and thus make
that person a member of) a local LDAP server group object that your Foswiki service is
using.

Note the latter -- this module continues to support the full LDAP capabilities of LdapContrib,
including building and maintaining a cache of group names from LDAP. Note two things, though:

you probably want to use group objects that support a "non-DN based group membership attribute", because there really is no need/advantage to creating person objects in your LDAP for users whose authentication and accompanying attributes are being provided through Shibboleth. A standard attribute that has been defined for groupOfNames objects that allows flexible user identifiers is the 'hasMember' attribute. This module expects to match the resultant user login name (after whatever manipulation you configure for such) to the value of whatever LDAP group object attribute that you configure (such as 'hasMember').

you probably want to leave the LDAP userBase config option as an empty list, because there likely won't be any value to reading in a set of person objects from LDAP.

the user information provided through Shibboleth is NOT written into the disk cache that holds the cached LDAP information. First, that could mean constant writes to that cache, and a much increased possibility of "race conditions" on such. But also, there is no local source of "backing information" on these Shib users (or at least there is no requirement for such), so as soon as you refreshed the cache, you'd "lose" the cached information on the Shib users anyways. So the Shib information just goes into a "memory cache", and all the methods in ShibLdapContrib that respond to queries about group memberships, wikinames, etc. have been modified to respond based on both the "tied disk cache" of LDAP data and the "in-memory cache" of Shib-provided data.

(Note that, while it has not been actually tested, you probably could, if you really wanted to, continue to have a local LDAP entry for every person, and thus an assigned DN, and then still use DN-valued 'member's within a LDAP group object. That local person record would just need to carry an attribute that matches up with user's login name, so you can have the LDAP processing use its "indirect" feature to turn the group membership DNs into a "user identifier" that will match up with the user's login name.)

The underlying LdapContrib provides "LDAP support", and downloads all relevant records from your
LDAP server into a local cache the first time you use it. This can take a noticeable period of time
depending on the size of your LDAP database. (Note that below we highlight that, when you are relying
on Shibboleth/SAMl to deliver identities to your Foswiki, you are unlikely to have any need for local
person objects in your LDAP server to be used here with Foswiki. So you are likely to only need to
read in and cache "group objects", and thus the time to build/rebuild the cache is lessened, and the
size of the resultant cache is likely noticeably smaller.)

This cache will be refreshed on a configurable interval (defaults to once a day).
You can also disable automatic refreshing and refresh the ShibLdapContrib's cache manually using
the "Refresh Cache" button below. Read the documentation of MaxCacheAge in the section
"Performance Settings" in configure.

Refresh Cache Now button

Shibboleth questionnaire

First, in order to use this extension, you need to have a Shibboleth SP (or similar SAML SP
or some other WebSSO service) installed and configured to make the user's login name and
potentially other attributes about the user available as Environment variables that this
extension can then access to get that information. So those environment variables need to be
available to all Foswiki paths for which access control is to applied. With the Shib SP, that
likely means you want to require a Shib session for all paths on your web that don't contain
fully anonymous access. See the Shibboleth wiki ( https://wiki.shibboleth.net )
for information on Shibboleth installation and configuration.

Given that, you'll need to be able to answer the following questions about exactly what
environment variables contain what, and which functions of this extension should be active.

Which environment variable will contain the user's login name? Note that the Shib SP has logic for populating REMOTE_USER from a sequential list of attributes, using whichever in that sequence first has a value. So REMOTE_USER is the default, and most likely, choice for most. And that usually comes down to the eduPersonPrincipalName.

Do you need to do any manipulation of the login name before using it with your web? You can choose to normalize it (wikiname syntax rules) or choose to make it case sensitive if you want.

What environment variable(s) will contain the values from which to construct the user's wikiname? Again, there are a number of config options that allow for manipulation of those values to ultimately result in the wikiname to be used.

What environment variable (if any) will contain "group memberships" for this user? Again, assuming some group memberships for this user are provided thru Shib, there are a variety of options for manipulating those group names.

Will you also want to use groups maintained in a local LDAP server? If so, the following LDAP questionnaire and configuration will be also be important.

LDAP questionnaire

Before you can further configure the LDAP connection you will have to answer
a set of basic questions about your LDAP server. These are:

What's the host name (or IP address) of the LDAP server (e.g. ldap.my.domain.com)?

What port does it listen to LDAP requests (e.g. 389)?

Does your LDAP Server use SASL to authenticate connections? If so which authentication mechanism does it use (EXTERNAL, DIGEST-MD5, ...)?

Do you have a kind of "proxy" user that the wiki can use to perform the initial connection? You need its DN and credentials. Advice: don't use the LDAP admin account, you only need a simple user that has read access to all of the directory (or the relevant parts); it does not need any write access.

What is the "base dn" of the directory (e.g. dc=my,dc=domain,dc=com )?

What is the common root/branch for all users? For example, Are they all found under ou=people,dc=my,dc=domain,dc=com or are they are scattered all over the place? (NOTE: it is generally assumed you will NOT need to read in user objects from LDAP, so even if they exist, you very well might want to keep this "empty" [] .)

What is the common root/branch where all groups are defined (e.g. ou=group,dc=my,dc=domain,dc=com)?

Which attribute of a user record should be used to log in (must be unique)?

Which attribute(s) of a user record do you want to use to construct a WikiName (used to display them online, pointing to their homepage)?

What's the name attribute of a group?

Which attribute in a group record defines its members (e.g. member or memberUid)? Note, that if the member attribute of a group is a DN you need to enable "member indirection" (see #Membership). (NOTE: it is likely much easier to work with groups that have a membership attribute, like 'hasMember', that can be an arbitrary identifier.)

Collect the answers to these questions either yourself using your favorite LDAP
browser, or ask your friendly LDAP admin.

Authentication

To authenticate wiki users using your LDAP server
you have to register the ShibLdapApacheLogin class as the so called
LoginManager. You'll set the PasswordManager to be "none".
This is done by adding the following lines in the
lib/LocalSite.cfg configuration file (or by using the configure tool alternatively):

(Note that subsequently logging in as the Foswiki Admin will still override the
Shib-provided authentication/user name, just as it does with other Foswiki
authentication/authorization choices.)

User Groups

User groups can be configured to come from:

Shibboleth (passed in to the SP and made available as an environment variable) and/or

LDAP groups

This group functionality, which can be leveraged in Foswiki access control lists, requires registering
the UserMappingManager implementation to be "ShibLdapUserMapping". This is done by adding the following
to your lib/LocalSite.cfg configuration file (or by using the configure tool alternatively):

In addition you can decide if you want to add the LDAP groups or use
LDAP groups solely. This is controlled by the ShibMapGroups and MapGroups flags. If
using both, you can also decide if Shib-provided groups are allowed to clash names with
LDAP provided groups or not using the flag ShibMergeWithLdapGroups.

Normalization of login, wiki and group names

See this same topic below. The same options (in the case of login and wikinames,
the exact same "named" options) for normalization of login, wiki and group names,
and rewriting them, are available (or also apply to) The Shib-provided such values.
These options are documented in the Configuration options that will show up in
bin/configure's "ShibLdap" section/"tab" under Extensions. (The same place you'd find
the LdapContrib options if using that.)

One key thing to note, however, about normalization of the Shib-provided login name. Given
the nature of federated authentication and getting users from multiple domains, the "@domain.edu"
string at the end of a scoped login name is NOT removed as part of normalization for the
login name.

Underlying LdapContrib documentation

The rest of this documentation is pretty much verbatim from the ShibLdapContrib
documentation, and most of it still applies, because ShibLdapContrib is a
derivative of LdapContrib and left in almost all of its functionality "untouched".
With the following provisos:

See the Introduction above for a discussion about the kind of group objects and its membership attribute you probably want to use

See the Introduction above for a discussion about the likelihood of not needing to maintain/read in user objects

See the Introduction above for a discussion about DN-based groups, and reading user records, and resolving group "indirection", maybe still working if needed, and that functionality is still in here, but has not been tested.

The configuration for WikiGroupsBackoff is theoretically still here also, but again, that has not been tested.

User Groups information specific to the underlying LDAP functionality

Assuming you continue to use a local LDAP to maintain access control groups
for your Foswiki, you'll still need to read those in, maintain a cache of
them, and reference them when users access your protected content. So all the
following config for LdapContrib is still available here, noting the just
mentioned above provisos.

In addition you can decide if you want to add the LDAP groups or use
LDAP groups solely. This is controlled by the WikiGroupsBackoff flag. If
switched on then LDAP groups will be added. If there's a name clash LDAP groups
take precedence. If switched off WikiGroups are ignored.

You might decide in not using your LDAP groups but still map login names
to WikiNames. Both, LDAP user groups and name mapping is done by the
UserMappingManager. So to make use of name mapping but not its group
feature,
register the
LdapUserMapping implementation for the UserMappingManager but
disable the MapGroups setting.

When multiple groups in your LDAP directory clash on the same group name
you might actually wish to merge these groups as used online in your wiki.
This is done using the MergeGroups flag. When disabled, clashing groups
are reported as a warning in the server log files when the LDAP cache is
refreshed.

Membership

LDAP servers follow different schemata to define "membership". They store the
information either using a set of unique ids in
the group object (posixGroup) or the full DNs of the user objects
(groupOfNames). In the latter case the user objects' unique ids have to be
fetched separately based on their distinguished name. This mode has to be switched on
using the MemberIndirection setting.

The reverse relation, where the user objects hold membership information
(for example using a memberOf attribute) is
maintained by some LDAP servers automatically. Those that encode membership this
way only are not supported by the ShibLdapContrib yet.

Furthermore, user objects may have one primary group attribute.
This is a simple value that stores the id of a default group
that user is member of. This attribute is defined by specifying the PrimaryGroupAttribute
setting a.

ShibLdapContrib reads membership information as they are stored
in the group objects, and may map the member object indirectly to the
login name. In addition any "primary group" setting stored in the user objects
is consulted as well.

Normalization of login, wiki and group names

ShibLdapContrib reads three kinds of names from your LDAP server and reuses this information
as needed. These are the login names - used to log in -,
the WikiNames - used to display users online -, and the group names - used in
access control lists.

The WikiName can be generated by
setting the parameters

WikiNameAttributes: a comma separated list of LDAP attributes that are then assembled to form a proper WikiName

NormalizeWikiName: boolean flag; if set a couple of extra operations are performed to generate a proper WikiName, i.e. removing illegal characters.

WikiNameAliases: a comma separated key=value list of WikiNames to be mapped to another WikiName (DEPCRETATED: use RewriteWikiNames instead).

The givenName and sn (surname) LDAP attributes will be fetched and concatenated
to form a proper WikiName, so that "givenName=Hans-Peter,sn=Schwarze" will
result in the WikiName "HansPeterSchwarze".

The login name can be normalized by enabling the

$Foswiki::cfg{ShibLdap}{NormalizeLoginNames} = 1;

setting. This will also strip off any '@...' string from the login as found
when logging using the mail attribute or when using ShibLdapContrib in combination
with a kerberos single sign on strategy.

In most scenarios users prefer not to care about case sensitivity of their login names
for convenience. If however your authentication requires an exact match of the login name
including case sensitivity, the use

$Foswiki::cfg{ShibLdap}{CaseSensitiveLogin} = 1;

to switch that on.

Similar to the WikiName of a user, group names can be normalized using

$Foswiki::cfg{ShibLdap}{NormalizeGroupNames} = 1;

If a user in your LDAP directory changed his name, e.g. because of a marriage,
this use can be mapped to his/her old account using an alias that points back
from the old WikiName to the new one. This is done using a setting like this:

The parameter takes a comma separated list of FromWikiName=ToWikiName. Whenever
this account is still used in an access control list, its rights will be
inherited by the targeted ToWikiName account.

Group names can be rewritten using a set of rewrite rules. This is useful when the
names as stored in your LDAP directory don't satisfy your criteria for being displayed
online. In conjunction with the MergeGroups flag, separate LDAP groups can be
merged onto one group as it is used online in your wiki.

Each rule consists of a pattern that will be substituted in the group name as specified.
The substitute can contain variables $1, $2, ... , $5 to insert the first, second, ..., fifth
bracket pair in the key pattern. (see perl manual for regular expressions).

Example:

$Foswiki::cfg{ShibLdap}{RewriteGroups} = {
'(.*)_users' => '$1'
};

WikiNames can be processed similarly using the $Foswiki::cfg{ShibLdap}{RewriteWikiNames}
parameter. Given the WikiName is derived from the mail attribute, then use the following
rule to strip off domain parts from the wiki name:

$Foswiki::cfg{ShibLdap}{RewriteWikiNames} = {
'^(.*)@.*$' => '$1'
};

This can be further refined to prevent name clashes by adding back the domain part:

So given your company uses email addresses like john.doe@germany.mycompany.com
and john.doe@spain.mycompany.com it will generate the wiki names JohnDoeGermany
and JohnDoeSpain from it (given NormalizeWikiNames is switched on too).

Another trick is to add additional LDAP attributes to the WikiNameAttributes that
help to create unique WikiNames, and then strip off unwanted parts again
with an appropriate rewrite rule.

generate a temporary WikiName concatenating the attributes according to the WikiNameAttributes setting, e.g. "John-Doe Smith jds", where jds is the sAMAccountName value

let's say there's also a second record for John-Doe Smith that he uses to log in

with admin rights using his jds-adm login.

rule 1 of the RewriteWikiNames will match the jds-adm and will generate a nice John-Doe Smith Admin, whereas

rule 2 will only match those records that don't have the -adm suffic at their sAMAccountName.

note that both rules only copy over the first part of the string captured in brackets (.*) over to the result leaving out the trailing sAMAccountName part.

finally the string is wikified to make it a proper CamelCase word by all non-alphabetic characters between the parts of the name

WikiName clashes

Depending on the choice of WikiNameAttributes and RewriteWikiNames rules your LDAP records will be mapped
onto a proper WikiName. These have to be unique to represent the identity of the person granted access to Foswiki.
However, while you LDAP records are unique
due to their Distinguished Names, it is quite common that two independent records result in the
same WikiName. That's a so called name clash. You are strongly encouraged to control the way
WikiNames are generated to keep the number of name clashes as low as possible. Use appropriate
rewrite rues as described above.

In real world you will most probalby run into a name clash that you can't possibly resolve. In that case
ShibLdapContrib will enumerate all JohnSmiths as they are found, calling them JohnSmith, JohnSmith1, JohnSmith2, etc.
Each of these maps back to a unique Distinguished Name in your LDAP directory of course.

ShibLdapContrib tries to keep the choice which of the JohnSmiths maps to which DN stable over time. Whenever
you refresh the LDAP cache the previous WikiNames will be reused while new LDAP records will get a
higher number attached to the WikiName.

When ShibLdapContrib is building up its cache for the first time, the actual mapping is pretty arbitrary, given
there are no additional means to distinguish the names. From there on WikiNames are kept,
even when you reconfigure ShibLdapContrib itself. This is the default behavior not to risk mapping a different
identity to a WikiName.

You still might decide to nuke the decisions once made while resolving name clashes by refreshing the ldap
cache using the refreshldap=force url parameter (compared to refreshldap=on to up the cache regularly).

Note doing this later in the life time of your wiki might accidentally swap the mapping of LDAP records
to WikiNames in case they clash. So be very cautious when doing that.

Configuration

The ShibLdapContrib package is configured using a set of variables that need
to be added to the lib/LocalSite.cfg configuration file.
Use the configure tool (at least
once) after you installed this package. Have a look at your lib/LocalSite.cfg
file afterwards. You might also make your changes therein directly to
accommodate your installation to your specific LDAP installation and user
accounting. See the documentation within the configure tool for an explanation
of the various options.

Updating the LDAP cache using a cronjob

In some environments, updating the internal LDAP cache of the ShibLdapContrib might
take considerable time. The intervals the cache data is thought to be "expired" is
configured using the MaxCacheAge setting. This setting defaults to updating the
cache every 24 hours. The refresh procedure will then be triggered by the first request
that hits the site when this period expired.

To remove this burden from the "first visitor in the morning", the automatic refresh procedure can
be disabled by setting

$Foswiki::cfg{ShibLdap}{MaxCacheAge} = 0;

This means that the age of the cached data will not be checked automatically anymore. The
responsibility that the data is updated is now up to you, that is you have to update the
cache explicitly. This can be done by either hitting the red "Refresh Cache" button above,
or by setting up an appropriate cronjob on the machine running your wiki server.

To trigger an explicit update of the cache on 5 past midnight every day use a
cronjob similar to:

This will call the engine on the command line and provide the necessary query parameters so
that the ShibLdapContrib will force an update of the cache data.

Debugging this Extension, Shib, and LDAP

There are a number of "print statements" in the components of this extension that
will be activated if you turn the {ShibLdap}{Debug} option "on". Those are all set
to write into the "../working/logs/debug.log" file. The lines written into that log
should give you a pretty good picture of what information is being picked up by this
Extension, and what is happening with it. Both in terms of the Shibboleth connectivity
(environment variables being found, their values, etc.), and in terms of the LDAP caching
of groups etc. And, if you need even more extensive debugging,
there are a number of "writeDebug" statements that are commented out, and you could change
the actual code to remove the '#' in front that makes those a comment to activate even
more information being written into the debug.log.

So, in conclusion, if you are having problems with the functionality of this extension,
the first best thing to do is to enable {ShibLdap}{Debug} in configure
and analyze the output as generated in the debug.log file of your Foswiki (likely in the ../working/logs directory
in the directory on your server where you've installed Foswiki).

$Foswiki::cfg{ShibLdap}{Debug} = 1;

Note that that {ShibLdap}{Debug} will only switch on debug notes of
ShibLdapContrib, not of your web server performing ldap requests on its own
depending on your setup.