The alternative PairwiseIdStore generates random identifiers on first use and stores them in a database for future use. This has some benefits and addresses some of the limitations of the computed approach, but requires a highly available database accessible to every IdP node and is very difficult (bordering on impossible) to make reliable. Note that it is not possible to implement such a database using asynchronous/unreliable replication. This will lead to conflicts and race conditions, and eventually a risk of errors and duplicate entries. This is the main reason it isn't easy to get working, as most applications simply can't tolerate these kinds of conflicts easily. The "vanilla" DDL needed for this approach is: Code Block |
---|
language | sql |
---|
title | Stored ID Table Definition |
---|
collapse | true |
---|
| CREATE TABLE shibpid (
localEntity VARCHAR(255) NOT NULL,
peerEntity VARCHAR(255) NOT NULL,
persistentId VARCHAR(50) NOT NULL,
principalName VARCHAR(50) NOT NULL,
localId VARCHAR(50) NOT NULL,
peerProvidedId VARCHAR(50) NULL,
creationDate TIMESTAMP NOT NULL,
deactivationDate TIMESTAMP NULL,
PRIMARY KEY (localEntity, peerEntity, persistentId)
); |
You will need to define the table above in your database, and you must define a primary key as shown above or the implementation will not function as intended. The absence of this constraint will normally be detected at startup time and prevent use of the mechanism. Also ensure that the collation associated with the "localId" column is appropriate for use with the source attribute you specify. An inappropriate collation can render the attribute non-unique. In particular, it has been observed that a case-sensitive collation is needed if using the Active Directory objectSid as the source attribute, to ensure that persistent IDs are uniquely identified. "utf8_bin" has been found to work in this circumstance. Using this strategy requires setting the properties described earlier, as well as some additional changes: - The idp.persistentId.generator property needs to be set to "shibboleth.StoredPersistentIdGenerator".
- The idp.persistentId.dataSource property must be set to the name of a DataSource bean you must define. You can place it in saml-nameid.xml if you like (anywhere at the "top" level of the file).
A default feature of the stored strategy is that it uses the computed strategy to produce the initial identifier for each subject, to help with migration. If you don't need that to happen, you can set the idp.persistentId.computed property to an empty value and ignore that feature entirely, but it isn't a terrible idea to leverage this because it hedges your bets. If you find that the stored model is unworkable in practice, you may be able to easily convert back to the computed approach if all your values are compatible with it. Note |
---|
It's not a good idea to define a single shared DataSource bean between this feature and, for example, the JPA StorageService feature, even if you happen to use one database for both. The reason is that you don't want "non-essential" features like consent potentially interfering with the more essential use here. Separate DataSource beans will keep the pools of connections separate and prevent problems in one component from breaking the other. |
Examples of each type of bean using an unspecified database and the DBCP2 pooling library (included with the IdP) follows. You will need to determine what driver class to plug into the bean definition for your database and the proper URL to use. Always use current drivers when possible; bug fixes for obscure problems tend to be frequent. When in doubt, grab a newer one. Code Block |
---|
language | xml |
---|
title | Example persistent ID store beans in saml-nameid.xml |
---|
collapse | true |
---|
| <!-- A DataSource bean suitable for use in the idp.persistentId.dataSource property. -->
<bean id="MyDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
p:driverClassName="com.example.database.Driver"
p:url="jdbc:example://localhost/database"
p:username="shibboleth"
p:password="foo"
p:maxIdle="5"
p:maxWaitMillis="15000"
p:testOnBorrow="true"
p:validationQuery="select 1"
p:validationQueryTimeout="5" />
<!-- A replacement bean suitable for use in the idp.persistentId.generator property. -->
<bean id="MyPersistentIdStore" parent="shibboleth.StoredPersistentIdGenerator"
p:dataSource-ref="MyDataSource"
p:queryTimeout="PT2S"
p:retryableErrors="#{{'23000'}}" /> |
Advanced CustomizationThere are a few cases where more advanced customization of the stored approach may be required, and this is accomodated by defining your own custom bean that inherits from "shibboleth.JDBCPersistentIdStoreStoredPersistentIdGenerator" and defines all of the any additional bean properties required (see the JDBCPairwiseIdStore javadoc). The option to define and reference your own bean rather than just supplying a plain DataSource is present to allow you to override the default table and column names used in the data store, the SQL queries used, the timeout, etc. The most common settings to override are the queryTimeout , and to provide a list of retryableErrors that are reported when a database improperly fails to prevent a duplicate insert. If this happens, the log will warn you and tell you what the error code was, and then you can add it to the configuration to prevent that problem in the future. (It also means your database fails to implement locking properly, and the retry mechanism is a workaround for that bug.) The example above illustrates this, but most of these settings are now accessible in V4.1 via simple Java properties and will not require a bean definition. |