StorageConfiguration

File(s): conf/global.xml, conf/idp.properties
Format: Native Spring

Overview

The IdP provides a number of general-purpose storage facilities that can be used by various features like sessions, consent, replay detection, CAS ticket storage, and many others, including various features provided by additional plugins.

Broadly speaking, there are two kinds of storage plugins: client-side and server-side. Client-side plugins have the advantage of requiring no additional software or configuration and make clustering very robust and simple, but they only support a subset of use cases well since the data lives only in a single user agent. Server-side plugins support all use cases (aside from the simple case of storing data in memory), but require additional software and configuration, and usually create additional points of failure in a clustered deployment.

Where possible, the project recommends using client-side storage whereever possible/acceptable, and in particular for session storage, which uses that approach now by default. In other cases, we suggest consideration of in-memory storage where the use case allows, or if the feature supports a more advanced approach that doesn’t require storage at all. In most cases, we default to not requiring storage when possible (e.g., CAS ticket encoding, SAML transient NameID construction, others).

The most common use case in the core software requiring persistent server-side storage, and thus some additional infrastructure, is probably consent (assuming that storing consent per-browser is not desirable).

When clustering, you should obviously take a look at the https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199501063 topic for a more holistic discussion of that use case. You may also wish to review the https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199501597 topic, as it may have implications for your storage options and/or the need to address SameSite based on your chosen options.

The IdP ships with 3 preconfigured StorageService beans:

  • shibboleth.ClientSessionStorageService (of type ClientStorageService)

    • Stores data in a browser session cookie or HTML local storage

  • shibboleth.ClientPersistentStorageService (of type ClientStorageService)

    • Stores data in a long-lived browser cookie or HTML local storage

  • shibboleth.StorageService (of type MemoryStorageService)

    • Stores data in server memory, does not survive restarts and is not replicated across a cluster

There is an additional storage service implementation included in the software (memcached), and at least one plugin available for JDBC, but they are not predefined. Using them requires defining beans yourself and setting various properties to point to them.

By default, the shibboleth.ClientSessionStorageService bean, which stores data in the client, is used to store IdP session data, but that can be modified via the idp.properties file:

Example changing IdP session storage to in-memory for non-clustered use:
idp.session.StorageService = shibboleth.StorageService

There are additional properties that can be used to change how other data is stored on a per-use case basis, but note that some components can't (or usually shouldn’t) rely on client-side storage options, and more specific documentation will address that. This topic is the overview of how to configure storage options, but doesn’t speak to handling specific use cases.

Reference

Property

Type

Default

Description

Property

Type

Default

Description

idp.storage.cleanupInterval

Duration

PT10M

Interval of background thread sweeping server-side storage for expired records

idp.storage.htmlLocalStorage

Boolean

false

Whether to use HTML Local Storage (if available) instead of cookies

idp.storage.clientSessionStorageName

String

shib_idp_session_ss

Name of cookie or HTML storage key used by the default per-session instance of the client storage service

idp.storage.clientPersistentStorageName

String

shib_idp_persistent_ss

Name of cookie or HTML storage key used by the default persistent instance of the client storage service

idp.session.StorageService

Bean ID of a StorageService

shibboleth.ClientSessionStorageService

Storage back-end to use for IdP sessions, authentication results, and optionally tracking of SP usage for logout

idp.consent.StorageService

Bean ID of a StorageService

shibboleth.ClientPersistentStorageService

Storage back-end to use for consent and terms-of-use records

idp.replayCache.StorageService

Bean ID of a StorageService

shibboleth.StorageService

Storage back-end to use for message replay checking (must be server-side)

idp.replayCache.strict

Boolean

true

Whether storage errors during replay checks should be treated as a replay

idp.artifact.StorageService

Bean ID of a StorageService

shibboleth.StorageService

Storage back-end to use for short-lived SAML Artifact mappings (must be server-side)

idp.cas.StorageService

Bean ID of a StorageService

shibboleth.StorageService

Storage back-end to use for CAS ticket mappings (must be server-side)

The following beans (most of which are internal to the system) can be used in various properties to control what storage instances are used for specific purposes. You can define your own beans also (e.g. in global.xml).

Bean ID

Type

Description

Bean ID

Type

Description

shibboleth.StorageService

MemoryStorageService

Default server-side storage, stores data in memory

shibboleth.ClientSessionStorageService

ClientStorageService

Default client-side storage for per-session data, stores data in session cookies or HTML local storage

shibboleth.ClientPersistentStorageService

ClientStorageService

Default client-side storage for long-lived data, stores data in persistent cookies or HTML local storage

shibboleth.ClientStorageServices

List<StorageService>

