OpenID Connect Authenticator

Last modified by Thomas Mortagne on 2024/10/07 00:13

openid_connect_16x16.pngAllow an XWiki instance to authenticate on an OpenID Connect provider
Recommended
TypeJAR
CategoryAuthenticator
Developed by

Thomas Mortagne

Active Installs122
Rating
1 Votes
LicenseGNU Lesser General Public License 2.1
Compatibility

XWiki 14.10+ is required.

Installable with the Extension Manager

Description

Allow an XWiki instance to authenticate on an OpenId Connect provider. It also performs automatic synchronization.

See also OpenID Connect Provider.

oidc_client_provider.png

Release notes can be found on OpenID Connect project page.

Main limitations

Configuration

Configuration Guides for specific systems

Lemon LDAP / Open PAAS

A configuration guide is available to connect XWiki to LemonLDAP / OpenPAAS using the OpenIDC XWiki client.

OpenID Authentication with Keycloak

A configuration example for Keycloak is available.

Univention Corporate Server

A configuration example for Univention Corporate Server (UCS) is available.

Microsoft Entra ID

A configuration example for Microsoft Entra ID is available.

Configuration files

xwiki.cfg

#-# The authentication management class.
xwiki.authentication.authclass=org.xwiki.contrib.oidc.auth.OIDCAuthServiceImpl

xwiki.properties

#-# The base URL of the OpenId Connect Provider to use as starting point to discover the provider configuration.
#-# See following endpoints properties if the provider is does not support OpenID Connect discovery.
#-# If not indicated and not custom endpoint is provided, it will be asked to the user.
# oidc.provider=https://xwikiorg-node1.xwikisas.com/xwiki/oidc

#-# The generic OpenId Connect endpoints to use to communicate with the provider.
#-# It's generally not needed when providing the provider discovery endpoint (which is supposed to provide those enpoints).
# oidc.endpoint.authorization=https://xwikiorg-node1.xwikisas.com/xwiki/oidc/authorization
# oidc.endpoint.token=https://xwikiorg-node1.xwikisas.com/xwiki/oidc/token
# oidc.endpoint.userinfo=https://xwikiorg-node1.xwikisas.com/xwiki/oidc/userinfo
# oidc.endpoint.logout=https://xwikiorg-node1.xwikisas.com/xwiki/oidc/logout

#-# It's possible to add custom HTTP headers to the endpoint (generally only needed for bad or non-oidc providers)
#-# by adding the suffix ".headers" to the endpoint property key and listing the custom headers using key:value format.
#-# Note that it's not taken into account for the oidc.endpoint.authorization endpoint because it's used as a redirect.
#-# Here is an example to send "Accept: application/json" and "SomeOtherHeader: header" HTTP headers with the userinfo request.
# oidc.endpoint.userinfo.headers=Accept:application/json
# oidc.endpoint.userinfo.headers=SomeOtherHeader:header value

#-# The scopes to use when redirecting to the provider
#-# The standard OpenID Connection scopes are:
#-# * openid: Informs the authorisation server that the client is making an OpenID Connect request (REQUIRED).
#-# * profile: Requests that access to the end-user's default profile claims at the UserInfo endpoint be granted by the issued access token.
#-# * email: Requests that access to the email and email_verified claims at the UserInfo endpoint be granted by the issued access token.
#-# * address: Requests that access to address claim at the UserInfo endpoint be granted by the issued access token.
#-# * phone: Requests that access to the {phone_number and phone_number_verified claims at the UserInfo endpoint be granted by the issued access token.
#-# * offline_access: Requests that an OAuth 2.0 refresh token be issued that can be used to obtain an access token that grants access the end-user's UserInfo endpoint even when the user is not present (not logged in).
#-# 
#-# But depending on the provider more can be listed.
#-# 
#-# The default is:
# oidc.scope=openid,profile,email,address,phone

