Package net.shibboleth.idp.attribute.impl

# Class JDBCPairwiseIdStore

java.lang.Object
net.shibboleth.shared.component.AbstractInitializableComponent
net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore

All Implemented Interfaces:
  `DurablePairwiseIdStore`, `PairwiseIdStore`, `Component`, `DestructableComponent`, `InitializableComponent`

public class JDBCPairwiseIdStore extends AbstractInitializableComponent implements DurablePairwiseIdStore
JDBC-based storage management for pairwise IDs.

The general DDL for the database, which is unchanged for compatibility, is:

     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)
         );

.

The first three columns should be defined as the primary key of the table, and the other columns should be indexed.

Since:
  4.0.0

## Nested Class Summary

Nested Classes
Modifier and Type
Class
Description
`protected class`
`JDBCPairwiseIdStore.ConnectionWithLock`
A Class to encapsulate a `Connection` protected by an optional read/write lock.

## Field Summary

Fields
Modifier and Type
Field
Description
`private String`
`attachSQL`
Parameterized update statement used to attach an alias to an ID.
`private String`
`creationTimeColumn`
Name of the creation time column.
`private DataSource`
`dataSource`
JDBC data source for retrieving connections.
`private String`
`deactivateSQL`
Parameterized update statement used to deactivate an ID.
`private String`
`deactivationTimeColumn`
Name of the deactivation time column.
`private String`
`deleteSQL`
Parameterized delete statement used to clear dummy rows after verification.
`private String`
`getByIssuedSelectSQL`
Parameterized select query for lookup by issued value.
`private String`
`getBySourceSelectSQL`
Parameterized select query for lookup by source ID.
`private PairwiseIdStore`
`initialValueStore`
Optional hook for obtaining initial values from a primary store, usually a computed algorithm.
`private String`
`insertSQL`
Parameterized insert statement used to insert a new record.
`private String`
`issuerColumn`
Name of the issuer entityID column.
`private final org.slf4j.Logger`
`log`
Class logger.
`private String`
`peerProvidedIdColumn`
Name of recipient-attached alias column.
`private String`
`persistentIdColumn`
Name of the persistent ID column.
`private String`
`principalNameColumn`
Name of the principal name column.
`private Duration`
`queryTimeout`
Timeout of SQL queries.
`private ReadWriteLock`
`readWriteLock`
If non-null we doing local locking.
`private String`
`recipientColumn`
Name of the recipient entityID column.
`private Collection<String>`
`retryableErrors`
Error messages that signal a transaction should be retried.
`private String`
`sourceIdColumn`
Name of the source ID column.
`private String`
`tableName`
Name of the database table.
`private int`
`transactionIsolation`
What transaction isolation do we want?
`private int`
`transactionRetry`
Number of times to retry a transaction if it rolls back.
`private boolean`
`verifyDatabase`
Whether to fail if the database cannot be verified.

## Constructor Summary

Constructors
Constructor
Description
`JDBCPairwiseIdStore()`
Constructor.

## Method Summary

