
Apache module mod_lookup_identity
=================================

Apache module to lookup user identifier and retrieve additional
information about the authenticated user.

The module supports lookup of the user identifier based on
certificate via SSSD D-Bus call, setting up the r->user request
structure.
Method org.freedesktop.sssd.infopipe.Users.FindByNameAndCertificate
is used by default and value of query string parameter configured
with directive LookupUserByCertificateParamName is passed to SSSD
together with certificate to allow mapping of single certificate to
multiple user accounts.
Setting NO_CERTIFICATE_MAPPING_SUPPORT at build time changes the
module so it does not check the query string and calls SSSD D-Bus
method org.freedesktop.sssd.infopipe.Users.FindByCertificate.

It also allows retrieval of list of group names the user belongs to
using org.freedesktop.sssd.infopipe.GetUserGroups call and any
custom attributes configured in /etc/sssd/sssd.conf using with
org.freedesktop.sssd.infopipe.GetUserAttr call. It can also retrieve
the GECOS information using the getpwnam call. The retrieved values
get stored in notes/environment variables.

The sssd-dbus package needs to be installed and the ifp service
enabled in the [sssd] section of /etc/sssd/sssd.conf.

The module itself needs to be loaded into Apache's configuration file
like /etc/httpd/conf/httpd.conf with directive like

    LoadModule lookup_identity_module modules/mod_lookup_identity.so

User Lookup
-----------

By default, no user identifier lookup is enabled. Directive

    LookupUserByCertificate On

enables the lookup. It uses the original internal r->user value
as input, so the typical setup for example with mod_ssl will be

    SSLVerifyClient require
    SSLUserName SSL_CLIENT_CERT
    LookupUserByCertificate On

when mod_ssl puts the certificate to the username field and then
mod_lookup_identity replaces it with user identifier found with
org.freedesktop.sssd.infopipe.Users.FindByCertificate. If no user
is found based on the certificate, the r->user value is cleared.
Make sure the FakeBasicAuth is not enable in SSLOptions or the
r->user will not be set.

SSSD version 1.13 or higher is needed for LookupUserByCertificate
functionality.

Retrieving Group Membership and Attributes
------------------------------------------