#-# The response type to control the flow used by the OpenId Connect protocol.
#-# This is often used to control if the information about the user should
#-# be gathered from the userinfo endpoint with a request from XWiki to the provider ("code", the default)
#-# or the id token directly provided when the provider redirects to XWiki ("id_token")
#-# but it's also possible to combine.
#-# See https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3 for mode details.
#-# For an hybrid flow, use list syntax (so comma or several set) instead of the white space
#-# documented in the specification to separate words.
#-#
#-# The default is:
# oidc.responseType=code

#-# The method used to access the userinfo endpoint.
#-# 
#-# Supported values are:
#-# * GET: use GET HTTP method
#-# * POST: use POST HTTP method
#-# 
#-# The default is:
# oidc.endpoint.userinfo.method=GET

#-# The pattern to use to generate the XWiki user name.
#-# 
#-# The following variables are available:
#-# oidc.user.subject: the unique id of the user in the provider
#-# oidc.user.mail: the mail of the user
#-# oidc.user.familyName : the last name of the user
#-# oidc.user.givenName: the first name of the user
#-# oidc.user.preferredUsername: the recommended string to use as id for the user
#-# oidc.provider: the URL of the XWiki provider (only when a XWiki provider is used)
#-# oidc.provider.host: the host of the provider URL
#-# oidc.provider.path: the path of the provider URL
#-# oidc.provider.protocol: the protocol (usually https) of the provider URL
#-# oidc.provider.port: the port of the provider URL
#-# oidc.issuer: the issuer URI
#-# oidc.issuer.host: the host of the issuer URI
#-# oidc.issuer.path: the path of the issuer URI
#-# oidc.issuer.scheme: the scheme (usually https) of the issuer URI
#-# oidc.issuer.port: the port of the issuer URI
#-# 
#-# Both the entire userinfo and id token JSON received from the provider are also available using respectively:
#-# * "oidc.user." for the userinfo
#-# * "oidc.idtoken." for the id token
#-# For example if the provider send the following JSON for the user info:
#-# {
#-#   "sub"                : "248289761001",
#-#   "name"               : "Jane Doe",
#-#   "given_name"         : "Jane",
#-#   "family_name"        : "Doe",
#-#   "preferred_username" : "j.doe",
#-#   "email"              : "[email protected]",
#-#   "picture"            : "http://example.com/janedoe/me.jpg"
#-#   "customobject"        :
#-#   {
#-#     "customproperty"   :  "customvalue"
#-#   }
#-# }
#-# you can use the variable ${oidc.user.customobject.customproperty}.
#-#
#-# The following suffixes can be added:
#-# * "._lowerCase": the lower case version of the string
#-# * "._upperCase": the upper case version of the string 
#-# * "._clean": a version of the string stripped from ".", ":", ",", "@", "^" characters and "\s" (all forms of white spaces).
#-#             It can itself be suffixed with "._lowerCase" and "._upperCase".
#-#
#-# The variable syntax also have other features (fallback value, etc.) detailed on https://commons.apache.org/proper/commons-text/apidocs/org/apache/commons/text/StringSubstitutor.html.
#-# 
#-# The default is: 
# oidc.user.nameFormater=${oidc.issuer.host._clean}-${oidc.user.preferredUsername._clean}

#-# The pattern to use to generate the unique identifier of the user in the OpenId Connect provider.
#-# It is used to avoid collisions with user have similar name.
#-# 
#-# The syntax is the same than the one described for oidc.user.nameFormater property.
#-# 
#-# The default is: 
# oidc.user.subjectFormater=${oidc.user.subject}

#-# It's possible to associate non standard properties coming from the OpenID Connect provider with the XWiki user.
#-# It's a map with the name of the XWiki user property and a format similar to the one defined in oidc.user.nameFormater for the OpenID Connect side.
#-# 
# oidc.user.mapping=myxproperty1=${oidc.user.subject}
# oidc.user.mapping=myxproperty2=myprefix-${oidc.user.subject}