Modifier and Type
Method
Description
`void`
`attach(PairwiseId pid)`
Attach a peer-supplied alias to a pairwise ID.
`private List<PairwiseId>`
`buildIdentifierEntries(ResultSet resultSet)`
Build a list of `PairwiseId` objects from a result set.
`void`
`deactivate(PairwiseId pid)`
Deactivate/revoke a pairwise ID.
`protected void`
`doInitialize()`
`PairwiseId`
`getByIssuedValue(PairwiseId pid)`
Populate the underlying principal/source fields for the input object based on the supplied values.
`PairwiseId`
`getBySourceValue(PairwiseId pid, boolean allowCreate)`
Populate the pairwise ID field for the input object based on the supplied values.
`DataSource`
`getDataSource()`
Get the source datasource used to communicate with the database.
`PairwiseIdStore`
`getInitialValueStore()`
Get a store to use to produce the first value for a given issuer/recipient pair.
`Duration`
`getQueryTimeout()`
Get the SQL query timeout.
`Collection<String>`
`getRetryableErrors()`
Get the error messages to check for classifying a driver error as retryable, generally indicating a lock violation or duplicate insert that signifies a broken database.
`String`
`getTableName()`
Gets the table name.
`int`
`getTransactionRetries()`
Get the number of retries to attempt for a failed transaction.
`boolean`
`getVerifyDatabase()`
Get whether to allow startup if the database cannot be verified.
`boolean`
`isLocalLocking()`
Do we do thread level locking or delegate to the Database?
`void`
`setAttachSQL(String sql)`
Set the UPDATE statement used to attach an SPProvidedID to an issued value.
`void`
`setCreateTimeColumn(String name)`
Set the name of the creation time column.
`void`
`setDataSource(DataSource source)`
Get the source datasource used to communicate with the database.
`void`
`setDeactivateSQL(String sql)`
Set the UPDATE statement used to deactivate issued values.
`void`
`setDeactivationTimeColumn(String name)`
Set the name of the deactivation time column.
`void`
`setDeleteSQL(String sql)`
Set the DELETE statement used to clear dummy row(s) created during verification.
`void`
`setGetByIssuedSelectSQL(String sql)`
Set the SELECT statement used to lookup records by issued value.
`void`
`setGetBySourceSelectSQL(String sql)`
Set the SELECT statement used to lookup records by source ID.
`void`
`setInitialValueStore(PairwiseIdStore store)`
Set a store to use to produce the first value for a given issuer/recipient pair.
`void`
`setInsertSQL(String sql)`
Set the INSERT statement used to insert new records.
`void`
`setLocalEntityColumn(String name)`
Set the name of the issuer entityID column.
`void`
`setLocalLocking(boolean what)`
Will we do thread level locking or delegate to the Database?
`void`
`setPeerEntityColumn(String name)`
Set the name of the recipient entityID column.
`void`
`setPeerProvidedIdColumn(String name)`
Set the name of the peer-provided ID column.
`void`
`setPersistentIdColumn(String name)`
Set the name of the persistent ID column.
`void`
`setPrincipalNameColumn(String name)`
Set the name of the principal name column.
`void`
`setQueryTimeout(Duration timeout)`
Set the SQL query timeout.
`void`
`setRetryableErrors(Collection<String> errors)`
Set the error messages to check for classifying a driver error as retryable, generally indicating a lock violation or duplicate insert that signifies a broken database.
`void`
`setSourceIdColumn(String name)`
Set the name of the source ID column.
`void`
`setTableName(String name)`
Set the table name.
`void`
`setTransactionIsolation(int what)`
Set the parameter that will be passed to `Connection.setTransactionIsolation(int)`.
`void`
`setTransactionRetries(int retries)`
Set the number of retries to attempt for a failed transaction.
`void`
`setVerifyDatabase(boolean flag)`
Set whether to allow startup if the database cannot be verified.
`(package private) void`
`store(PairwiseId entry, JDBCPairwiseIdStore.ConnectionWithLock dbConn)`
Store a record containing the values from the input object.
`private void`
`verifyDatabase()`
Check the database and the presence of a uniqueness constraint.

### Methods inherited from class net.shibboleth.shared.component.AbstractInitializableComponent

`checkComponentActive, checkSetterPreconditions, destroy, doDestroy, ifDestroyedThrowDestroyedComponentException, ifInitializedThrowUnmodifiabledComponentException, ifNotInitializedThrowUninitializedComponentException, initialize, isDestroyed, isInitialized`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

## Field Details

### log

@Nonnull private final org.slf4j.Logger log
Class logger.

### dataSource

@NonnullAfterInit private DataSource dataSource
JDBC data source for retrieving connections.

### queryTimeout

@Nonnull private Duration queryTimeout
Timeout of SQL queries.

### transactionRetry

@NonNegative private int transactionRetry
Number of times to retry a transaction if it rolls back.

### transactionIsolation

private int transactionIsolation
What transaction isolation do we want?

### retryableErrors

