Note |
---|
This document hasn’t been peer-reviewed. Your mileage may vary! |
Warning |
---|
The Attribute Definitions in this example use the |
Table of Contents |
---|
There are many reasons why you may be using the StoredIdConnector but may also wish to move away from it.
In moving away to a purely ComputedIdConnector you risk losing the existing persistent IDs that your users may be relying on to get access to resources.
Configuration Changes
It’s possible to configure the IdP to:
Check the existing StoredID database for a value and return it if present
If a value is not present, request one from the ComputedID generator instead
An approximation in pseudo-code:
...
This example uses SQLite as a target database engine for the (read-only) data set. Firstly because it’s really simple. Secondly, if you’re making this jump then no “new” data will be added to the database so the file can be statically deployed to your IdP nodes with no need to worry about another RDBMS and replication etc.
Starting
...
Point
This assumes you have a working StoredID connector servicing requests for persistent IDs, for example:
Code Block | ||
---|---|---|
| ||
<DataConnector xsi:type="StoredId" id="storedID" generatedAttributeID="storedID" exportAttributes="storedID" salt='%{idp.persistentId.salt}'> <InputAttributeDefinition ref="uid" /> <BeanManagedConnection>sqlite-dataconnector</BeanManagedConnection> </DataConnector> <AttributeDefinition id="eduPersonTargetedID" xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"> <InputDataConnector ref="storedID" attributeNames="storedID"/> <AttributeEncoder xsi:type="SAML2XMLObject" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" friendlyName="eduPersonTargetedID" /> </AttributeDefinition> |
This configuration will be happily servicing requests for eduPersonTargetedID
producing values by first looking them up in the database, returning the value if it’s present and, otherwise, generating one, storing it and returning it. These values may be used for seeding SAML 2.0 persistent NameIDs or the new pairwise-id SAML Attribute.
Changes
Switching this basic config to the desired model… I’ve switched from the examples generating storedID
to persistentId
as it’s more descriptive.
Add the ComputedID
...
Connector
Code Block | ||
---|---|---|
| ||
<DataConnector xsi:type="ComputedId" id="computedIDcomputedId" generatedAttributeID="persistentId" exportAttributes="persistentId" salt='%{idp.persistentId.salt}'> <InputAttributeDefinition ref="uid" /> </DataConnector> |
Be sure to use the same Saltsalt, which may be configured as a property elsewhere.
Add the new
...
RelationalDatabase Connector
Code Block | ||
---|---|---|
| ||
<DataConnector id="sqlite-db" xsi:type="RelationalDatabase" noResultIsError="true" exportAttributes="persistentId"> <FailoverDataConnector ref="computedIDcomputedId"/> <SimpleManagedConnection jdbcDriver="%{datasource.driverClass}" jdbcURL="%{datasource.jdbcUrl}" /> <QueryTemplate> <![CDATA[ SELECT persistentId FROM shibpid WHERE peerEntity='$resolutionContext.attributeRecipientID' AND principalName='$resolutionContext.principal'; ]]> </QueryTemplate> <Column columnName="persistentId" attributeID="persistentId" /> </DataConnector> |
...
The SELECT
statement looks up the required value based on the requesting Service Provider and the principal already. You may need to tweak this for your setup depending on what’s being used now.
Update
...
any Dependent Settings
In this step, adjust any dependent Attribute Definitions or NameID generation properties to reference to new “persistentId” attribute.
Reviewing Existing Data for Mismatches
It’s possible to get the RDBMS to evaluate all your existing records and report which are wrong (in that if they were regenerated now, the persistentId
would be different).
This process is specifically for MySQL but the general principle should port to other database engines (the function calls may be different!). I’ve also assumed that you’re using BASE64
and SHA1
so you may need to tweak the query for your specific circumstances.
Create a temporary table with salt
In creating a TEMPORARY
table, the data stays in memory only, doesn’t persist outside of the session you’re using and isn’t written to transaction logs.
Code Block | ||
---|---|---|
| ||
<!-- OLD -->
<InputDataConnector ref="storedID" attributeNames="storedID"/>
<!-- NEW -->
<InputDataConnector ref="sqlite-db" attributeNames="persistentId"/> |
...
| |
CREATE TEMPORARY TABLE salt (
id integer primary key not null,
salt varchar(1024)
);
INSERT INTO salt VALUES (0, 'EXISTING SALT VALUE'); |
Compare the data
This query recalculates the persistentId
for all existing records in the database and compares that with the one already in the database and only reports mismatches:
Code Block | ||||
---|---|---|---|---|
| <AttributeDefinition id="eduPersonTargetedID" xsi:type="SAML2NameID"
| |||
SELECT * FROM ( SELECT c.localEntity, nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">c.peerEntity, <InputDataConnector ref="sqlite-db" attributeNames="persistentId"/> c.persistentId, c.principalName, <AttributeEncoder xsi:type="SAML2XMLObject" c.localId, name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" friendlyName="eduPersonTargetedID" /> </AttributeDefinition>c.creationDate, TO_BASE64( UNHEX( SHA1( CONCAT( c.peerEntity, '!', c.localId, '!', s.salt ) ) ) ) as computedId FROM shibpid c JOIN salt s WHERE s.id=0 ) generate_pids WHERE persistentId <> computedId; |