#-# The righs each new user should have on its own profile as a comma (only comma, no white space allowed) separated list. Setting a right also implies that all the others users don't have it.
#-# For example if you want that only users have view right on their profile but thay can modify their own profile you could use:
# oidc.user.oidc.user.ownProfileRights=view,edit
#-# 
#-# The default is (user profiles are viewable by all users by default and it's possible to edit one own's profile):
# oidc.user.oidc.user.ownProfileRights=edit

#-# The full custom claims JSON to request from the provider. By default this is empty and the values from oidc.idtokenclaims and oidc.userinfoclaims are sent as claims. 
#-# The oidc.idtokenclaims and oidc.userinfoclaims only allow you to set the keys passed to the IdP, but some claims (e.g. the acr claim) may also require a value.
#-# Use oidc.claims if you have to set a value for any of the claims. If oidc.claims is set and valid, the values in oidc.idtokenclaims and oidc.userinfoclaims are ignored.
#-# It is currently necessary to escape commas in the JSON. This will change when XWIKI-22071 is resolved.
#-# Example: request an essential acr value of 2 and keep all other default claims from oidc.idtokenclaims and oidc.userinfoclaims:
#-# oidc.claims={"userinfo":{"xwiki_user_accessibility":null\,"xwiki_user_company":null\,"xwiki_user_displayHiddenDocuments":null\,"xwiki_user_editor":null\,"xwiki_user_usertype":null}\,"id_token":{"xwiki_instance_id":null\,"acr":{"values":["2"]\,"essential":true}}}
#-#
#-# The default is:
# oidc.claims=

#-# The custom claims to request to the provider for id token.
#-#
#-# The default is:
# oidc.idtokenclaims=xwiki_instance_id

#-# The name of the claim used to get the list of groups the user belong to.
#-# This claim also need to be listed in oidc.userinfoclaims which control if group membership synchronization is enabled or not.
#-# 
#-# It's also possible to use a custom property from the userinfo JSON.
#-# For example if the provider send the following JSON for the user info:
#-# {
#-#   "sub"                : "248289761001",
#-#   "name"               : "Jane Doe",
#-#   "given_name"         : "Jane",
#-#   "family_name"        : "Doe",
#-#   "preferred_username" : "j.doe",
#-#   "email"              : "[email protected]",
#-#   "picture"            : "http://example.com/janedoe/me.jpg"
#-#   "customobject"        :
#-#   {
#-#     "customgroups"   :  ["group1", "group2"]
#-#   }
#-# }
#-# you can use:
# oidc.groups.claim=customobject.customgroups
#-# 
#-# The default is:
# oidc.groups.claim=xwiki_groups

#-# Receiving a groups list is enough to enable group synchronization but you might need to configure XWiki groups names different from the remote groups names.
#-# It's also required to indicate what's the field containing the list of groups (that's not an OpenID Connect standard) using oidc.groups.claim property.
#-# 
# oidc.groups.mapping=MyXWikiGroup=my-oidc-group
# oidc.groups.mapping=MyXWikiGroup2=my-oidc-group2
# oidc.groups.mapping=MyXWikiGroup2=my-oidc-group3

#-# The groups the user need to belong to be allowed to authenticate.
#-# Not taken into account if not set or empty.
#-# 
# oidc.groups.allowed=

#-# If the user belong to one of these groups it won't be allowed to authenticate
#-# Not taken into account if not set or empty.
#-# 
# oidc.groups.forbidden=

#-# If set, only group names with this prefix will be provisioned
#-# Not taken into account if not set or empty.
#-# 
# oidc.groups.prefix=