@Nonnull private Collection<String> retryableErrors
Error messages that signal a transaction should be retried.

### readWriteLock

private ReadWriteLock readWriteLock
If non-null we doing local locking.

### verifyDatabase

private boolean verifyDatabase
Whether to fail if the database cannot be verified.

### tableName

@Nonnull @NotEmpty private String tableName
Name of the database table.

### issuerColumn

@Nonnull @NotEmpty private String issuerColumn
Name of the issuer entityID column.

### recipientColumn

@Nonnull @NotEmpty private String recipientColumn
Name of the recipient entityID column.

### principalNameColumn

@Nonnull @NotEmpty private String principalNameColumn
Name of the principal name column.

### sourceIdColumn

@Nonnull @NotEmpty private String sourceIdColumn
Name of the source ID column.

### persistentIdColumn

@Nonnull @NotEmpty private String persistentIdColumn
Name of the persistent ID column.

### peerProvidedIdColumn

@Nonnull @NotEmpty private String peerProvidedIdColumn
Name of recipient-attached alias column.

### creationTimeColumn

@Nonnull @NotEmpty private String creationTimeColumn
Name of the creation time column.

### deactivationTimeColumn

@Nonnull @NotEmpty private String deactivationTimeColumn
Name of the deactivation time column.

### getByIssuedSelectSQL

@NonnullAfterInit private String getByIssuedSelectSQL
Parameterized select query for lookup by issued value.

### getBySourceSelectSQL

@NonnullAfterInit private String getBySourceSelectSQL
Parameterized select query for lookup by source ID.

### insertSQL

@NonnullAfterInit private String insertSQL
Parameterized insert statement used to insert a new record.

### deactivateSQL

@NonnullAfterInit private String deactivateSQL
Parameterized update statement used to deactivate an ID.

### attachSQL

@NonnullAfterInit private String attachSQL
Parameterized update statement used to attach an alias to an ID.

### deleteSQL

@NonnullAfterInit private String deleteSQL
Parameterized delete statement used to clear dummy rows after verification.

### initialValueStore

@Nullable private PairwiseIdStore initialValueStore
Optional hook for obtaining initial values from a primary store, usually a computed algorithm.

## Constructor Details

### JDBCPairwiseIdStore

public JDBCPairwiseIdStore()
Constructor.

## Method Details

### getDataSource

@NonnullAfterInit public DataSource getDataSource()
Get the source datasource used to communicate with the database.

Returns:
  the data source;

### setDataSource

public void setDataSource(@Nonnull DataSource source)
Get the source datasource used to communicate with the database.

Parameters:
  `source` - the data source;

### setLocalLocking

public void setLocalLocking(boolean what)
Will we do thread level locking or delegate to the Database?

Parameters:
  `what` - do we want to lock locally?

### isLocalLocking

public boolean isLocalLocking()
Do we do thread level locking or delegate to the Database?

Returns:
  do we lock locally?

### setTransactionIsolation

public void setTransactionIsolation(int what)
Set the parameter that will be passed to `Connection.setTransactionIsolation(int)`.

Parameters:
  `what` - the value to set

### getQueryTimeout

@Nonnull public Duration getQueryTimeout()
Get the SQL query timeout.

Returns:
  the timeout

### setQueryTimeout

public void setQueryTimeout(@Nonnull Duration timeout)
Set the SQL query timeout. Defaults to 5s.

Parameters:
  `timeout` - the timeout to set

### getTransactionRetries

public int getTransactionRetries()
Get the number of retries to attempt for a failed transaction.

Returns:
  number of retries

### setTransactionRetries

public void setTransactionRetries(@NonNegative int retries)
Set the number of retries to attempt for a failed transaction. Defaults to 3.

Parameters:
  `retries` - the number of retries

### getRetryableErrors

@Nonnull @NotLive @Unmodifiable public Collection<String> getRetryableErrors()
Get the error messages to check for classifying a driver error as retryable, generally indicating a lock violation or duplicate insert that signifies a broken database.

Returns:
  retryable messages

### setRetryableErrors