Enumeration of ClientStorageService plugins used, ensures proper load/save of data

Storage Implementations

There are only two functionally-complete implementations of the storage interface supplied with the software (aside from the in-memory option of course). The JPA implementation is no longer included, and has been replaced by the JDBC storage plugin.

The ClientStorageService is an advanced, and strongly recommended, option that includes support for HTML Local Storage along with cookies as a fallback or alternative. It is the default mechanism for storage of sessions that allow for SSO and we recommend it for that purpose to the exclusion of the server-side options.

Local Storage support is enabled by default for new installation, but note that it requires JavaScript be enabled, because reading and writing to the client requires an explicit page be rendered. When JavaScript is enabled, the additional page appears quickly as a short-lived interstitial with a message about the loading or saving of the data to the client. In practice, it is has no material impact on the user experience and the loading page only appears when a new session with the servlet container is created.

Controlling the Local Storage feature is handled by the idp.storage.htmlLocalStorage property.

No additional configuration is required, but you may want to change the look and feel of the templates that are displayed to the client while data is being read or written. These pages don't require any user interaction as long as JavaScript is enabled, but they tend to be visible at least briefly. They're somewhat similar to the templates displayed when SAML messages are handed off to the browser.

Much of that look is obviously controlled by style sheets and message properties, but the "visible" portions are in views/client-storage

As to why you would use Local Storage vs. just allowing use of cookies with this storage implementation, there are really two main reasons:

  • Logout

  • Consent

The main reason for this feature is to enable the IdP's session manager to track and index the sessions created with SPs, and that information does not fit reliably in a cookie. That makes the single-logout feature unusable with client-side sessions unless Local Storage is enabled, since the IdP doesn't know what SPs to communicate with. Enabling the Local Storage feature is necessary but not sufficient to allow at least some form of single logout to work without moving session storage to the server. You also will need to ensure a couple of additional session management properties (idp.session.trackSPSessions and idp.session.secondaryServiceIndex) are enabled, and they are also on by default in new installs. There are two properties because the latter is more a SAML-specific need that may not extend to other protocols in the future.

The consent feature is very limited when cookies are used because the number of records it can store is extremely small. If Local Storage is available, that limit is essentially ignored. If you're comfortable with tracking consent per-device, this is a simpler way to deploy it than with a database.

Requirements: memcached v1.4.14 or later

The memcached-based storage service is based on the spymemcached library, which has a number of features for HA deployments:

  • Optimized IO for high throughput

  • Memcached failover facility

  • Stable hashing algorithm supports memcached pool resizing

The failover facility merits further discussion. Failover is enabled by specifying multiple memcached hosts and failureMode="Redistribute". When the client encounters an unreachable host in redistribute mode, it will temporarily remove the unavailable host from the pool of available hosts. Any keys that hash to the unavailable host will be written or retrieved from a backup host. The high-level effect of this behavior on the IdP session management service is that a node failure will cause loss of IdP session, which would impact users as an unexpected authentication. The IdP session management service, however, would be fully functional during a host failure/recovery event. Also note that this behavior requires no state sharing (i.e. repcache) between memcached nodes.

Bear in mind that different storage use cases have different failover properties. While the replay cache would be similarly unimpacted, the artifact map failing to retrieve a previously stored artifact mapping would result in a failed login to the service to which the artifact was sent.

The following architecture is suggested for HA deployments using memcache:

Thus every IdP node runs a memcached service and the Java process running the IdP software connects to every memcached service. The following configuration example assumes the recommended architecture above and should be placed in conf/global.xml .

MemcachedStorageService Configuration
  <bean id="shibboleth.MemcachedStorageService" class="org.opensaml.storage.impl.memcached.MemcachedStorageService" c:timeout="2"> <constructor-arg name="client"> <bean class="net.spy.memcached.spring.MemcachedClientFactoryBean" p:servers="idp-1.example.com:11211,idp-2.example.com:11211,idp-3.example.com:11211" p:protocol="BINARY" p:locatorType="CONSISTENT" p:failureMode="Redistribute"> <property name="hashAlg"> <util:constant static-field="net.spy.memcached.DefaultHashAlgorithm.FNV1_64_HASH" /> </property> <property name="transcoder"> <!-- DO NOT MODIFY THIS PROPERTY --> <bean class="org.opensaml.storage.impl.memcached.StorageRecordTranscoder" /> </property> </bean> </constructor-arg> </bean>

Once a MemcachedStorageService bean has been defined as above, it can be used with subsystems that require a StorageService component. The following configuration snippet from conf/idp.properties indicates how to use memcached for session storage.

Memcached for IdP Sessions
idp.session.StorageService = shibboleth.MemcachedStorageService