#-# If the identity provider returns group memberships as a single value attribute delimited with a char, for example:
#-# {
#-#   "sub"                : "248289761001",
#-#   "name"               : "Jane Doe",
#-#   "given_name"         : "Jane",
#-#   "family_name"        : "Doe",
#-#   "preferred_username" : "j.doe",
#-#   "email"              : "[email protected]",
#-#   "picture"            : "http://example.com/janedoe/me.jpg",
#-#   "groups"             : "group1,group2"
#-# }
#-# you can set here the separator char to get the list of groups the user belong to. 
#-# If not set, group memberships are evaluated as a multi valued attribute.
#-# 
# oidc.groups.separator=

#-# The custom claims to request to the provider for the UserInfo
#-# 
#-# The available custom claims are:
#-# xwiki_groups (or whatever you indicated in oidc.groups.claim): the groups a user belong to in the provider (see "Group synchronization" section for more details)
#-# xwiki_user_<fieldname>: the suffix to use to request any field in the user profile document (generally when the provider is XWiki) 
#-# The default is:
# oidc.userinfoclaims=xwiki_user_accessibility,xwiki_user_company,xwiki_user_displayHiddenDocuments,xwiki_user_editor,xwiki_user_usertype

#-# The time after which the user information should be refreshed (in milliseconds)
#-# 
#-# The default is:
# oidc.userinforefreshrate=600000

#-# Some providers have a bad implementation of the userinfo endpoint, making it unusable. Fortunately in those cases the id token tends to contains the user information, making possible to just skip the userinfo and use that instead.
#-# 
#-# The default is:
# oidc.userinfo.skip=false

#-# The client identifier used by the authentication.
#-# The default is the identifier of the XWiki instance.
# oidc.clientid=

#-# The client secret (optionally) registered on the provider.
#-# By default nothing is sent to the provider.
# oidc.secret=

#-# How to send the client id and secret.
#-# 
#-# Supported values are:
#-# * client_secret_basic: the id and the secret are sent using BASIC auth header
#-# * client_secret_post: the id and the secret are sent in the the request body 
#-# 
#-# The default is:
# oidc.endpoint.token.auth_method=client_secret_basic

#-# The token to send along with the registration request to the provider.
#-# 
# oidc.endpoint.register.token=

#-# Configure the in-wiki OIDC configuration
#-# 
#-# Define the name of the default wiki OIDC configuration to be used for client authentication.
#-# If no configuration with such name is found, the authenticator will rely only on the configuration keys declared in
#-# this file.
#-#
#-# The default is:
#-# oidc.defaultClientConfiguration=default
#-#
#-# When using in-wiki OIDC configuration, it is possible to define multiple configurations that can be selected by
#-# the end user through a cookie indicating the name of the configuration to be used. You can control the name of
#-# this cookie with the following configuration.
#-#
#-# oidc.clientConfigurationCookie=oidcProvider

#-# Define if user accounts should be enabled (marked as active) on first login
#-#
# oidc.enableUser=true

#-# Disable the OpenId Connect authenticator
#-# 
#-# The default is:
# oidc.skipped=false

In-wiki configuration

XWiki 1.30+ The OIDC authenticator can be configured in XWiki, and to rely on multiple configurations which get selected through a user cookie.

In order to use the in-wiki configuration of the OIDC authenticator, you will still need to define the configuration key xwiki.authentication.authclass in xwiki.cfg. Once the OIDC Authenticator installed, you will be able to define new OIDC Client configurations through objects of class XWiki.OIDC.ClientConfigurationClass.

The property "Configuration name" of the object will define the name of the OIDC configuration being declared. Use default for the default OIDC configuration. The other properties are similar to the properties defined in xwiki.properties. Use the key oidc.defaultClientConfiguration in xwiki.properties to change the name of the OIDC configuration that should be used by default.

When creating multiple in-wiki configurations, each configuration will be selectable by the user through the cookie oidcProvider. You can change the name of this cookie with the key oidc.clientConfigurationCookie in xwiki.properties.

Authentication with a domain-based instance