public void setRetryableErrors(@Nullable Collection<String> errors)
Set the error messages to check for classifying a driver error as retryable, generally indicating a lock violation or duplicate insert that signifies a broken database.

Parameters:
  `errors` - retryable messages

### getVerifyDatabase

public boolean getVerifyDatabase()
Get whether to allow startup if the database cannot be verified.

Returns:
  whether to allow startup if the database cannot be verified

### setVerifyDatabase

public void setVerifyDatabase(boolean flag)
Set whether to allow startup if the database cannot be verified.

Verification consists not only of a liveness check, but the successful insertion of a dummy row, a failure to insert a duplicate, and then deletion of the row.

Parameters:
  `flag` - flag to set

### getTableName

@Nonnull @NotEmpty public String getTableName()
Gets the table name.

Returns:
  table name
Since:
  4.1.0

### setTableName

public void setTableName(@Nonnull @NotEmpty String name)
Set the table name.

Parameters:
  `name` - table name

### setLocalEntityColumn

public void setLocalEntityColumn(@Nonnull @NotEmpty String name)
Set the name of the issuer entityID column.

Parameters:
  `name` - name of issuer column

### setPeerEntityColumn

public void setPeerEntityColumn(@Nonnull @NotEmpty String name)
Set the name of the recipient entityID column.

Parameters:
  `name` - name of recipient column

### setPrincipalNameColumn

public void setPrincipalNameColumn(@Nonnull @NotEmpty String name)
Set the name of the principal name column.

Parameters:
  `name` - name of principal name column

### setSourceIdColumn

public void setSourceIdColumn(@Nonnull @NotEmpty String name)
Set the name of the source ID column.

Parameters:
  `name` - name of source ID column

### setPersistentIdColumn

public void setPersistentIdColumn(@Nonnull @NotEmpty String name)
Set the name of the persistent ID column.

Parameters:
  `name` - name of the persistent ID column

### setPeerProvidedIdColumn

public void setPeerProvidedIdColumn(@Nonnull @NotEmpty String name)
Set the name of the peer-provided ID column.

Parameters:
  `name` - name of peer-provided ID column

### setCreateTimeColumn

public void setCreateTimeColumn(@Nonnull @NotEmpty String name)
Set the name of the creation time column.

Parameters:
  `name` - name of creation time column

### setDeactivationTimeColumn

public void setDeactivationTimeColumn(@Nonnull @NotEmpty String name)
Set the name of the deactivation time column.

Parameters:
  `name` - name of deactivation time column

### setGetByIssuedSelectSQL

public void setGetByIssuedSelectSQL(@Nonnull @NotEmpty String sql)
Set the SELECT statement used to lookup records by issued value.

Parameters:
  `sql` - statement text, which must contain three parameters (NameQualifier, SPNameQualifier, value)

### setGetBySourceSelectSQL

public void setGetBySourceSelectSQL(@Nonnull @NotEmpty String sql)
Set the SELECT statement used to lookup records by source ID.

Parameters:
  `sql` - statement text, which must contain six parameters (NameQualifier, SPNameQualifier, source ID, NameQualifier, SPNameQualifier, source ID)

### setInsertSQL

public void setInsertSQL(@Nonnull @NotEmpty String sql)
Set the INSERT statement used to insert new records.

Parameters:
  `sql` - statement text, which must contain 8 parameters (NameQualifier, SPNameQualifier, value, principal, source ID, SPProvidedID, creation time, deactivation time)

### setDeactivateSQL

public void setDeactivateSQL(@Nonnull @NotEmpty String sql)
Set the UPDATE statement used to deactivate issued values.

Parameters:
  `sql` - statement text, which must contain four parameters (deactivation TS, NameQualifier, SPNameQualifier, value)

### setAttachSQL

public void setAttachSQL(@Nonnull @NotEmpty String sql)
Set the UPDATE statement used to attach an SPProvidedID to an issued value.

Parameters:
  `sql` - statement text, which must contain four parameters (SPProvidedID, NameQualifier, SPNameQualifier, value)