For the custom attributes fetching, caching of non-POSIX attributes
needs to be enabled in the [domain/*] section of /etc/sssd/sssd.conf,
configuration ldap_user_extra_attrs, and the attributes also need to
be enabled in the [ifp] section using the user_attributes
configuration option.

Example of sssd.conf:

    [domain/example.com]
    ...
    ldap_user_extra_attrs = mail, telephoneNumber, givenname, sn

    [sssd]
    services = nss, pam, ssh, ifp

    [ifp]
    allowed_uids = apache, root
    user_attributes = +mail, +telephoneNumber, +givenname, +sn

The default behaviour can be changed with the following directives:

    LookupOutput where_to_store_results

	Specifies if the lookups will be done at all and where the results
	of the lookup will be stored. Possible values are:

	    None: Disable the lookup altogether
	    Notes: Sets the Apache notes table only
	    Env: Sets environment variables only
	    Headers: Sets HTTP request headers, for use by proxy setups.
	    Headers-Base64: Sets HTTP request headers with values
		Base64-encoded, for use by proxy setups.

	The default is Notes and Env.

    LookupUserGECOS name

	Name of the note and/or environment variable for the GECOS
	value. If prefixed with '+' sign, it is set only if the
	note/environment variable is not set yet, otherwise the
	value is overwritten.

	Setting this option requires for the user identity to be
	POSIX identity, retrievable with getpwnam.

	Example: LookupUserGECOS REMOTE_USER_FULLNAME

	Example: LookupUserGECOS +REMOTE_USER_GECOS

	Default is not set.

    LookupUserGroups name [separator]

	Name of the note and/or environment variable for the list of groups
	retrieved using the org.freedesktop.sssd.infopipe.GetUserGroups
	call, and optionally separator for multiple groups.

	If the separator is specified, it is used to concatenate
	multiple groups in single string value of the
	note/environment variable. If the separator is not specified,
	only one group is set.

	Example: if user alice is member of groups staff and student,
	option

	    LookupUserGroups REMOTE_USER_GROUPS :

	will set value of REMOTE_USER_GROUPS to staff:student (or
	student:staff, depending on the order returned by the sssd
	dbus call). If the option is

	    LookupUserGroups REMOTE_USER_GROUPS

	the value will be either staff or student (the first in the list
	returned by the sssd dbus call; order not to be relied on).

	When

	    LookupOutput headers-base64

	is specified, the values are encoded individually and then
	concatenated. For the staff and student values example,

	    LookupUserGroups REMOTE-USER-GROUPS :

	will produce c3RhZmY=:c3R1ZGVudA==.

	When prefixed with '+' sign and the note/environment variable
	already has some value set, behaviour differs depending on
	whether the optional separator is specified or not. If it is,
	the string with separator-separated values is appended after
	separator to existing value. If separator is not specified,
	existing value is preserved.

	Example: when user alice is member of groups staff and student,
	and the environment variable REMOTE_USER_GROUPS already has
	value "anonymous" set (by Apache configuration or by some
	module that was invoked before mod_lookup_identity), directive

	    LookupUserGroups +REMOTE_USER_GROUPS :

	will set the value to "anonymous:staff:student" (or
	"anonymous:student:staff"). On the other hand,

	    LookupUserGroups +REMOTE_USER_GROUPS

	would leave the value unchanged at "anonymous".

	By default, groups are not retrieved.

    LookupUserGroupsIter name

	The number of groups the user is a member of (as returned by
	the org.freedesktop.sssd.infopipe.GetUserGroups call) will be
	stored in note/environment variable <name>_N and individual
	values in <name>_1 .. <name>_<<name>_N>. This allows for
	safe retrieval of groups without the separator clashing with
	the values.

	Example: if user alice is member of groups staff and student,
	option

	    LookupUserGroupsIter REMOTE_USER_GROUP

	will set

	    REMOTE_USER_GROUP_N=2
	    REMOTE_USER_GROUP_1=staff
	    REMOTE_USER_GROUP_2=student

	(or the values of REMOTE_USER_GROUP_1 and REMOTE_USER_GROUP_2
	will be flipped).

	When

	    LookupOutput headers-base64

	is specified and assuming

	    LookupUserGroupsIter REMOTE-USER-GROUP

	the HTTP header values will be

	    REMOTE-USER-GROUP-N=2
	    REMOTE-USER-GROUP-1=c3RhZmY=
	    REMOTE-USER-GROUP-2=c3R1ZGVudA==

	Note that the numerical <name>_N is not Base64-encoded.

	If user is not a member of any group, the <name>_N value will
	be set to 0.

	When the name is prefixed with '+' sign, existing values are
	preserved and new values added to the list. Thus, if alice is
	member of groups staff and student and REMOTE_USER_GROUP_N
	already has value 2 set and the directive is

	    LookupUserGroupsIter +REMOTE_USER_GROUP

	the module will set values of REMOTE_USER_GROUP_3
	and REMOTE_USER_GROUP_4 and will update REMOTE_USER_GROUP_N
	to value 4. The module will however not check/fix the consistency
	of existing values; if REMOTE_USER_GROUP_N is set to value 2
	prior to invocation of mod_lookup_identity, it will not check
	if REMOTE_USER_GROUP_1 and REMOTE_USER_GROUP_2 are set to match
	REMOTE_USER_GROUP_N.

	By default, groups are not retrieved.

    LookupUserAttr the_attribute name [separator]

	Name of the attribute to be retrieved using the
	org.freedesktop.sssd.infopipe.GetUserAttr call and name of
	the note and/or environment variable where the value will
	be stored, and optionally separator for multivalued results.

	If the separator is specified, it is used to concatenate
	multiple values in single string value of the
	note/environment variable. If the separator is not specified,
	only one value is set.

	Example:

	    LookupUserAttr mail REMOTE_USER_MAIL

	will retrieve one value from the mail attribute (from potentially
	multivalued attribute) and store them to note/environment
	variable REMOTE_USER_MAIL.

	Directive

	    LookupUserAttr mail REMOTE_USER_MAIL ", "

	will retrieve all the values and store them as comma-separated
	string. The same way as with LookupUserGroups, headers-base64
	will first Base64 encode and then concatenate.

	When the name is prefixed with '+' sign, similar to LookupUserGroups
	it will only set the value if not set yet, or append to existing
	value if separator is specified: when

	    LookupUserAttr team +REMOTE_USER_TEAMS ", "

	is configured and REMOTE_USER_ORGS is already set to "IT" and
	the sssd dbus returned values "Helpdesk" and "Support", the
	resulting value will be "IT, Helpdek, Support".

	Multiple LookupUserAttr lines can be used to retrieve multiple
	attributes.

	By default, no user attributes are retrieved.

    LookupUserAttrIter the_attribute name

	The number of attribute values for the user (as returned by
	the org.freedesktop.sssd.infopipe.GetUserAttr call) will be
	stored in note/environment variable <name>_N and individual
	values in <name>_1 .. <name>_<<name>_N>. This allows for
	safe retrieval of multivalued attributes without the
	separator clashing with the values.

	Example: if user alice has multivalued custom attribute
	office_no with values M314 and P005,

	    LookupUserAttrIter office_no REMOTE_USER_OFFICE

	will cause the following notes/environment variables to be
	set:

	    REMOTE_USER_OFFICE_N=2
	    REMOTE_USER_OFFICE_1=M314
	    REMOTE_USER_OFFICE_2=P005

	When the '+' sign is used, behaviour matches the behaviour of
	LookupUserGroupsIter -- the list formed by _N and _# variables
	is appended to.

	Multiple LookupUserAttr lines can be used to retrieve multiple
	attributes.

	By default, no user attributes are retrieved.

    LookupDbusTimeout miliseconds

	Default: 5000 (== 5 s).

    LookupUserByCertificateParamName

    Name of parameter for HTTP request's query string. The value from
    query string (if there is any) is then sent to SSSD together with
    the certificate. This is useful when single certificate is
    assigned to multiple user accounts.

    By default, no parameter is parsed from query string.

Please note that LookupUserGroups and LookupUserGroupsIter, as well as
LookupUserAttr and LookupUserAttrIter for single attribute can be
configured with the same note/environment variable name. For example,

    LookupUserGroups REMOTE_USER_GROUPS :
    LookupUserGroupsIter REMOTE_USER_GROUP

can be set at the same time and for user with two groups, all the
following values will be set:

    REMOTE_USER_GROUPS=staff:student
    REMOTE_USER_GROUP_N=2
    REMOTE_USER_GROUP_1=staff
    REMOTE_USER_GROUP_2=student

Building from sources
---------------------

When building from sources, command

    apxs -i -a -c $(pkg-config --cflags dbus-1) $(pkg-config --libs dbus-1) \
	 -Wc,"-Wall -pedantic -std=c99" mod_lookup_identity.c

should build and install the module.

If the available version of sssd does not provide or is not configured
to provide the ifp dbus service, compile with

    apxs -DNO_USER_ATTR -i -a -c -Wc,"-Wall -pedantic -std=c99" \
	 mod_lookup_identity.c

In that case, the LookupUserAttr functionality will not be compiled
in and will not be available.

License
-------

Copyright 2013--2017 Jan Pazdziora

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