When XWiki is configured as a domain-based instance, users will not be automatically authenticated on every wiki by default, as the OIDC authenticator does not rely on the property xwiki.authentication.cookiedomains in xwiki.cfg.

To still allow users to be automatically authenticated when accessing one of the wikis of the farm, you will have to update the configuration of the session cookie of your servlet container so that this cookie gets set on a top-level domain, encompassing every wiki of farm. If your XWiki instance has very different domains for its wikis, this fix will not work.

When using Tomcat as a servlet container, it's possible to change the domain of the cookie JSESSIONID by adding the attribute sessionCookieDomain to context.xml as such :

<Context sessionCookieDomain="mytld.org">
...
</Context>

Endpoints

Callback

path: authenticator/callback

Back-Channel Logout

path: authenticator/backchannel_logout

Bypass OpenID Connect

As indicated in the previous section you can disable OpenID Connect using the property oidc.skipped in the xwiki.properties file.

It's also possible to skip OpenId Connect temporarily using a URL parameter: for example https://mydomain/xwiki/bin/view/Main/?oidc.skipped=true.

Group synchronization

The default group synchronization is enabled by adding the claim xwiki_groups to the claims sent to the IdP. You have to perform one of the following two steps in the xwiki.properties file depending on the property you use to specify claims:

  • If you use the oidc.claims property add "xwiki_groups":null to the userinfo object in the JSON specified as its value
  • If you use the oidc.userinfoclaims property add xwiki_groups to its list of values

By default this synchronization expect to receive the list of group names (without the `wiki:XWiki.` prefix) in which the user should be placed (groups are automatically created when they don't exist). You can also define a mapping between the XWiki groups and the provider groups using oidc.groups.mapping property.

It's also possible to implement your own custom group synchronization in a listener. See Listeners section.

ACR claim

You can specify an acr claim using the oidc.claims property in the xwiki.properties file, e.g. if you want to request a specific level of authentication. The acr value in the token returned by the IdP upon login will be compared to the value specified in the property and the login will be rejected if the values do not match.

Customization

Templates

The authenticator uses a template to ask the user for the target provider when it's not provided in the configuration. This template can be overwritten through the standard template system.

The name of the template is oidc/client/provider.vm.

Listeners

It's possible to implement an event listener and be notified during user profile update to add more to this process or do other things after it:

  • org.xwiki.contrib.oidc.event.OIDCUserUpdating to modify the user profile before it being saved
  • org.xwiki.contrib.oidc.event.OIDCUserUpdated to do something after the user profile has been saved

Troubleshooting

Enable DEBUG log

See Logging Admin Guide.

The specific packages to track for OpenID Connect module is org.xwiki.contrib.oidc. There is several ways to enable debug log.

With the Logging Admin UI

Use Logging Admin UI from the Administration section, add set TRACE or DEBUG level classes located in package org.xwiki.contrib.oidc.

Anything you set trough the Logging Administration won't be remembered after a restart.

With the Logback configuration file

You need to add the following in WEB-INF/classes/logback.xml:

<logger name="org.xwiki.contrib.oidc" level="trace"/>

You need to restart XWiki for this to be taken into account.

Short URLs

If you use short URL setup you will have to make sure to add "oidc" to the known entry points (same as "webjars" for example).

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.


Once you installed the extension you will need to indicate you want to use it as authenticator with the property xwiki.authentication.authclass in xwiki.cfg file. See Configuration section for more details.

Dependencies

Dependencies for this extension (org.xwiki.contrib.oidc:oidc-authenticator 2.13.0):

  • org.xwiki.platform:xwiki-platform-oldcore 14.10.2
  • com.nimbusds:oauth2-oidc-sdk 11.20
  • org.xwiki.contrib.oidc:oidc-provider 2.13.0
  • org.xwiki.contrib.oidc:oidc-authenticator-configuration 2.13.0
  • org.xwiki.contrib.oidc:oidc-authenticator-user 2.13.0

Get Connected