### setDeleteSQL

public void setDeleteSQL(@Nonnull @NotEmpty String sql)
Set the DELETE statement used to clear dummy row(s) created during verification.

Parameters:
  `sql` - statement text, which must contain one parameter (NameQualifier)

### getInitialValueStore

@Nullable public PairwiseIdStore getInitialValueStore()
Get a store to use to produce the first value for a given issuer/recipient pair.

Returns:
  initial value source

### setInitialValueStore

public void setInitialValueStore(@Nullable PairwiseIdStore store)
Set a store to use to produce the first value for a given issuer/recipient pair.

This is typically used to draw the "first" (often only) value for a given pairwise relationship from an algorithm instead of a random value requiring storage to know.

Parameters:
  `store` - initial value source

### doInitialize

protected void doInitialize() throws ComponentInitializationException

Overrides:
  `doInitialize` in class `AbstractInitializableComponent`
Throws:
  `ComponentInitializationException`

### getBySourceValue

@Nullable public PairwiseId getBySourceValue(@Nonnull PairwiseId pid, boolean allowCreate) throws IOException
Populate the pairwise ID field for the input object based on the supplied values.

The input object must contain values for issuer and recipient entityIDs and the principal name, and the pairwise ID will be populated as applicable on output.

The object returned, if non-null, may be, but does not have to be, the same physical object used as input. The original input object should not be referenced further.

Specified by:
  `getBySourceValue` in interface `PairwiseIdStore`
Parameters:
  `pid` - object to populate
  `allowCreate` - true iff the caller is authorizing the issuance of a new identifier
Returns:
  object for the given inputs or null if none exists
Throws:
  `IOException` - if an error occurs accessing the store

### getByIssuedValue

@Nullable public PairwiseId getByIssuedValue(@Nonnull PairwiseId pid) throws IOException
Populate the underlying principal/source fields for the input object based on the supplied values.

The input object must contain values for issuer and recipient entityIDs and the pairwiseId itself, and the rest of the fields will be populated as applicable on output.

The object returned, if non-null, will at least contain the principal name and source system ID. It may be, but does not have to be, the same physical object used as input. The original input object should not be referenced further.

Specified by:
  `getByIssuedValue` in interface `DurablePairwiseIdStore`
Parameters:
  `pid` - object to populate
Returns:
  object for the given inputs or null if none exists
Throws:
  `IOException` - if an error occurs accessing the store

### deactivate

public void deactivate(@Nonnull PairwiseId pid) throws IOException
Deactivate/revoke a pairwise ID.

If the object's deactivation time field is null, then the current time is used.

Specified by:
  `deactivate` in interface `DurablePairwiseIdStore`
Parameters:
  `pid` - the object to deactivate/revoke
Throws:
  `IOException` - if there is an error updating the store

### attach

public void attach(@Nonnull PairwiseId pid) throws IOException
Attach a peer-supplied alias to a pairwise ID.

Specified by:
  `attach` in interface `DurablePairwiseIdStore`
Parameters:
  `pid` - the object to update in storage
Throws:
  `IOException` - if there is an error updating the store

### store

void store(@Nonnull PairwiseId entry, @Nonnull JDBCPairwiseIdStore.ConnectionWithLock dbConn) throws SQLException
Store a record containing the values from the input object.

Parameters:
  `entry` - new object to store
  `dbConn` - connection to obtain a statement from.
Throws:
  `SQLException` - if an error occurs

### verifyDatabase

private void verifyDatabase() throws SQLException
Check the database and the presence of a uniqueness constraint.

Throws:
  `SQLException` - if the database cannot be verified

### buildIdentifierEntries

@Nonnull @Live private List<PairwiseId> buildIdentifierEntries(@Nonnull ResultSet resultSet) throws SQLException
Build a list of `PairwiseId` objects from a result set.

Parameters:
  `resultSet` - the result set
Returns:
  list of `PairwiseId` objects
Throws:
  `SQLException` - thrown if there is a problem reading the information from the database