[java-identity-provider] branch master updated: IDP-1413 - Clean up StoredID support classes/interfaces/beans
Scott Cantor
cantor.2 at osu.edu
Tue Feb 19 10:57:18 EST 2019
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=cb727a9cc25e0898ae8e2f88f6f429c5dbf5322d
The following commit(s) were added to refs/heads/master by this push:
new cb727a9 IDP-1413 - Clean up StoredID support classes/interfaces/beans
cb727a9 is described below
commit cb727a9cc25e0898ae8e2f88f6f429c5dbf5322d
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Feb 19 10:57:11 2019 -0500
IDP-1413 - Clean up StoredID support classes/interfaces/beans
https://issues.shibboleth.net/jira/browse/IDP-1413
Redesigned class hierarchy and updated parsers and wiring.
---
.../idp/attribute/DurablePairwiseIdStore.java | 72 ++++
.../net/shibboleth/idp/attribute/PairwiseId.java | 104 +++---
.../shibboleth/idp/attribute/PairwiseIdStore.java | 50 +++
idp-attribute-impl/.checkstyle | 15 +
idp-attribute-impl/.classpath | 38 ++
idp-attribute-impl/.gitignore | 21 ++
idp-attribute-impl/.project | 40 ++
.../.settings/org.eclipse.core.resources.prefs | 6 +
.../.settings/org.eclipse.jdt.core.prefs | 351 ++++++++++++++++++
.../.settings/org.eclipse.jdt.ui.prefs | 63 ++++
.../.settings/org.eclipse.m2e.core.prefs | 4 +
idp-attribute-impl/checkstyle.xml | 116 ++++++
idp-attribute-impl/pom.xml | 48 +++
idp-attribute-impl/src/main/java/.gitkeep | 0
.../attribute/impl/ComputedPairwiseIdStore.java | 75 ++--
.../idp/attribute/impl/JDBCPairwiseIdStore.java | 404 +++++++++++----------
.../idp/attribute/impl/package-info.java | 22 ++
idp-attribute-impl/src/main/resources/.gitkeep | 0
idp-attribute-impl/src/test/java/.gitkeep | 0
.../impl/ComputedPairwiseIdStoreTest.java | 168 +++++++++
.../attribute/impl/JDBCPairwiseIdStoreTest.java | 94 +++--
.../src/test/resources/logback-test.xml | 17 +
.../shibboleth/idp/attribute/impl/DeleteStore.sql | 1 +
.../idp/attribute/impl/StoredIdStore.sql | 11 +
.../resolver/dc/impl/PairwiseIdDataConnector.java | 310 ++++++++++++++++
.../dc/impl/ComputedIDDataConnectorTest.java | 115 +++---
.../dc/impl/StoredIDDataConnectorTest.java | 126 ++-----
idp-attribute-resolver-spring/pom.xml | 10 +
.../dc/impl/ComputedIDDataConnectorParser.java | 62 +++-
...ser.java => PairwiseIdDataConnectorParser.java} | 68 ++--
.../dc/impl/StoredIDDataConnectorParser.java | 81 ++---
.../dc/ComputedIDDataConnectorParserTest.java | 33 +-
.../resolver/spring/dc/ManagedConnectionTest.java | 47 +--
.../spring/dc/StoredIDDataConnectorParserTest.java | 40 +-
.../resources/system/conf/saml-nameid-system.xml | 14 +-
idp-parent/pom.xml | 1 +
idp-saml-impl/pom.xml | 5 +
.../resolver/impl/ComputedIDDataConnector.java | 237 ------------
.../resolver/impl/StoredIDDataConnector.java | 243 -------------
.../impl/PersistentIdGenerationStrategy.java | 48 ---
.../idp/saml/nameid/impl/PersistentIdStoreEx.java | 98 -----
.../impl/PersistentSAML2NameIDGenerator.java | 103 ++++--
.../nameid/impl/StoredPersistentIdDecoder.java | 42 ++-
.../impl/StoredPersistentIdGenerationStrategy.java | 140 -------
.../impl/PersistentSAML2NameIDGeneratorTest.java | 181 ++-------
.../nameid/impl/StoredPersistentIdDecoderTest.java | 9 +-
46 files changed, 2106 insertions(+), 1627 deletions(-)
diff --git a/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/DurablePairwiseIdStore.java b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/DurablePairwiseIdStore.java
new file mode 100644
index 0000000..d1cabe8
--- /dev/null
+++ b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/DurablePairwiseIdStore.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute;
+
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Extended {@link PairwiseIdStore} interface that supports reversal, mutation, and deactivation features
+ * requiring durable storage.
+ *
+ * @since 4.0.0
+ */
+public interface DurablePairwiseIdStore extends PairwiseIdStore {
+
+ /**
+ * Populate the underlying principal/source fields for the input object based on the
+ * supplied values.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param pid object to populate
+ *
+ * @return object for the given inputs or null if none exists
+ * @throws IOException if an error occurs accessing the store
+ */
+ @Nullable PairwiseId getByIssuedValue(@Nonnull final PairwiseId pid) throws IOException;
+
+ /**
+ * Deactivate/revoke a pairwise ID.
+ *
+ * <p>If the object's deactivation time field is null, then the current time is used.</p>
+ *
+ * @param pid the object to deactivate/revoke
+ *
+ * @throws IOException if there is an error updating the store
+ */
+ void deactivate(@Nonnull PairwiseId pid) throws IOException;
+
+ /**
+ * Attach a peer-supplied alias to a pairwise ID.
+ *
+ * @param pid the object to update in storage
+ *
+ * @throws IOException if there is an error updating the store
+ */
+ void attach(@Nonnull PairwiseId pid) throws IOException;
+
+}
\ No newline at end of file
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/PersistentIdEntry.java b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseId.java
similarity index 62%
rename from idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/PersistentIdEntry.java
rename to idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseId.java
index bcff909..36400c1 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/PersistentIdEntry.java
+++ b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseId.java
@@ -15,50 +15,48 @@
* limitations under the License.
*/
-package net.shibboleth.idp.saml.nameid;
-
-import java.io.Serializable;
-import java.sql.Timestamp;
+package net.shibboleth.idp.attribute;
import javax.annotation.Nullable;
-/** Object representing a persistent identifier entry in storage. */
-public class PersistentIdEntry implements Serializable {
-
- /** Serial version UID. */
- private static final long serialVersionUID = -8711779466442306767L;
+/**
+ * Object representing a pairwise/targeted identifier entry as a storage input/output.
+ *
+ * @since 4.0.0
+ */
+public class PairwiseId {
/** ID of the entity that issued that identifier. */
- @Nullable private String issuerEntityId;
+ @Nullable private String issuerEntityID;
/** ID of the entity to which the identifier was issued. */
- @Nullable private String recipientEntityId;
+ @Nullable private String recipientEntityID;
/** Name of the principal represented by the identifier. */
@Nullable private String principalName;
- /** Underlying source ID of the entry. */
- @Nullable private String sourceId;
+ /** Underlying unique key/ID of the principal. */
+ @Nullable private String sourceSystemId;
- /** The persistent identifier. */
- @Nullable private String persistentId;
+ /** The identifier. */
+ @Nullable private String pairwiseId;
- /** ID, associated with the persistent identifier, provided by the peer. */
+ /** A secondary identifier attached to the record by the recipient. */
@Nullable private String peerProvidedId;
/** Time the identifier was created. */
- @Nullable private Timestamp creationTime;
+ @Nullable private Long creationTime;
/** Time the identifier was deactivated. */
- @Nullable private Timestamp deactivationTime;
+ @Nullable private Long deactivationTime;
/**
* Get the ID of the entity that issued the identifier.
*
* @return ID of the entity that issued the identifier
*/
- @Nullable public String getIssuerEntityId() {
- return issuerEntityId;
+ @Nullable public String getIssuerEntityID() {
+ return issuerEntityID;
}
/**
@@ -66,8 +64,8 @@ public class PersistentIdEntry implements Serializable {
*
* @param id ID of the entity that issued the identifier
*/
- public void setIssuerEntityId(@Nullable final String id) {
- issuerEntityId = id;
+ public void setIssuerEntityID(@Nullable final String id) {
+ issuerEntityID = id;
}
/**
@@ -75,8 +73,8 @@ public class PersistentIdEntry implements Serializable {
*
* @return ID of the entity to which the identifier was issued
*/
- @Nullable public String getRecipientEntityId() {
- return recipientEntityId;
+ @Nullable public String getRecipientEntityID() {
+ return recipientEntityID;
}
/**
@@ -84,8 +82,8 @@ public class PersistentIdEntry implements Serializable {
*
* @param id ID of the entity to which the identifier was issued
*/
- public void setRecipientEntityId(@Nullable final String id) {
- recipientEntityId = id;
+ public void setRecipientEntityID(@Nullable final String id) {
+ recipientEntityID = id;
}
/**
@@ -107,39 +105,41 @@ public class PersistentIdEntry implements Serializable {
}
/**
- * Get the source ID underlying the persistent identifier.
+ * Get the underlying unique key/ID from the source IDM system, which may be more
+ * stable than the "name".
*
- * @return source ID underlying the persistent identifier
+ * @return the principal's unique key or ID
*/
- @Nullable public String getSourceId() {
- return sourceId;
+ @Nullable public String getSourceSystemId() {
+ return sourceSystemId;
}
/**
- * Set the source ID underlying the persistent identifier.
+ * Set the underlying unique key/ID from the source IDM system, which may be more
+ * stable than the "name".
*
- * @param id source ID underlying the persistent identifier
+ * @param id principal's unique key or ID
*/
- public void setSourceId(@Nullable final String id) {
- sourceId = id;
+ public void setSourceSystemId(@Nullable final String id) {
+ sourceSystemId = id;
}
/**
- * Get the persistent identifier.
+ * Get the pairwise identifier.
*
- * @return the persistent identifier
+ * @return the pairwise identifier
*/
- @Nullable public String getPersistentId() {
- return persistentId;
+ @Nullable public String getPairwiseId() {
+ return pairwiseId;
}
/**
- * Set the persistent identifier.
+ * Set the pairwise identifier.
*
- * @param id the persistent identifier
+ * @param id the pairwise identifier
*/
- public void setPersistentId(@Nullable final String id) {
- persistentId = id;
+ public void setPairwiseId(@Nullable final String id) {
+ pairwiseId = id;
}
/**
@@ -165,7 +165,7 @@ public class PersistentIdEntry implements Serializable {
*
* @return time the identifier was created
*/
- @Nullable public Timestamp getCreationTime() {
+ @Nullable public Long getCreationTime() {
return creationTime;
}
@@ -174,7 +174,7 @@ public class PersistentIdEntry implements Serializable {
*
* @param time time the identifier was created
*/
- public void setCreationTime(@Nullable final Timestamp time) {
+ public void setCreationTime(@Nullable final Long time) {
creationTime = time;
}
@@ -183,7 +183,7 @@ public class PersistentIdEntry implements Serializable {
*
* @return time the identifier was deactivated
*/
- @Nullable public Timestamp getDeactivationTime() {
+ @Nullable public Long getDeactivationTime() {
return deactivationTime;
}
@@ -192,22 +192,22 @@ public class PersistentIdEntry implements Serializable {
*
* @param time the time the identifier was deactivated
*/
- public void setDeactivationTime(@Nullable final Timestamp time) {
+ public void setDeactivationTime(@Nullable final Long time) {
deactivationTime = time;
}
/** {@inheritDoc} */
@Override
public String toString() {
- final StringBuilder stringForm = new StringBuilder("PersistentIdEntry{");
- stringForm.append("persistentId:").append(persistentId).append(", ");
- stringForm.append("localEntityId:").append(issuerEntityId).append(", ");
- stringForm.append("recipientEntityId:").append(recipientEntityId).append(", ");
- stringForm.append("sourceId:").append(sourceId).append(", ");
+ final StringBuilder stringForm = new StringBuilder("PairwiseId {");
+ stringForm.append("pairwiseId:").append(pairwiseId).append(", ");
+ stringForm.append("issuerEntityID:").append(issuerEntityID).append(", ");
+ stringForm.append("recipientEntityID:").append(recipientEntityID).append(", ");
+ stringForm.append("sourceSystemId:").append(sourceSystemId).append(", ");
stringForm.append("principalName:").append(principalName).append(", ");
stringForm.append("peerProvidedId:").append(peerProvidedId).append(", ");
stringForm.append("creationTime:").append(creationTime).append(", ");
- stringForm.append("deactivationTime:").append(deactivationTime).append(", ");
+ stringForm.append("deactivationTime:").append(deactivationTime);
stringForm.append("}");
return stringForm.toString();
}
diff --git a/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseIdStore.java b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseIdStore.java
new file mode 100644
index 0000000..2175bb8
--- /dev/null
+++ b/idp-attribute-api/src/main/java/net/shibboleth/idp/attribute/PairwiseIdStore.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute;
+
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Storage and retrieval interface for pairwise/targeted identifiers allowing for custom implementations.
+ *
+ * @since 4.0.0
+ */
+public interface PairwiseIdStore {
+
+ /**
+ * Populate the pairwise ID field for the input object based on the
+ * supplied values.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param pid object to populate
+ * @param allowCreate true iff the caller is authorizing the issuance of a new identifier
+ *
+ * @return object for the given inputs or null if none exists
+ * @throws IOException if an error occurs accessing the store
+ */
+ @Nullable PairwiseId getBySourceValue(@Nonnull final PairwiseId pid, final boolean allowCreate) throws IOException;
+
+}
\ No newline at end of file
diff --git a/idp-attribute-impl/.checkstyle b/idp-attribute-impl/.checkstyle
new file mode 100644
index 0000000..5ef9989
--- /dev/null
+++ b/idp-attribute-impl/.checkstyle
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+
+ <local-check-config name="Shibboleth Checkstyle" location="checkstyle.xml" type="project" description="">
+ <additional-data name="cache-file" value="true"/>
+ <additional-data name="cache-props-file-location" value="null_1312636288299_cache.properties"/>
+ <additional-data name="cache-file-location" value="null_1312636288299_cache.xml"/>
+ </local-check-config>
+
+ <fileset name="main source" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
+ <file-match-pattern match-pattern="src/main/java/.*\.java$" include-pattern="true"/>
+ </fileset>
+
+</fileset-config>
diff --git a/idp-attribute-impl/.classpath b/idp-attribute-impl/.classpath
new file mode 100644
index 0000000..4a3c7ea
--- /dev/null
+++ b/idp-attribute-impl/.classpath
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/idp-attribute-impl/.gitignore b/idp-attribute-impl/.gitignore
new file mode 100644
index 0000000..de41221
--- /dev/null
+++ b/idp-attribute-impl/.gitignore
@@ -0,0 +1,21 @@
+# A simulation of Subversion default ignores, generated by reposurgeon.
+*.o
+*.lo
+*.la
+*.al
+*.libs
+*.so
+*.so.[0-9]*
+*.a
+*.pyc
+*.pyo
+*.rej
+*.iml
+*~
+*.#*
+.*.swp
+.DS_store
+# Simulated Subversion default ignores end here
+
+/target
+/test-output
diff --git a/idp-attribute-impl/.project b/idp-attribute-impl/.project
new file mode 100644
index 0000000..93b9a0c
--- /dev/null
+++ b/idp-attribute-impl/.project
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>idp-attribute-impl</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.springframework.ide.eclipse.core.springbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.springframework.ide.eclipse.core.springnature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
diff --git a/idp-attribute-impl/.settings/org.eclipse.core.resources.prefs b/idp-attribute-impl/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..29abf99
--- /dev/null
+++ b/idp-attribute-impl/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/<project>=UTF-8
diff --git a/idp-attribute-impl/.settings/org.eclipse.jdt.core.prefs b/idp-attribute-impl/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..4537d67
--- /dev/null
+++ b/idp-attribute-impl/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,351 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=ignore
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=ignore
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=120
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/idp-attribute-impl/.settings/org.eclipse.jdt.ui.prefs b/idp-attribute-impl/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..86c79c4
--- /dev/null
+++ b/idp-attribute-impl/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,63 @@
+cleanup.add_default_serial_version_id=false
+cleanup.add_generated_serial_version_id=true
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=false
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=true
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_Shibboleth
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Shibboleth
+formatter_settings_version=11
+internal.default.compliance=default
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.overrideannotation=false
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return Returns the ${bare_field_name}.\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Commen [...]
diff --git a/idp-attribute-impl/.settings/org.eclipse.m2e.core.prefs b/idp-attribute-impl/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/idp-attribute-impl/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/idp-attribute-impl/checkstyle.xml b/idp-attribute-impl/checkstyle.xml
new file mode 100644
index 0000000..48ae807
--- /dev/null
+++ b/idp-attribute-impl/checkstyle.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+ This configuration file was written by the eclipse-cs plugin configuration editor
+-->
+<!--
+ Checkstyle-Configuration: Shibboleth Checkstyle
+ Description: none
+-->
+<module name="Checker">
+ <property name="severity" value="warning"/>
+ <module name="TreeWalker">
+ <property name="tabWidth" value="4"/>
+ <module name="JavadocMethod">
+ <property name="allowThrowsTagsForSubclasses" value="true"/>
+ <property name="allowUndeclaredRTE" value="true"/>
+ </module>
+ <module name="JavadocType">
+ <property name="allowUnknownTags" value="true"/>
+ </module>
+ <module name="JavadocVariable"/>
+ <module name="JavadocStyle">
+ <property name="checkEmptyJavadoc" value="true"/>
+ </module>
+ <module name="ConstantName"/>
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+ <module name="AvoidStarImport"/>
+ <module name="IllegalImport"/>
+ <module name="RedundantImport"/>
+ <module name="UnusedImports"/>
+ <module name="LineLength">
+ <property name="max" value="120"/>
+ </module>
+ <module name="MethodLength">
+ <property name="max" value="70"/>
+ </module>
+ <module name="ParameterNumber">
+ <property name="max" value="5"/>
+ </module>
+ <module name="EmptyForIteratorPad"/>
+ <module name="MethodParamPad"/>
+ <module name="ModifierOrder"/>
+ <module name="AvoidNestedBlocks"/>
+ <module name="LeftCurly"/>
+ <module name="NeedBraces"/>
+ <module name="RightCurly"/>
+ <module name="EmptyStatement"/>
+ <module name="EqualsHashCode"/>
+ <module name="HiddenField"/>
+ <module name="IllegalInstantiation"/>
+ <module name="InnerAssignment"/>
+ <module name="MissingSwitchDefault"/>
+ <module name="SimplifyBooleanExpression"/>
+ <module name="SimplifyBooleanReturn"/>
+ <module name="FinalClass"/>
+ <module name="HideUtilityClassConstructor"/>
+ <module name="VisibilityModifier"/>
+ <module name="ArrayTypeStyle"/>
+ <module name="UpperEll"/>
+ <module name="AnonInnerLength"/>
+ <module name="EmptyForInitializerPad"/>
+ <module name="CovariantEquals"/>
+ <module name="DefaultComesLast"/>
+ <module name="DeclarationOrder"/>
+ <module name="ExplicitInitialization"/>
+ <module name="FallThrough"/>
+ <module name="IllegalThrows"/>
+ <module name="MultipleVariableDeclarations"/>
+ <module name="PackageDeclaration"/>
+ <module name="ParameterAssignment"/>
+ <module name="ReturnCount">
+ <property name="max" value="8"/>
+ <property name="maxForVoid" value="8"/>
+ </module>
+ <module name="StringLiteralEquality"/>
+ <module name="SuperFinalize"/>
+ <module name="ArrayTrailingComma"/>
+ <module name="UnnecessaryParentheses"/>
+ <module name="MutableException"/>
+ <module name="ThrowsCount">
+ <property name="max" value="3"/>
+ </module>
+ <module name="CyclomaticComplexity"/>
+ <module name="TrailingComment"/>
+ <module name="EqualsAvoidNull"/>
+ <module name="ModifiedControlVariable"/>
+ <module name="FinalParameters">
+ <property name="tokens" value="METHOD_DEF,CTOR_DEF,LITERAL_CATCH"/>
+ </module>
+ <module name="FinalLocalVariable">
+ <property name="tokens" value="PARAMETER_DEF,VARIABLE_DEF"/>
+ <property name="validateEnhancedForLoopVariable" value="true"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="\bCheck[Ss]tyle:\s*([\w|]+)\s+OFF\b"/>
+ <property name="onCommentFormat" value="\bCheck[Ss]tyle:\s*([\w|]+)\s+ON\b"/>
+ <property name="checkFormat" value="$1"/>
+ </module>
+ </module>
+ <module name="FileTabCharacter"/>
+ <module name="FileLength">
+ <property name="max" value="1000"/>
+ </module>
+ <module name="Header">
+ <property name="header" value="/*\n * Licensed to the University Corporation for Advanced Internet Development,\n * Inc. (UCAID) under one or more contributor license agreements. See the\n * NOTICE file distributed with this work for additional information regarding\n * copyright ownership. The UCAID licenses this file to You under the Apache\n * License, Version 2.0 (the "License"); you may not use this file except in\n * compliance with the License. You may obtain a cop [...]
+ </module>
+ <module name="JavadocPackage"/>
+</module>
diff --git a/idp-attribute-impl/pom.xml b/idp-attribute-impl/pom.xml
new file mode 100644
index 0000000..a5329d5
--- /dev/null
+++ b/idp-attribute-impl/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.shibboleth.idp</groupId>
+ <artifactId>idp-parent</artifactId>
+ <version>4.0.0-SNAPSHOT</version>
+ <relativePath>../idp-parent</relativePath>
+ </parent>
+
+ <name>Shibboleth IdP :: Attribute Implementation</name>
+ <description>Attribute Implementation</description>
+ <artifactId>idp-attribute-impl</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <!-- Compile Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>idp-attribute-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Provided Dependencies -->
+
+ <!-- Runtime Dependencies -->
+
+ <!-- Test Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>idp-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Managed Dependencies -->
+ </dependencies>
+
+</project>
diff --git a/idp-attribute-impl/src/main/java/.gitkeep b/idp-attribute-impl/src/main/java/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
similarity index 80%
rename from idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java
rename to idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
index cb0dc4c..75c32e2 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java
+++ b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
@@ -15,8 +15,9 @@
* limitations under the License.
*/
-package net.shibboleth.idp.saml.nameid.impl;
+package net.shibboleth.idp.attribute.impl;
+import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
@@ -26,6 +27,8 @@ import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.PairwiseIdStore;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.codec.Base32Support;
@@ -36,26 +39,26 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
-import org.opensaml.saml.common.SAMLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The basis of a {@link PersistentIdGenerationStrategy} that generates a unique ID by computing the hash of
- * a given attribute value, the entity ID of the inbound message issuer, and a provided salt.
+ * A {@link PairwiseIdStore} that generates a pairwise ID by computing the hash of
+ * a given attribute value, the entity ID of the recipient, and a provided salt.
*
* <p>The original implementation and values in common use relied on base64 encoding of the result,
* but due to discovery of the lack of appropriate case handling of identifiers by applications, the
- * ability to use base32 has been added to eliminate the possibility of case conflicts.</p>
+ * ability to use base32 has been added to eliminate the possibility of case conflicts.</p>
+ *
+ * @since 4.0.0
*/
-public class ComputedPersistentIdGenerationStrategy extends AbstractInitializableComponent
- implements PersistentIdGenerationStrategy {
+public class ComputedPairwiseIdStore extends AbstractInitializableComponent implements PairwiseIdStore {
/** An override trigger to apply to all relying parties. */
@Nonnull @NotEmpty public static final String WILDCARD_OVERRIDE = "*";
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(ComputedPersistentIdGenerationStrategy.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(ComputedPairwiseIdStore.class);
/** Post-digest encoding types. */
public enum Encoding {
@@ -79,7 +82,7 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
@Nonnull private Map<String,Map<String,String>> exceptionMap;
/** Constructor. */
- public ComputedPersistentIdGenerationStrategy() {
+ public ComputedPairwiseIdStore() {
algorithm = "SHA";
encoding = Encoding.BASE64;
exceptionMap = Collections.emptyMap();
@@ -110,13 +113,26 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
}
/**
- * Set the base64-encoded salt used when computing the ID.
+ * Set the salt used when computing the ID.
*
* <p>An empty/null input is ignored.</p>
*
* @param newValue used when computing the ID
+ */
+ public void setSalt(@Nullable final String newValue) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ if (newValue != null && !newValue.isEmpty()) {
+ salt = newValue.getBytes();
+ }
+ }
+
+ /**
+ * Set the base64-encoded salt used when computing the ID.
+ *
+ * <p>An empty/null input is ignored.</p>
*
- * @since 3.3.0
+ * @param newValue used when computing the ID
*/
public void setEncodedSalt(@Nullable final String newValue) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
@@ -130,8 +146,6 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
* Get the JCE algorithm name of the digest algorithm to use (default is SHA).
*
* @return JCE message digest algorithm
- *
- * @since 3.4.0
*/
@Nonnull @NotEmpty public String getAlgorithm() {
return algorithm;
@@ -152,8 +166,6 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
* Get the post-digest encoding to use.
*
* @return encoding
- *
- * @since 3.4.0
*/
@Nonnull public Encoding getEncoding() {
return encoding;
@@ -217,37 +229,42 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
throw new ComponentInitializationException("Salt must be at least 16 bytes in size");
}
}
-
+
/** {@inheritDoc} */
- @Override
- @Nonnull @NotEmpty public String generate(@Nonnull @NotEmpty final String assertingPartyId,
- @Nonnull @NotEmpty final String relyingPartyId, @Nonnull @NotEmpty final String principalName,
- @Nonnull @NotEmpty final String sourceId) throws SAMLException {
+ @Nullable public PairwiseId getBySourceValue(@Nonnull final PairwiseId pid, final boolean allowCreate)
+ throws IOException {
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- final byte[] effectiveSalt = getEffectiveSalt(principalName, relyingPartyId);
+ Constraint.isNotNull(pid, "Input PairwiseId object cannot be null");
+ Constraint.isNotEmpty(pid.getRecipientEntityID(), "Recipient entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPrincipalName(), "Principal name cannot be null or empty");
+ Constraint.isNotEmpty(pid.getSourceSystemId(), "Source system ID cannot be null or empty");
+
+ final byte[] effectiveSalt = getEffectiveSalt(pid.getPrincipalName(), pid.getRecipientEntityID());
if (effectiveSalt == null) {
- throw new SAMLException("Generation blocked by exception rule");
+ log.warn("Pairwise ID generation blocked for relying party ({})", pid.getRecipientEntityID());
+ throw new IOException("Pairwise ID generation blocked by exception rule");
}
try {
final MessageDigest md = MessageDigest.getInstance(algorithm);
- md.update(relyingPartyId.getBytes());
+ md.update(pid.getRecipientEntityID().getBytes());
md.update((byte) '!');
- md.update(sourceId.getBytes());
+ md.update(pid.getSourceSystemId().getBytes());
md.update((byte) '!');
if (encoding == Encoding.BASE32) {
- return Base32Support.encode(md.digest(effectiveSalt), Base32Support.UNCHUNKED);
+ pid.setPairwiseId(Base32Support.encode(md.digest(effectiveSalt), Base32Support.UNCHUNKED));
} else if (encoding == Encoding.BASE64) {
- return Base64Support.encode(md.digest(effectiveSalt), Base64Support.UNCHUNKED);
+ pid.setPairwiseId(Base64Support.encode(md.digest(effectiveSalt), Base64Support.UNCHUNKED));
} else {
- throw new SAMLException("Desired encoding was not recognized, unable to compute ID");
+ throw new IOException("Desired encoding was not recognized, unable to compute ID");
}
} catch (final NoSuchAlgorithmException e) {
log.error("Digest algorithm {} is not supported", algorithm);
- throw new SAMLException("Digest algorithm was not supported, unable to compute ID", e);
+ throw new IOException("Digest algorithm was not supported, unable to compute ID", e);
}
+
+ return pid;
}
/**
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/JDBCPersistentIdStoreEx.java b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStore.java
similarity index 67%
rename from idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/JDBCPersistentIdStoreEx.java
rename to idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStore.java
index c170133..dd44c7f 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/JDBCPersistentIdStoreEx.java
+++ b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStore.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.saml.nameid.impl;
+package net.shibboleth.idp.attribute.impl;
import java.io.IOException;
import java.sql.Connection;
@@ -34,7 +34,9 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.sql.DataSource;
-import net.shibboleth.idp.saml.nameid.PersistentIdEntry;
+import net.shibboleth.idp.attribute.DurablePairwiseIdStore;
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.PairwiseIdStore;
import net.shibboleth.utilities.java.support.annotation.Duration;
import net.shibboleth.utilities.java.support.annotation.constraint.Live;
import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
@@ -47,15 +49,13 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
-import org.joda.time.DateTime;
-import org.opensaml.saml.common.SAMLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * JDBC-based storage management for SAML persistent IDs.
+ * JDBC-based storage management for pairwise IDs.
*
- * <p>The general DDL for the database is:
+ * <p>The general DDL for the database, which is unchanged for compatibility, is:</p>
*
* <pre>
* CREATE TABLE shibpid (
@@ -70,13 +70,15 @@ import org.slf4j.LoggerFactory;
* PRIMARY KEY (localEntity, peerEntity, persistentId)
* );</pre>.
*
- * The first three columns should be defined as the primary key of the table, and the other columns
+ * <p>The first three columns should be defined as the primary key of the table, and the other columns
* should be indexed.</p>
+ *
+ * @since 4.0.0
*/
-public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent implements PersistentIdStoreEx {
+public class JDBCPairwiseIdStore extends AbstractInitializableComponent implements DurablePairwiseIdStore {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(JDBCPersistentIdStoreEx.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(JDBCPairwiseIdStore.class);
/** JDBC data source for retrieving connections. */
@NonnullAfterInit private DataSource dataSource;
@@ -137,9 +139,12 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
/** Parameterized delete statement used to clear dummy rows after verification. */
@NonnullAfterInit private String deleteSQL;
+
+ /** Optional hook for obtaining initial values from a primary store, usually a computed algorithm. */
+ @Nullable private PairwiseIdStore initialValueStore;
/** Constructor. */
- public JDBCPersistentIdStoreEx() {
+ public JDBCPairwiseIdStore() {
transactionRetry = 3;
retryableErrors = Arrays.asList("23000", "23505");
queryTimeout = 5000;
@@ -437,6 +442,29 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
deleteSQL = Constraint.isNotNull(StringSupport.trimOrNull(sql), "SQL statement cannot be null or empty");
}
+
+ /**
+ * Get a store to use to produce the first value for a given issuer/recipient pair.
+ *
+ * @return initial value source
+ */
+ @Nullable public PairwiseIdStore getInitialValueStore() {
+ return initialValueStore;
+ }
+
+ /**
+ * Set a store to use to produce the first value for a given issuer/recipient pair.
+ *
+ * <p>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.</p>
+ *
+ * @param store initial value source
+ */
+ public void setInitialValueStore(@Nullable final PairwiseIdStore store) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ initialValueStore = store;
+ }
/** {@inheritDoc} */
@Override
@@ -444,7 +472,7 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
super.doInitialize();
if (null == dataSource) {
- throw new ComponentInitializationException(getLogPrefix() + " No database connection provided");
+ throw new ComponentInitializationException("DataSource cannot be null");
}
if (getByIssuedSelectSQL == null) {
@@ -492,181 +520,179 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
try {
verifyDatabase();
- log.info("{} Data source successfully verified", getLogPrefix());
+ log.info("DataSource successfully verified");
} catch (final SQLException e) {
if (verifyDatabase) {
- log.error("{} Exception verifying database", getLogPrefix(), e);
+ log.error("Exception verifying database", e);
throw new ComponentInitializationException(
"The database was not reachable or was not defined with an appropriate table + primary key");
} else {
- log.warn("{} The database was not reachable or was not defined with an appropriate table + primary key",
- getLogPrefix(), e);
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- @Nullable public PersistentIdEntry getByIssuedValue(@Nonnull @NotEmpty final String nameQualifier,
- @Nonnull @NotEmpty final String spNameQualifier, @Nonnull @NotEmpty final String persistentId)
- throws IOException {
- ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- log.debug("{} Selecting previously issued persistent ID entry", getLogPrefix(), getByIssuedSelectSQL);
-
- log.trace("{} Prepared statement: {}", getLogPrefix(), getByIssuedSelectSQL);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 1, nameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 2, spNameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 3, persistentId);
-
- try (final Connection dbConn = getConnection(true)) {
- final PreparedStatement statement = dbConn.prepareStatement(getByIssuedSelectSQL);
- statement.setQueryTimeout((int) (queryTimeout / 1000));
-
- statement.setString(1, nameQualifier);
- statement.setString(2, spNameQualifier);
- statement.setString(3, persistentId);
-
- final List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
-
- if (entries == null || entries.size() == 0) {
- return null;
+ log.warn("The database was not reachable or was not defined with an appropriate table + primary key",e);
}
-
- if (entries.size() > 1) {
- log.warn("{} More than one record found, only the first will be returned", getLogPrefix());
- }
-
- return entries.get(0);
- } catch (final SQLException e) {
- throw new IOException(e);
}
}
-// Checkstyle: MethodLength|CyclomaticComplexity|ParameterNumber OFF
+ // Checkstyle: MethodLength|CyclomaticComplexity OFF
/** {@inheritDoc} */
- @Override
- @Nullable public PersistentIdEntry getBySourceValue(@Nonnull @NotEmpty final String nameQualifier,
- @Nonnull @NotEmpty final String spNameQualifier, @Nonnull @NotEmpty final String sourceId,
- @Nonnull @NotEmpty final String principal, final boolean allowCreate,
- @Nullable final ComputedPersistentIdGenerationStrategy computedIdStrategy) throws IOException {
+ @Nullable public PairwiseId getBySourceValue(@Nonnull final PairwiseId pid, final boolean allowCreate)
+ throws IOException {
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- log.debug("{} Obtaining persistent ID for source ID: {}", getLogPrefix(), sourceId);
-
- log.trace("{} Prepared statement: {}", getLogPrefix(), getBySourceSelectSQL);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 1, nameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 2, spNameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 3, sourceId);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 4, nameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 5, spNameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 6, sourceId);
+ Constraint.isNotNull(pid, "Input PairwiseId object cannot be null");
+ Constraint.isNotEmpty(pid.getIssuerEntityID(), "Issuer entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getRecipientEntityID(), "Recipient entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPrincipalName(), "Principal name cannot be null or empty");
+ Constraint.isNotEmpty(pid.getSourceSystemId(), "Source system ID cannot be null or empty");
+
+ log.debug("Obtaining pairwise ID for source ID: {}", pid.getSourceSystemId());
+
+ log.trace("Prepared statement: {}", getBySourceSelectSQL);
+ log.trace("Setting prepared statement parameter {}: {}", 1, pid.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 2, pid.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 3, pid.getSourceSystemId());
+ log.trace("Setting prepared statement parameter {}: {}", 4, pid.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 5, pid.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 6, pid.getSourceSystemId());
int retries = transactionRetry;
while (true) {
try (final Connection dbConn = getConnection(false)) {
final PreparedStatement statement = dbConn.prepareStatement(getBySourceSelectSQL);
statement.setQueryTimeout((int) (queryTimeout / 1000));
- statement.setString(1, nameQualifier);
- statement.setString(2, spNameQualifier);
- statement.setString(3, sourceId);
- statement.setString(4, nameQualifier);
- statement.setString(5, spNameQualifier);
- statement.setString(6, sourceId);
-
- log.debug("{} Getting active and/or last inactive persistent Id entry", getLogPrefix());
- final List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
+ statement.setString(1, pid.getIssuerEntityID());
+ statement.setString(2, pid.getRecipientEntityID());
+ statement.setString(3, pid.getSourceSystemId());
+ statement.setString(4, pid.getIssuerEntityID());
+ statement.setString(5, pid.getRecipientEntityID());
+ statement.setString(6, pid.getSourceSystemId());
+
+ log.debug("Getting active and/or last inactive pairwise ID entry");
+ final List<PairwiseId> entries = buildIdentifierEntries(statement.executeQuery());
if (entries != null && entries.size() > 0 && (entries.get(0).getDeactivationTime() == null
- || entries.get(0).getDeactivationTime().getTime() > System.currentTimeMillis())) {
- log.debug("{} Returning existing active persistent ID: {}", getLogPrefix(),
- entries.get(0).getPersistentId());
+ || entries.get(0).getDeactivationTime() > System.currentTimeMillis())) {
dbConn.commit();
+ log.debug("Returning existing active pairwise ID: {}", entries.get(0).getPairwiseId());
return entries.get(0);
} else if (!allowCreate) {
- log.debug("{} No existing persistent ID and creation is not permitted", getLogPrefix());
dbConn.commit();
+ log.debug("No existing pairwise ID and creation is not permitted by caller");
return null;
}
- final PersistentIdEntry newEntry = new PersistentIdEntry();
- newEntry.setIssuerEntityId(nameQualifier);
- newEntry.setRecipientEntityId(spNameQualifier);
- newEntry.setSourceId(sourceId);
- newEntry.setPrincipalName(principal);
- newEntry.setCreationTime(new Timestamp(System.currentTimeMillis()));
-
- if ((entries == null || entries.size() == 0) && computedIdStrategy != null) {
- log.debug("{} Issuing new computed persistent ID", getLogPrefix());
- newEntry.setPersistentId(
- computedIdStrategy.generate(nameQualifier, spNameQualifier, principal, sourceId));
+ pid.setCreationTime(System.currentTimeMillis());
+
+ // Circumvent final modifier on parameter.
+ PairwiseId retValue = pid;
+
+ if ((entries == null || entries.size() == 0) && initialValueStore != null) {
+ log.debug("Issuing new pairwise ID using initial value store");
+ retValue = initialValueStore.getBySourceValue(pid, allowCreate);
} else {
- log.debug("{} Issuing new random persistent ID", getLogPrefix());
- newEntry.setPersistentId(UUID.randomUUID().toString());
+ log.debug("Issuing new random pairwise ID");
+ retValue.setPairwiseId(UUID.randomUUID().toString());
if (entries != null && entries.size() > 0) {
- newEntry.setPeerProvidedId(entries.get(0).getPeerProvidedId());
+ retValue.setPeerProvidedId(entries.get(0).getPeerProvidedId());
}
}
- store(newEntry, dbConn);
+ store(retValue, dbConn);
dbConn.commit();
- return newEntry;
+ return retValue;
} catch (final SQLException e) {
boolean retry = false;
for (final String msg : retryableErrors) {
if (e.getSQLState() != null && e.getSQLState().contains(msg)) {
- log.warn("{} Caught retryable SQL exception", getLogPrefix(), e);
+ log.warn("Caught retryable SQL exception", e);
retry = true;
+ break;
}
}
if (retry) {
if (--retries < 0) {
- log.warn("{} Error retryable, but retry limit exceeded", getLogPrefix());
+ log.warn("Error retryable, but retry limit exceeded");
throw new IOException(e);
} else {
- log.info("{} Retrying persistent ID lookup/create operation", getLogPrefix());
+ log.info("Retrying pairwise ID lookup/create operation");
}
} else {
throw new IOException(e);
}
- } catch (final SAMLException e) {
- throw new IOException(e);
}
}
}
-// Checkstyle: MethodLength|CyclomaticComplexity|ParameterNumber ON
+// Checkstyle: MethodLength|CyclomaticComplexity ON
/** {@inheritDoc} */
- @Override
- public void deactivate(@Nonnull @NotEmpty final String nameQualifier,
- @Nonnull @NotEmpty final String spNameQualifier, @Nonnull @NotEmpty final String persistentId,
- @Nullable final DateTime deactivation) throws IOException {
+ @Nullable public PairwiseId getByIssuedValue(@Nonnull final PairwiseId pid) throws IOException {
+ ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ Constraint.isNotNull(pid, "Input PairwiseId object cannot be null");
+ Constraint.isNotEmpty(pid.getIssuerEntityID(), "Issuer entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getRecipientEntityID(), "Recipient entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPairwiseId(), "Pairwise ID cannot be null or empty");
+
+ log.debug("Selecting previously issued pairwise ID entry", getByIssuedSelectSQL);
+
+ log.trace("Prepared statement: {}", getByIssuedSelectSQL);
+ log.trace("Setting prepared statement parameter {}: {}", 1, pid.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 2, pid.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 3, pid.getPairwiseId());
+
+ try (final Connection dbConn = getConnection(true)) {
+ final PreparedStatement statement = dbConn.prepareStatement(getByIssuedSelectSQL);
+ statement.setQueryTimeout((int) (queryTimeout / 1000));
+
+ statement.setString(1, pid.getIssuerEntityID());
+ statement.setString(2, pid.getRecipientEntityID());
+ statement.setString(3, pid.getPairwiseId());
+
+ final List<PairwiseId> entries = buildIdentifierEntries(statement.executeQuery());
+
+ if (entries == null || entries.size() == 0) {
+ return null;
+ }
+
+ if (entries.size() > 1) {
+ log.warn("More than one record found, only the first will be returned");
+ }
+
+ return entries.get(0);
+ } catch (final SQLException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void deactivate(@Nonnull final PairwiseId pid) throws IOException {
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ Constraint.isNotNull(pid, "Input PairwiseId object cannot be null");
+ Constraint.isNotEmpty(pid.getIssuerEntityID(), "Issuer entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getRecipientEntityID(), "Recipient entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPairwiseId(), "Pairwise ID cannot be null or empty");
final Timestamp deactivationTime;
- if (deactivation == null) {
+ if (pid.getDeactivationTime() == null) {
deactivationTime = new Timestamp(System.currentTimeMillis());
} else {
- deactivationTime = new Timestamp(deactivation.getMillis());
+ deactivationTime = new Timestamp(pid.getDeactivationTime());
}
- log.debug("Deactivating persistent id {} as of {}", persistentId, deactivationTime);
+ log.debug("Deactivating pairwise ID {} as of {}", pid.getPairwiseId(), deactivationTime);
- log.trace("{} Prepared statement: {}", getLogPrefix(), deactivateSQL);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 1, deactivationTime);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 2, nameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 3, spNameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 4, persistentId);
+ log.trace("Prepared statement: {}", deactivateSQL);
+ log.trace("Setting prepared statement parameter {}: {}", 1, deactivationTime);
+ log.trace("Setting prepared statement parameter {}: {}", 2, pid.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 3, pid.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 4, pid.getPairwiseId());
try (final Connection dbConn = getConnection(true)) {
final PreparedStatement statement = dbConn.prepareStatement(deactivateSQL);
statement.setQueryTimeout((int) (queryTimeout / 1000));
statement.setTimestamp(1, deactivationTime);
- statement.setString(2, nameQualifier);
- statement.setString(3, spNameQualifier);
- statement.setString(4, persistentId);
+ statement.setString(2, pid.getIssuerEntityID());
+ statement.setString(3, pid.getRecipientEntityID());
+ statement.setString(4, pid.getPairwiseId());
final int rowCount = statement.executeUpdate();
if (rowCount != 1) {
- log.warn("{} Unexpected result, statement affected {} rows", getLogPrefix(), rowCount);
+ log.warn("Unexpected result, statement affected {} rows", rowCount);
}
} catch (final SQLException e) {
@@ -675,37 +701,39 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
}
/** {@inheritDoc} */
- @Override
- public void attach(@Nonnull @NotEmpty final String nameQualifier, @Nonnull @NotEmpty final String spNameQualifier,
- @Nonnull @NotEmpty final String persistentId, @Nonnull @NotEmpty final String spProvidedId)
- throws IOException {
+ public void attach(@Nonnull final PairwiseId pid) throws IOException {
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ Constraint.isNotNull(pid, "Input PairwiseId object cannot be null");
+ Constraint.isNotEmpty(pid.getIssuerEntityID(), "Issuer entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getRecipientEntityID(), "Recipient entityID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPairwiseId(), "Pairwise ID cannot be null or empty");
+ Constraint.isNotEmpty(pid.getPeerProvidedId(), "Peer-provided ID cannot be null or empty");
- log.debug("Attaching SPProvidedID {} to persistent id {}", spProvidedId, persistentId);
+ log.debug("Attaching peer-provided ID {} to pairwise id {}", pid.getPeerProvidedId(), pid.getPairwiseId());
- log.trace("{} Prepared statement: {}", getLogPrefix(), attachSQL);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 1, spProvidedId);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 2, nameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 3, spNameQualifier);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 4, persistentId);
+ log.trace("Prepared statement: {}", attachSQL);
+ log.trace("Setting prepared statement parameter {}: {}", 1, pid.getPeerProvidedId());
+ log.trace("Setting prepared statement parameter {}: {}", 2, pid.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 3, pid.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 4, pid.getPairwiseId());
try (final Connection dbConn = getConnection(true)) {
final PreparedStatement statement = dbConn.prepareStatement(attachSQL);
statement.setQueryTimeout((int) (queryTimeout / 1000));
- statement.setString(1, spProvidedId);
- statement.setString(2, nameQualifier);
- statement.setString(3, spNameQualifier);
- statement.setString(4, persistentId);
+ statement.setString(1, pid.getPeerProvidedId());
+ statement.setString(2, pid.getIssuerEntityID());
+ statement.setString(3, pid.getRecipientEntityID());
+ statement.setString(4, pid.getPairwiseId());
final int rowCount = statement.executeUpdate();
if (rowCount != 1) {
- log.warn("{} Unexpected result, statement affected {} rows", getLogPrefix(), rowCount);
+ log.warn("Unexpected result, statement affected {} rows", rowCount);
}
} catch (final SQLException e) {
throw new IOException(e);
}
}
-// Checkstyle: MethodLength|CyclomaticComplexity|ParameterNumber ON
+// Checkstyle: MethodLength|CyclomaticComplexity ON
/**
* Store a record containing the values from the input object.
@@ -715,45 +743,45 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
*
* @throws SQLException if an error occurs
*/
- void store(@Nonnull final PersistentIdEntry entry, @Nonnull final Connection dbConn) throws SQLException {
+ void store(@Nonnull final PairwiseId entry, @Nonnull final Connection dbConn) throws SQLException {
- log.debug("{} Storing new persistent ID entry", getLogPrefix());
+ log.debug("Storing new pairwise ID entry");
- if (StringSupport.trimOrNull(entry.getIssuerEntityId()) == null
- || StringSupport.trimOrNull(entry.getRecipientEntityId()) == null
- || StringSupport.trimOrNull(entry.getPersistentId()) == null
+ if (StringSupport.trimOrNull(entry.getIssuerEntityID()) == null
+ || StringSupport.trimOrNull(entry.getRecipientEntityID()) == null
+ || StringSupport.trimOrNull(entry.getPairwiseId()) == null
|| StringSupport.trimOrNull(entry.getPrincipalName()) == null
- || StringSupport.trimOrNull(entry.getSourceId()) == null
+ || StringSupport.trimOrNull(entry.getSourceSystemId()) == null
|| entry.getCreationTime() == null) {
throw new SQLException("Required field was empty/null, store operation not possible");
}
- log.trace("{} Prepared statement: {}", getLogPrefix(), insertSQL);
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 1, entry.getIssuerEntityId());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 2, entry.getRecipientEntityId());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 3, entry.getPersistentId());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 4, entry.getPrincipalName());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 5, entry.getSourceId());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 6, entry.getPeerProvidedId());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 7, entry.getCreationTime());
- log.trace("{} Setting prepared statement parameter {}: {}", getLogPrefix(), 8, entry.getDeactivationTime());
+ log.trace("Prepared statement: {}", insertSQL);
+ log.trace("Setting prepared statement parameter {}: {}", 1, entry.getIssuerEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 2, entry.getRecipientEntityID());
+ log.trace("Setting prepared statement parameter {}: {}", 3, entry.getPairwiseId());
+ log.trace("Setting prepared statement parameter {}: {}", 4, entry.getPrincipalName());
+ log.trace("Setting prepared statement parameter {}: {}", 5, entry.getSourceSystemId());
+ log.trace("Setting prepared statement parameter {}: {}", 6, entry.getPeerProvidedId());
+ log.trace("Setting prepared statement parameter {}: {}", 7, entry.getCreationTime());
+ log.trace("Setting prepared statement parameter {}: {}", 8, entry.getDeactivationTime());
final PreparedStatement statement = dbConn.prepareStatement(insertSQL);
statement.setQueryTimeout((int) (queryTimeout / 1000));
- statement.setString(1, entry.getIssuerEntityId());
- statement.setString(2, entry.getRecipientEntityId());
- statement.setString(3, entry.getPersistentId());
+ statement.setString(1, entry.getIssuerEntityID());
+ statement.setString(2, entry.getRecipientEntityID());
+ statement.setString(3, entry.getPairwiseId());
statement.setString(4, entry.getPrincipalName());
- statement.setString(5, entry.getSourceId());
+ statement.setString(5, entry.getSourceSystemId());
if (entry.getPeerProvidedId() != null) {
statement.setString(6, entry.getPeerProvidedId());
} else {
statement.setNull(6, Types.VARCHAR);
}
- statement.setTimestamp(7, entry.getCreationTime());
+ statement.setTimestamp(7, new Timestamp(entry.getCreationTime()));
if (entry.getDeactivationTime() != null) {
- statement.setTimestamp(8, entry.getDeactivationTime());
+ statement.setTimestamp(8, new Timestamp(entry.getDeactivationTime()));
} else {
statement.setNull(8, Types.TIMESTAMP);
}
@@ -787,18 +815,16 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
final String uuid = UUID.randomUUID().toString();
- final PersistentIdEntry newEntry = new PersistentIdEntry();
- newEntry.setIssuerEntityId("http://dummy.com/idp/" + uuid);
- newEntry.setRecipientEntityId("http://dummy.com/sp/" + uuid);
- newEntry.setSourceId("dummy");
+ final PairwiseId newEntry = new PairwiseId();
+ newEntry.setIssuerEntityID("http://dummy.com/idp/" + uuid);
+ newEntry.setRecipientEntityID("http://dummy.com/sp/" + uuid);
+ newEntry.setSourceSystemId("dummy");
newEntry.setPrincipalName("dummy");
- newEntry.setCreationTime(new Timestamp(System.currentTimeMillis()));
- newEntry.setPersistentId(uuid);
+ newEntry.setCreationTime(System.currentTimeMillis());
+ newEntry.setPairwiseId(uuid);
try (final Connection conn = getConnection(true)) {
store(newEntry, conn);
- } finally {
-
}
boolean keyMissing = false;
@@ -807,11 +833,9 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
keyMissing = true;
} catch (final SQLException e) {
if (e.getSQLState() != null && !retryableErrors.contains(e.getSQLState())) {
- log.warn("{} Duplicate insert failed as required with SQL State '{}', ensure this value is "
- + "configured as a retryable error", getLogPrefix(), e.getSQLState());
+ log.warn("Duplicate insert failed as required with SQL State '{}', ensure this value is "
+ + "configured as a retryable error", e.getSQLState());
}
- } finally {
-
}
try (final Connection conn = getConnection(true)) {
@@ -819,8 +843,6 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
statement.setQueryTimeout((int) (queryTimeout / 1000));
statement.setString(1, "http://dummy.com/idp/" + uuid);
statement.executeUpdate();
- } finally {
-
}
if (keyMissing) {
@@ -829,43 +851,41 @@ public class JDBCPersistentIdStoreEx extends AbstractInitializableComponent impl
}
/**
- * Builds a list of {@link PersistentIdEntry}s from a result set.
+ * Build a list of {@link PairwiseId} objects from a result set.
*
* @param resultSet the result set
*
- * @return list of {@link PersistentIdEntry}s
+ * @return list of {@link PairwiseId} objects
*
* @throws SQLException thrown if there is a problem reading the information from the database
*/
- @Nonnull @NonnullElements @Live private List<PersistentIdEntry> buildIdentifierEntries(
+ @Nonnull @NonnullElements @Live private List<PairwiseId> buildIdentifierEntries(
@Nonnull final ResultSet resultSet) throws SQLException {
- final ArrayList<PersistentIdEntry> entries = new ArrayList<>();
+
+ final ArrayList<PairwiseId> entries = new ArrayList<>();
while (resultSet.next()) {
- final PersistentIdEntry entry = new PersistentIdEntry();
- entry.setIssuerEntityId(resultSet.getString(issuerColumn));
- entry.setRecipientEntityId(resultSet.getString(recipientColumn));
+ final PairwiseId entry = new PairwiseId();
+ entry.setIssuerEntityID(resultSet.getString(issuerColumn));
+ entry.setRecipientEntityID(resultSet.getString(recipientColumn));
entry.setPrincipalName(resultSet.getString(principalNameColumn));
- entry.setPersistentId(resultSet.getString(persistentIdColumn));
- entry.setSourceId(resultSet.getString(sourceIdColumn));
+ entry.setPairwiseId(resultSet.getString(persistentIdColumn));
+ entry.setSourceSystemId(resultSet.getString(sourceIdColumn));
entry.setPeerProvidedId(resultSet.getString(peerProvidedIdColumn));
- entry.setCreationTime(resultSet.getTimestamp(creationTimeColumn));
- entry.setDeactivationTime(resultSet.getTimestamp(deactivationTimeColumn));
+ Timestamp ts = resultSet.getTimestamp(creationTimeColumn);
+ if (ts != null) {
+ entry.setCreationTime(ts.getTime());
+ }
+ ts = resultSet.getTimestamp(deactivationTimeColumn);
+ if (ts != null) {
+ entry.setDeactivationTime(ts.getTime());
+ }
entries.add(entry);
- log.trace("{} Entry {} added to results", getLogPrefix(), entry.toString());
+ log.trace("Entry {} added to results", entry.toString());
}
return entries;
}
-
- /**
- * Return a string which is to be prepended to all log messages.
- *
- * @return "Stored Id Store:"
- */
- @Nonnull @NotEmpty private String getLogPrefix() {
- return "Stored Id Store:";
- }
}
\ No newline at end of file
diff --git a/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/package-info.java b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/package-info.java
new file mode 100644
index 0000000..550f2e3
--- /dev/null
+++ b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementations of general attribute functionality.
+ */
+
+package net.shibboleth.idp.attribute.impl;
\ No newline at end of file
diff --git a/idp-attribute-impl/src/main/resources/.gitkeep b/idp-attribute-impl/src/main/resources/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/idp-attribute-impl/src/test/java/.gitkeep b/idp-attribute-impl/src/test/java/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java
new file mode 100644
index 0000000..ab51fc8
--- /dev/null
+++ b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.impl;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore.Encoding;
+import net.shibboleth.idp.testing.DatabaseTestingSupport;
+import net.shibboleth.utilities.java.support.codec.Base64Support;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Test for {@link ComputedPairwiseIdStore}.
+ */
+public class ComputedPairwiseIdStoreTest {
+
+ /** Value calculated using V2 version. DO NOT CHANGE WITHOUT TESTING AGAINST 2.0 */
+ private static final String RESULT = "Vl6z6K70iLc4AuBoNeb59Dj1rGw=";
+
+ private static final String RESULT2 = "kLyH1uEvYigEvg1ZLh/QXeW1VAs=";
+
+ private static final String B32RESULT = "KZPLH2FO6SELOOAC4BUDLZXZ6Q4PLLDM";
+
+ private static final byte salt[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+ private static final String salt2 = "thisisaspecialsalt";
+
+ public static final String COMMON_ATTRIBUTE_VALUE_STRING = "at1-Data";
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testInvalidConfig() throws ComponentInitializationException {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.initialize();
+ }
+
+ @Test
+ public void testSaltSetters() throws ComponentInitializationException {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ Assert.assertEquals(salt, store.getSalt());
+
+ store.setEncodedSalt(Base64Support.encode(salt, false));
+ Assert.assertEquals(salt, store.getSalt());
+ }
+
+ @Test(expectedExceptions=IOException.class)
+ public void testRevoked() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.setExceptionMap(Collections.singletonMap("foo",
+ Collections.<String,String>singletonMap(DatabaseTestingSupport.SP_ENTITY_ID, null)));
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ store.getBySourceValue(pid, true);
+ }
+
+ @Test(expectedExceptions=IOException.class)
+ public void testRevokedWildcardRP() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.setExceptionMap(Collections.singletonMap("foo",
+ Collections.<String,String>singletonMap(ComputedPairwiseIdStore.WILDCARD_OVERRIDE, null)));
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ store.getBySourceValue(pid, true);
+ }
+
+ @Test(expectedExceptions=IOException.class)
+ public void testRevokedWildcardUser() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.setExceptionMap(Collections.singletonMap(ComputedPairwiseIdStore.WILDCARD_OVERRIDE,
+ Collections.<String,String>singletonMap(DatabaseTestingSupport.SP_ENTITY_ID, null)));
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ store.getBySourceValue(pid, true);
+ }
+
+ @Test
+ public void testComputedId() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ pid = store.getBySourceValue(pid, true);
+
+ Assert.assertNotNull(pid);
+ Assert.assertEquals(pid.getPairwiseId(), RESULT);
+ }
+
+ @Test
+ public void testComputedIdOverride() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.setExceptionMap(Collections.singletonMap(ComputedPairwiseIdStore.WILDCARD_OVERRIDE,
+ Collections.<String,String>singletonMap(DatabaseTestingSupport.SP_ENTITY_ID, salt2)));
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ pid = store.getBySourceValue(pid, true);
+
+ Assert.assertNotNull(pid);
+ Assert.assertEquals(pid.getPairwiseId(), RESULT2);
+ }
+
+ @Test
+ public void testBase32ComputedId() throws Exception {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.setEncoding(Encoding.BASE32);
+ store.initialize();
+
+ PairwiseId pid = new PairwiseId();
+ pid.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ pid.setPrincipalName("foo");
+ pid.setSourceSystemId(COMMON_ATTRIBUTE_VALUE_STRING);
+
+ pid = store.getBySourceValue(pid, true);
+
+ Assert.assertNotNull(pid);
+ Assert.assertEquals(pid.getPairwiseId(), B32RESULT);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/DatabaseBackedIDStoreTest.java b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStoreTest.java
similarity index 57%
rename from idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/DatabaseBackedIDStoreTest.java
rename to idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStoreTest.java
index 6c98629..a6b5ac8 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/DatabaseBackedIDStoreTest.java
+++ b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/JDBCPairwiseIdStoreTest.java
@@ -15,63 +15,54 @@
* limitations under the License.
*/
-package net.shibboleth.idp.saml.nameid.impl;
+package net.shibboleth.idp.attribute.impl;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.SQLException;
-import java.sql.Timestamp;
import java.util.Objects;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.sql.DataSource;
-import net.shibboleth.idp.saml.nameid.PersistentIdEntry;
+import net.shibboleth.idp.attribute.PairwiseId;
import net.shibboleth.idp.testing.DatabaseTestingSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.UninitializedComponentException;
import net.shibboleth.utilities.java.support.component.UnmodifiableComponentException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import com.google.common.io.CharStreams;
-
-/** Tests for {@link JDBCPersistentIdStoreEx}. */
-public class DatabaseBackedIDStoreTest {
-
- private final Logger log = LoggerFactory.getLogger(DatabaseBackedIDStoreTest.class);
+/** Tests for {@link JDBCPairwiseIdStore}. */
+public class JDBCPairwiseIdStoreTest {
private DataSource testSource;
- public static String convertStreamToString(java.io.InputStream is) throws IOException {
- return CharStreams.toString(new InputStreamReader(is));
- }
+ public static final String INIT_FILE = "/net/shibboleth/idp/attribute/impl/StoredIdStore.sql";
+ public static final String DELETE_FILE = "/net/shibboleth/idp/attribute/impl/DeleteStore.sql";
@BeforeMethod
public void setupSource() throws IOException, IOException {
- testSource = DatabaseTestingSupport.GetMockDataSource(PersistentSAML2NameIDGeneratorTest.INIT_FILE, "PersistentIdStore");
+ testSource = DatabaseTestingSupport.GetMockDataSource(INIT_FILE, "PersistentIdStore");
}
@AfterMethod public void teardown() {
- DatabaseTestingSupport.InitializeDataSource(PersistentSAML2NameIDGeneratorTest.DELETE_FILE, testSource);
+ DatabaseTestingSupport.InitializeDataSource(DELETE_FILE, testSource);
}
@Test public void initializeAndGetters() throws ComponentInitializationException, IOException {
- JDBCPersistentIdStoreEx store = new JDBCPersistentIdStoreEx();
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
try {
store.initialize();
Assert.fail("Need to initialize the source");
} catch (final ComponentInitializationException e) {
- // OK
+ // OK
}
store.setDataSource(testSource);
@@ -80,7 +71,7 @@ public class DatabaseBackedIDStoreTest {
store.setQueryTimeout(1);
try {
- store.getBySourceValue("foo", "foo", "foo", "foo", true, null);
+ store.getBySourceValue(new PairwiseId(), true);
Assert.fail("need to initialize first");
} catch (final UninitializedComponentException e) {
// OK
@@ -104,72 +95,69 @@ public class DatabaseBackedIDStoreTest {
Assert.assertEquals(store.getQueryTimeout(), 1);
}
- private boolean comparePersistentIdEntrys(@Nonnull PersistentIdEntry one, @Nonnull PersistentIdEntry other)
+ private boolean comparePersistentIdEntrys(@Nonnull PairwiseId one, @Nonnull PairwiseId other)
{
//
// Do not compare times
//
- boolean result = Objects.equals(one.getPersistentId(), other.getPersistentId()) &&
- Objects.equals(one.getIssuerEntityId(), other.getIssuerEntityId()) &&
- Objects.equals(one.getRecipientEntityId(), other.getRecipientEntityId()) &&
- Objects.equals(one.getSourceId(), other.getSourceId()) &&
+ return Objects.equals(one.getPairwiseId(), other.getPairwiseId()) &&
+ Objects.equals(one.getIssuerEntityID(), other.getIssuerEntityID()) &&
+ Objects.equals(one.getRecipientEntityID(), other.getRecipientEntityID()) &&
+ Objects.equals(one.getSourceSystemId(), other.getSourceSystemId()) &&
Objects.equals(one.getPrincipalName(), other.getPrincipalName()) &&
Objects.equals(one.getPeerProvidedId(), other.getPeerProvidedId()) &&
Objects.equals(one.getDeactivationTime(), other.getDeactivationTime());
- if (!result) {
- log.warn("Not equals: {} and {}", one, other);
- }
- return result;
}
@Test public void storeEntry() throws ComponentInitializationException, IOException, SQLException {
- JDBCPersistentIdStoreEx store = new JDBCPersistentIdStoreEx();
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
store.setDataSource(testSource);
store.setVerifyDatabase(true);
store.initialize();
- final PersistentIdEntry id = new PersistentIdEntry();
+ final PairwiseId id = new PairwiseId();
String persistentId = UUID.randomUUID().toString();
- id.setIssuerEntityId(DatabaseTestingSupport.IDP_ENTITY_ID);
- id.setRecipientEntityId(DatabaseTestingSupport.SP_ENTITY_ID);
+ id.setIssuerEntityID(DatabaseTestingSupport.IDP_ENTITY_ID);
+ id.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
id.setPrincipalName(DatabaseTestingSupport.PRINCIPAL_ID);
- id.setSourceId("localID");
+ id.setSourceSystemId("localID");
id.setPeerProvidedId("PeerprovidedId");
- id.setPersistentId(persistentId);
- id.setCreationTime(new Timestamp(System.currentTimeMillis()));
+ id.setPairwiseId(persistentId);
+ id.setCreationTime(System.currentTimeMillis());
try (final Connection conn = testSource.getConnection()) {
store.store(id, conn);
- } finally {
-
}
- PersistentIdEntry gotback = store.getByIssuedValue(DatabaseTestingSupport.IDP_ENTITY_ID,
- DatabaseTestingSupport.SP_ENTITY_ID, persistentId);
+ PairwiseId id2 = new PairwiseId();
+ id2.setIssuerEntityID(DatabaseTestingSupport.IDP_ENTITY_ID);
+ id2.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID);
+ id2.setPairwiseId(persistentId);
+ id2 = store.getByIssuedValue(id2);
- Assert.assertNull(gotback.getDeactivationTime());
- Assert.assertTrue(comparePersistentIdEntrys(gotback, id));
+ Assert.assertNull(id2.getDeactivationTime());
+ Assert.assertTrue(comparePersistentIdEntrys(id2, id));
- store.deactivate(DatabaseTestingSupport.IDP_ENTITY_ID, DatabaseTestingSupport.SP_ENTITY_ID, persistentId, null);
+ store.deactivate(id2);
- Assert.assertNull(store.getByIssuedValue(DatabaseTestingSupport.IDP_ENTITY_ID,
- DatabaseTestingSupport.SP_ENTITY_ID, persistentId));
+ Assert.assertNull(store.getByIssuedValue(id2));
persistentId = UUID.randomUUID().toString();
- id.setPersistentId(persistentId);
+ id.setPairwiseId(persistentId);
id.setPeerProvidedId(null);
- id.setRecipientEntityId(DatabaseTestingSupport.SP_ENTITY_ID + "2");
+ id.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID + "2");
try (final Connection conn = testSource.getConnection()) {
store.store(id, conn);
- } finally {
-
}
- gotback = store.getByIssuedValue(DatabaseTestingSupport.IDP_ENTITY_ID,
- DatabaseTestingSupport.SP_ENTITY_ID + "2", persistentId);
- Assert.assertNull(gotback.getDeactivationTime());
- Assert.assertTrue(comparePersistentIdEntrys(gotback, id));
+ PairwiseId id3 = new PairwiseId();
+ id3.setIssuerEntityID(DatabaseTestingSupport.IDP_ENTITY_ID);
+ id3.setRecipientEntityID(DatabaseTestingSupport.SP_ENTITY_ID + "2");
+ id3.setPairwiseId(persistentId);
+ id3 = store.getByIssuedValue(id3);
+ Assert.assertNull(id3.getDeactivationTime());
+ Assert.assertTrue(comparePersistentIdEntrys(id3, id));
}
}
\ No newline at end of file
diff --git a/idp-attribute-impl/src/test/resources/logback-test.xml b/idp-attribute-impl/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..f3280e5
--- /dev/null
+++ b/idp-attribute-impl/src/test/resources/logback-test.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<configuration>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%level [%logger:%line] - %msg%n</pattern>
+ <charset>UTF-8</charset>
+ </encoder>
+ </appender>
+
+ <root>
+ <level value="warn" />
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
\ No newline at end of file
diff --git a/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/DeleteStore.sql b/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/DeleteStore.sql
new file mode 100644
index 0000000..9ffe8bd
--- /dev/null
+++ b/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/DeleteStore.sql
@@ -0,0 +1 @@
+DROP TABLE shibpid;
diff --git a/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/StoredIdStore.sql b/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/StoredIdStore.sql
new file mode 100644
index 0000000..294b108
--- /dev/null
+++ b/idp-attribute-impl/src/test/resources/net/shibboleth/idp/attribute/impl/StoredIdStore.sql
@@ -0,0 +1,11 @@
+CREATE TABLE shibpid (
+ localEntity VARCHAR(100) NOT NULL,
+ peerEntity VARCHAR(100) NOT NULL,
+ persistentId VARCHAR(50) NOT NULL,
+ principalName VARCHAR(50) NOT NULL,
+ localId VARCHAR(50) NOT NULL,
+ peerProvidedId VARCHAR(50),
+ creationDate TIMESTAMP NOT NULL,
+ deactivationDate TIMESTAMP,
+ PRIMARY KEY (localEntity, peerEntity, persistentId)
+ );
diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/PairwiseIdDataConnector.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/PairwiseIdDataConnector.java
new file mode 100644
index 0000000..304173e
--- /dev/null
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/PairwiseIdDataConnector.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.resolver.dc.impl;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+
+import net.shibboleth.idp.attribute.EmptyAttributeValue;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.PairwiseIdStore;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.resolver.AbstractDataConnector;
+import net.shibboleth.idp.attribute.resolver.PluginDependencySupport;
+import net.shibboleth.idp.attribute.resolver.ResolutionException;
+import net.shibboleth.idp.attribute.resolver.ResolverAttributeDefinitionDependency;
+import net.shibboleth.idp.attribute.resolver.ResolverDataConnectorDependency;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * A {@link net.shibboleth.idp.attribute.resolver.DataConnector} that generates pairwise IDs that depend on
+ * a seed {@link IdPAttribute}.
+ *
+ * @since 4.0.0
+ */
+public class PairwiseIdDataConnector extends AbstractDataConnector {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PairwiseIdDataConnector.class);
+
+ /** ID of the attribute generated by this data connector. */
+ @NonnullAfterInit private String generatedAttribute;
+
+ /** Information about the dependency. */
+ @NonnullAfterInit private String sourceInformation;
+
+ /** Source of IDs. */
+ @NonnullAfterInit private PairwiseIdStore pidStore;
+
+ /**
+ * Get the attribute ID whose first value is being used when producing the pairwise ID.
+ *
+ * @return source attribute ID
+ */
+ @Nullable @NonnullAfterInit public String getSourceAttributeInformation() {
+ ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ return sourceInformation;
+ }
+
+ /**
+ * Get the ID of the attribute generated by this connector.
+ *
+ * @return ID of the attribute generated by this connector
+ */
+ @NonnullAfterInit public String getGeneratedAttributeId() {
+ return generatedAttribute;
+ }
+
+ /**
+ * Set the ID of the attribute generated by this connector.
+ *
+ * @param newAttributeId what to set.
+ */
+ public void setGeneratedAttributeId(@Nullable final String newAttributeId) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ generatedAttribute = newAttributeId;
+ }
+
+ /**
+ * Get the underlying pairwise ID store.
+ *
+ * @return ID store
+ */
+ @NonnullAfterInit public PairwiseIdStore getPairwiseIdStore() {
+ return pidStore;
+ }
+
+ /**
+ * Set the underlying pairwise ID store.
+ *
+ * @param store ID store
+ */
+ public void setPairwiseIdStore(@Nonnull final PairwiseIdStore store) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ pidStore = Constraint.isNotNull(store, "PairwiseIdStore cannot be null");
+ }
+
+ /**
+ * Do the dance with dependencies.
+ *
+ * @throws ComponentInitializationException if the dependencies are not aligned correctly
+ */
+ private void doDependencyInformation() throws ComponentInitializationException {
+ final StringBuilder dependencyInformation = new StringBuilder();
+ boolean seenAttribute = false;
+
+ for (final ResolverAttributeDefinitionDependency attrDep : getAttributeDependencies()) {
+ if (seenAttribute) {
+ dependencyInformation.append(", ");
+ }
+ dependencyInformation.append(attrDep.getDependencyPluginId());
+ seenAttribute = true;
+ }
+
+ for (final ResolverDataConnectorDependency dataConnectorDependency : getDataConnectorDependencies()) {
+ if (seenAttribute) {
+ dependencyInformation.append(", ");
+ }
+ if (dataConnectorDependency.isAllAttributes()) {
+ dependencyInformation.append(dataConnectorDependency.getDependencyPluginId()).append("/*");
+ } else if (dataConnectorDependency.getAttributeNames().isEmpty()) {
+ throw new ComponentInitializationException(getLogPrefix() + " No source attribute present.");
+ } else if (dataConnectorDependency.getAttributeNames().size() == 1) {
+ dependencyInformation.append(dataConnectorDependency.getDependencyPluginId()).
+ append('/').
+ append(dataConnectorDependency.getAttributeNames().iterator().next());
+ } else {
+ dependencyInformation.append(dataConnectorDependency.getDependencyPluginId()).
+ append('/').
+ append(dataConnectorDependency.getAttributeNames().toString());
+ }
+ seenAttribute = true;
+ }
+
+ if (!seenAttribute) {
+ throw new ComponentInitializationException(getLogPrefix() +
+ " No source attribute present in the supplied Dependencies");
+ }
+ sourceInformation = dependencyInformation.toString();
+ log.debug("{} Source for definition: {}", getLogPrefix(), sourceInformation);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doInitialize() throws ComponentInitializationException {
+
+ if (pidStore == null) {
+ throw new ComponentInitializationException("PairwiseIdStore cannot be null");
+ }
+
+ // Set up the dependencies first. Then the initialize in the parent
+ // will correctly rehash the dependencies.
+ doDependencyInformation();
+ super.doInitialize();
+
+ if (null == generatedAttribute) {
+ generatedAttribute = getId();
+ log.info("{} No generated attribute ID supplied, using ID of connector: {}", getLogPrefix(),
+ generatedAttribute);
+ }
+ }
+
+ /**
+ * Helper function to locate the source Attribute in the dependencies.
+ *
+ * @param workContext the context to look in
+ * @return the value, or null in any of the failure cases.
+ */
+ @Nullable protected String resolveSourceAttribute(@Nonnull final AttributeResolverWorkContext workContext) {
+ ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+ final List<IdPAttributeValue<?>> attributeValues =
+ PluginDependencySupport.getMergedAttributeValues(workContext,
+ getAttributeDependencies(),
+ getDataConnectorDependencies(),
+ getId());
+ if (attributeValues == null || attributeValues.isEmpty()) {
+ log.debug("{} Source attribute {} for connector {} provide no values", getLogPrefix(),
+ getSourceAttributeInformation(), getId());
+ return null;
+ }
+
+ if (attributeValues.size() > 1) {
+ log.warn("{} Source attribute {} for connector {} has more than one value, only one value is used",
+ getLogPrefix(), getSourceAttributeInformation(), getId());
+ }
+
+ final IdPAttributeValue attributeValue = attributeValues.iterator().next();
+
+ final String val;
+
+ if (attributeValue instanceof StringAttributeValue) {
+ if (StringSupport.trimOrNull((String) attributeValue.getValue()) == null) {
+ log.warn("{} Source attribute {} for connector {} was all-whitespace", getLogPrefix(),
+ getSourceAttributeInformation(), getId());
+ return null;
+ }
+ val = (String) attributeValue.getValue();
+ } else if (attributeValue instanceof EmptyAttributeValue) {
+ final EmptyAttributeValue emptyVal = (EmptyAttributeValue) attributeValue;
+ log.warn("{} Source attribute {} value for connector {} was an empty value of type {}", getLogPrefix(),
+ getSourceAttributeInformation(), getId(), emptyVal.getDisplayValue());
+ return null;
+ } else {
+ log.warn("{} Source attribute {} for connector {} was of an unsupported type: {}", getLogPrefix(),
+ getSourceAttributeInformation(), getId(), attributeValue.getClass().getName());
+ return null;
+ }
+
+ if (val == null) {
+ log.warn("{} Attribute value {} for connector {} resolved as empty or null", getLogPrefix(),
+ getSourceAttributeInformation(), getId());
+ }
+ return val;
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable protected Map<String, IdPAttribute> doDataConnectorResolve(
+ @Nonnull final AttributeResolutionContext resolutionContext,
+ @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {
+
+ ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+
+ final String principalName = resolutionContext.getPrincipal();
+ if (Strings.isNullOrEmpty(principalName)) {
+ log.warn("{} No principal name available, skipping ID creation", getLogPrefix());
+ return null;
+ }
+
+ final String attributeIssuerID = resolutionContext.getAttributeIssuerID();
+ if (Strings.isNullOrEmpty(attributeIssuerID)) {
+ log.warn("{} Could not get attribute issuer ID, skipping ID creation", getLogPrefix());
+ return null;
+ }
+
+ String attributeRecipientID = resolutionContext.getAttributeRecipientGroupID();
+ if (Strings.isNullOrEmpty(attributeRecipientID)) {
+ attributeRecipientID = resolutionContext.getAttributeRecipientID();
+ }
+ if (Strings.isNullOrEmpty(attributeRecipientID)) {
+ log.warn("{} Could not get attribute recipient or group ID, skipping ID creation", getLogPrefix());
+ return null;
+ }
+
+ final String sourceId = resolveSourceAttribute(workContext);
+ if (Strings.isNullOrEmpty(sourceId)) {
+ return null;
+ }
+
+ try {
+ PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(attributeIssuerID);
+ pid.setRecipientEntityID(attributeRecipientID);
+ pid.setPrincipalName(principalName);
+ pid.setSourceSystemId(sourceId);
+
+ pid = pidStore.getBySourceValue(pid, true);
+ if (pid != null && pid.getPairwiseId() != null) {
+ return encodeAsAttribute(pid.getPairwiseId());
+ } else {
+ log.warn("{} Pairwise ID store did not return a value", getLogPrefix());
+ return null;
+ }
+ } catch (final IOException e) {
+ throw new ResolutionException(e);
+ }
+ }
+
+ /**
+ * Encode the provided string.
+ *
+ * @param value the value to encode or null if that failed
+ * @return null or the attribute.
+ */
+ @Nullable protected Map<String, IdPAttribute> encodeAsAttribute(@Nullable final String value) {
+ ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+ if (null == value) {
+ // The message will have been logged above
+ return null;
+ }
+ final IdPAttribute attribute = new IdPAttribute(getGeneratedAttributeId());
+ attribute.setValues(Collections.singletonList(StringAttributeValue.valueOf(value)));
+ return Collections.singletonMap(getGeneratedAttributeId(), attribute);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ComputedIDDataConnectorTest.java b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ComputedIDDataConnectorTest.java
index 2d03a0f..461dfcb 100644
--- a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ComputedIDDataConnectorTest.java
+++ b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ComputedIDDataConnectorTest.java
@@ -33,6 +33,8 @@ import net.shibboleth.idp.attribute.EmptyAttributeValue.EmptyType;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.IdPAttributeValue;
import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.attribute.resolver.AttributeDefinition;
import net.shibboleth.idp.attribute.resolver.AttributeResolver;
import net.shibboleth.idp.attribute.resolver.DataConnector;
@@ -43,15 +45,13 @@ import net.shibboleth.idp.attribute.resolver.ad.impl.SimpleAttributeDefinition;
import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
import net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl;
import net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImplTest;
-import net.shibboleth.idp.saml.attribute.resolver.impl.AbstractPersistentIdDataConnector;
-import net.shibboleth.idp.saml.attribute.resolver.impl.ComputedIDDataConnector;
import net.shibboleth.idp.saml.impl.TestSources;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.component.UnmodifiableComponentException;
+import net.shibboleth.utilities.java.support.component.InitializableComponent;
/**
- * Test for {@link AbstractPersistentIdDataConnector}
+ * Test for {@link PairwiseIdDataConnector} with computed store.
*/
public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
@@ -71,7 +71,7 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
protected static final byte smallSalt[] = {0, 1, 2};
- private static void testInit(final AbstractPersistentIdDataConnector connector, final String failMessage) {
+ private static void testInit(final PairwiseIdDataConnector connector, final String failMessage) {
try {
connector.initialize();
Assert.fail(failMessage);
@@ -81,13 +81,17 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
}
@Test public void dataConnector() throws ComponentInitializationException, ResolutionException {
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
-
+
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
+
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
connector.setId(TEST_CONNECTOR_NAME);
connector.setAttributeDependencies(Collections.singleton(TestSources.makeAttributeDefinitionDependency(
TestSources.DEPENDS_ON_ATTRIBUTE_NAME_ATTR)));
testInit(connector, "No salt");
- connector.setSalt(salt);
+ connector.setPairwiseIdStore(store);
connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
connector.initialize();
@@ -119,43 +123,35 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
Assert.assertEquals(((StringAttributeValue) resultValues.iterator().next()).getValue(), RESULT);
}
- @Test public void getters() throws ComponentInitializationException {
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
- connector.setId(TEST_CONNECTOR_NAME);
- connector.setAttributeDependencies(Collections.singleton(TestSources.makeAttributeDefinitionDependency(
- TestSources.DEPENDS_ON_ATTRIBUTE_NAME_ATTR)));
- connector.setSalt(smallSalt);
- connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
- Assert.assertEquals(connector.getSalt(), smallSalt);
- testInit(connector, "Small salt");
- connector.setSalt(salt);
- connector.initialize();
-
- try {
- connector.setSalt(smallSalt);
- Assert.fail("setting after init");
- } catch (final UnmodifiableComponentException e) {
- // OK'
- }
-
- Assert.assertEquals(connector.getSalt(), salt);
- }
-
private AttributeResolver constructResolver(final int values) throws ComponentInitializationException {
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
-
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
return constructResolver(connector, values, false);
}
- protected static AttributeResolver constructResolver(final ComputedIDDataConnector connector, final int values, final boolean noSalt)
+ protected static AttributeResolver constructResolver(final PairwiseIdDataConnector connector, final int values, final boolean noSalt)
throws ComponentInitializationException {
+
+ if (!noSalt) {
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
+ if (connector.getPairwiseIdStore() != null) {
+ ((JDBCPairwiseIdStore) connector.getPairwiseIdStore()).setInitialValueStore(store);
+ } else {
+ connector.setPairwiseIdStore(store);
+ }
+ }
+
+ if (connector.getPairwiseIdStore() != null) {
+ ((InitializableComponent) connector.getPairwiseIdStore()).initialize();
+ }
+
connector.setId(TEST_CONNECTOR_NAME);
connector.setAttributeDependencies(Collections.singleton(TestSources.makeAttributeDefinitionDependency(
TestSources.DEPENDS_ON_ATTRIBUTE_NAME_ATTR)));
- if (!noSalt) {
- connector.setSalt(salt);
- }
+ connector.initialize();
+
final SimpleAttributeDefinition simple = new SimpleAttributeDefinition();
simple.setId(OUTPUT_ATTRIBUTE_NAME);
simple.setDataConnectorDependencies(Collections.singleton(TestSources.makeDataConnectorDependency(TEST_CONNECTOR_NAME,
@@ -172,14 +168,25 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
private AttributeResolver constructResolverWithNonString(final String dependantOn)
throws ComponentInitializationException {
- return constructResolverWithNonString(new ComputedIDDataConnector(), dependantOn);
+ return constructResolverWithNonString(new PairwiseIdDataConnector(), dependantOn);
}
- protected static AttributeResolver constructResolverWithNonString(final ComputedIDDataConnector connector,
+ protected static AttributeResolver constructResolverWithNonString(final PairwiseIdDataConnector connector,
final String dependantOn) throws ComponentInitializationException {
+
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+
+ if (connector.getPairwiseIdStore() != null) {
+ ((JDBCPairwiseIdStore) connector.getPairwiseIdStore()).setInitialValueStore(store);
+ } else {
+ connector.setPairwiseIdStore(store);
+ }
+ ((InitializableComponent) connector.getPairwiseIdStore()).initialize();
+
connector.setId(TEST_CONNECTOR_NAME);
connector.setAttributeDependencies(Collections.singleton(TestSources.makeAttributeDefinitionDependency(dependantOn)));
- connector.setSalt(salt);
+ connector.initialize();
final SimpleAttributeDefinition simple = new SimpleAttributeDefinition();
simple.setId(OUTPUT_ATTRIBUTE_NAME);
@@ -195,12 +202,12 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
return AttributeResolverImplTest.newAttributeResolverImpl("atresolver", set, Collections.singleton((DataConnector) connector));
}
- protected static AbstractPersistentIdDataConnector connectorFromResolver(final AttributeResolver resolver) {
- return (AbstractPersistentIdDataConnector) resolver.getDataConnectors().get(TEST_CONNECTOR_NAME);
+ protected static PairwiseIdDataConnector connectorFromResolver(final AttributeResolver resolver) {
+ return (PairwiseIdDataConnector) resolver.getDataConnectors().get(TEST_CONNECTOR_NAME);
}
- @Test(expectedExceptions={ComponentInitializationException.class,}) public void noSalt() throws ComponentInitializationException {
- connectorFromResolver(constructResolver(new ComputedIDDataConnector(), 1, true)).initialize();
+ @Test(expectedExceptions={ComponentInitializationException.class,}) public void noStore() throws ComponentInitializationException {
+ connectorFromResolver(constructResolver(new PairwiseIdDataConnector(), 1, true)).initialize();
}
@Test public void altDataConnector() throws ComponentInitializationException, ResolutionException {
@@ -291,12 +298,16 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
@Test public void case425() throws ComponentInitializationException, ResolutionException {
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
+
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
connector.setId(TEST_CONNECTOR_NAME);
connector.setDataConnectorDependencies(Collections.singleton(TestSources.makeDataConnectorDependency(
TestSources.STATIC_CONNECTOR_NAME, TestSources.DEPENDS_ON_ATTRIBUTE_NAME_CONNECTOR)));
- connector.setSalt(salt);
connector.setGeneratedAttributeId("wibble");
+ connector.setPairwiseIdStore(store);
connector.initialize();
final Set<DataConnector> set = new HashSet<>(2);
@@ -342,12 +353,15 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
final ResolverDataConnectorDependency depend = TestSources.makeDataConnectorDependency("connector1", ResolverTestSupport.EPA_ATTRIB_ID);
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
connector.setId(TEST_CONNECTOR_NAME);
connector.setDataConnectorDependencies(Collections.singleton(depend));
- connector.setSalt(salt);
connector.setGeneratedAttributeId("wibble");
+ connector.setPairwiseIdStore(store);
connector.initialize();
@@ -371,12 +385,15 @@ public class ComputedIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
final ResolverDataConnectorDependency depend = TestSources.makeDataConnectorDependency("connector1", ResolverTestSupport.EPA_ATTRIB_ID);
+ final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
+ store.setSalt(salt);
+ store.initialize();
- final ComputedIDDataConnector connector = new ComputedIDDataConnector();
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
connector.setId(TEST_CONNECTOR_NAME);
connector.setDataConnectorDependencies(Collections.singleton(depend));
- connector.setSalt(salt);
connector.setGeneratedAttributeId("wibble");
+ connector.setPairwiseIdStore(store);
connector.initialize();
final Map<String, IdPAttribute> result = connector.resolve(resolutionContext);
diff --git a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/StoredIDDataConnectorTest.java b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/StoredIDDataConnectorTest.java
index 7ffb811..2edaab8 100644
--- a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/StoredIDDataConnectorTest.java
+++ b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/StoredIDDataConnectorTest.java
@@ -18,26 +18,23 @@
package net.shibboleth.idp.attribute.resolver.dc.impl;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.sql.SQLException;
-import java.util.Collections;
import java.util.List;
import javax.sql.DataSource;
+import net.shibboleth.idp.attribute.DurablePairwiseIdStore;
import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.PairwiseId;
import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.attribute.resolver.AttributeResolver;
import net.shibboleth.idp.attribute.resolver.ResolutionException;
-import net.shibboleth.idp.attribute.resolver.ResolverAttributeDefinitionDependency;
import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
-import net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector;
import net.shibboleth.idp.saml.impl.TestSources;
import net.shibboleth.idp.testing.DatabaseTestingSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.component.UninitializedComponentException;
-import net.shibboleth.utilities.java.support.component.UnmodifiableComponentException;
import org.opensaml.core.OpenSAMLInitBaseTestCase;
import org.testng.Assert;
@@ -45,29 +42,17 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
-import com.google.common.io.CharStreams;
-
/**
- * Tests for {@link StoredIDDataConnector} Placed here for convenience.
+ * Test for {@link PairwiseIdDataConnector} with JDBC store.
*/
public class StoredIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
- /** The attribute name. */
- private static final String TEST_ATTRIBUTE_NAME = "storedAttribute";
-
- /** The connector name. */
- private static final String TEST_CONNECTOR_NAME = "storedAttributeConnector";
-
private static final String INIT_FILE = "/net/shibboleth/idp/attribute/resolver/impl/dc/StoredIdStore.sql";
private static final String DELETE_FILE = "/net/shibboleth/idp/attribute/resolver/impl/dc/DeleteStore.sql";
private DataSource testSource;
- public static String convertStreamToString(final java.io.InputStream is) throws IOException {
- return CharStreams.toString(new InputStreamReader(is));
- }
-
@BeforeTest public void setupSource() throws SQLException, IOException {
testSource = DatabaseTestingSupport.GetMockDataSource(INIT_FILE, "StoredIDDataConnectorStore");
@@ -77,80 +62,17 @@ public class StoredIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
DatabaseTestingSupport.InitializeDataSource(DELETE_FILE, testSource);
}
- private void tryInitialize(final StoredIDDataConnector connector, final String failMessage) {
- try {
- connector.initialize();
- Assert.fail(failMessage);
- } catch (final ComponentInitializationException e) {
- // OK
- }
-
- }
-
- @Test public void initializeAndGetters() throws ComponentInitializationException, SQLException, ResolutionException {
-
- StoredIDDataConnector connector = new StoredIDDataConnector();
- connector.setId(TEST_CONNECTOR_NAME);
- connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
-
- tryInitialize(connector, "No DataSource");
- connector = new StoredIDDataConnector();
- connector.setId(TEST_CONNECTOR_NAME);
- connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
- connector.setDataSource(testSource);
-
- connector = new StoredIDDataConnector();
- connector.setId(TEST_CONNECTOR_NAME);
- connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
- connector.setDataSource(testSource);
- connector.setSalt(ComputedIDDataConnectorTest.smallSalt);
- tryInitialize(connector, "salt too small");
-
- connector = new StoredIDDataConnector();
- connector.setId(TEST_CONNECTOR_NAME);
- connector.setGeneratedAttributeId(TEST_ATTRIBUTE_NAME);
- connector.setDataSource(testSource);
- connector.setSalt(ComputedIDDataConnectorTest.smallSalt);
- connector.setSalt(ComputedIDDataConnectorTest.salt);
-
- Assert.assertEquals(connector.getDataSource(), testSource);
- Assert.assertEquals(connector.getQueryTimeout(), 5000);
- connector.setQueryTimeout(1);
-
- try {
- connector.resolve(null);
- Assert.fail("need to initialize first");
- } catch (final UninitializedComponentException e) {
- // OK
- }
- connector.setAttributeDependencies(Collections.singleton(new ResolverAttributeDefinitionDependency("id")));
-
- connector.initialize();
- try {
- connector.setDataSource(null);
- Assert.fail("work after initialize");
- } catch (final UnmodifiableComponentException e) {
- // OK
- }
- connector.initialize();
- try {
- connector.setQueryTimeout(0);
- Assert.fail("work after initialize");
- } catch (final UnmodifiableComponentException e) {
- // OK
- }
- Assert.assertEquals(connector.getDataSource(), testSource);
- Assert.assertEquals(connector.getStoredIDStore().getDataSource(), testSource);
- Assert.assertEquals(connector.getQueryTimeout(), 1);
- }
-
private AttributeResolver constructResolver(final int values) throws ComponentInitializationException {
return constructResolver(values, false);
}
private AttributeResolver constructResolver(final int values, final boolean noSalt) throws ComponentInitializationException {
- final StoredIDDataConnector connector = new StoredIDDataConnector();
- connector.setDataSource(testSource);
+
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
+ store.setDataSource(testSource);
+
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
+ connector.setPairwiseIdStore(store);
return ComputedIDDataConnectorTest.constructResolver(connector, values, noSalt);
}
@@ -167,6 +89,7 @@ public class StoredIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
final AttributeResolver resolver = constructResolver(1);
ComponentSupport.initialize(resolver);
+
ComputedIDDataConnectorTest.connectorFromResolver(resolver).initialize();
final AttributeResolutionContext context =
@@ -257,12 +180,16 @@ public class StoredIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
resolver = constructResolver(1);
- final StoredIDDataConnector connector =
- (StoredIDDataConnector) ComputedIDDataConnectorTest.connectorFromResolver(resolver);
+ final PairwiseIdDataConnector connector =
+ (PairwiseIdDataConnector) ComputedIDDataConnectorTest.connectorFromResolver(resolver);
ComponentSupport.initialize(resolver);
connector.initialize();
- connector.getStoredIDStore().deactivate(TestSources.IDP_ENTITY_ID, TestSources.SP_ENTITY_ID,
- ComputedIDDataConnectorTest.RESULT, null);
+
+ final PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(TestSources.IDP_ENTITY_ID);
+ pid.setRecipientEntityID(TestSources.SP_ENTITY_ID);
+ pid.setPairwiseId(ComputedIDDataConnectorTest.RESULT);
+ ((DurablePairwiseIdStore) connector.getPairwiseIdStore()).deactivate(pid);
context =
TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
@@ -281,16 +208,23 @@ public class StoredIDDataConnectorTest extends OpenSAMLInitBaseTestCase {
@Test(dependsOnMethods = {"retrieveEntry"}) void badEntry() throws ComponentInitializationException,
IOException, ResolutionException {
- final StoredIDDataConnector connector = new StoredIDDataConnector();
- connector.setDataSource(testSource);
+
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
+ store.setDataSource(testSource);
+
+ final PairwiseIdDataConnector connector = new PairwiseIdDataConnector();
+ connector.setPairwiseIdStore(store);
final AttributeResolver resolver = ComputedIDDataConnectorTest.constructResolverWithNonString(connector, "nonString");
ComponentSupport.initialize(resolver);
ComputedIDDataConnectorTest.connectorFromResolver(resolver).initialize();
- connector.getStoredIDStore().deactivate(TestSources.IDP_ENTITY_ID, TestSources.SP_ENTITY_ID,
- ComputedIDDataConnectorTest.RESULT, null);
+ final PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(TestSources.IDP_ENTITY_ID);
+ pid.setRecipientEntityID(TestSources.SP_ENTITY_ID);
+ pid.setPairwiseId(ComputedIDDataConnectorTest.RESULT);
+ ((DurablePairwiseIdStore) connector.getPairwiseIdStore()).deactivate(pid);
final AttributeResolutionContext context =
TestSources.createResolutionContext(" ", TestSources.IDP_ENTITY_ID, TestSources.SP_ENTITY_ID);
diff --git a/idp-attribute-resolver-spring/pom.xml b/idp-attribute-resolver-spring/pom.xml
index d00feac..72b4a4a 100644
--- a/idp-attribute-resolver-spring/pom.xml
+++ b/idp-attribute-resolver-spring/pom.xml
@@ -34,6 +34,11 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>idp-attribute-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>idp-attribute-resolver-api</artifactId>
<version>${project.version}</version>
</dependency>
@@ -154,6 +159,11 @@
</dependency>
<dependency>
+ <groupId>org.ldaptive</groupId>
+ <artifactId>ldaptive-unboundid</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<scope>test</scope>
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIDDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIDDataConnectorParser.java
index 8926c9b..c7a45ac 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIDDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIDDataConnectorParser.java
@@ -20,9 +20,12 @@ package net.shibboleth.idp.attribute.resolver.spring.dc.impl;
import javax.annotation.Nonnull;
import javax.xml.namespace.QName;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore;
import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
-import net.shibboleth.idp.saml.attribute.resolver.impl.ComputedIDDataConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
@@ -30,20 +33,63 @@ import org.w3c.dom.Element;
/**
* Spring bean definition parser for configuring {@link ComputedIDDataConnector}.
*/
-public class ComputedIDDataConnectorParser extends BaseComputedIDDataConnectorParser {
+public class ComputedIDDataConnectorParser extends PairwiseIdDataConnectorParser {
/** Schema type - resolver. */
@Nonnull public static final QName TYPE_NAME_RESOLVER = new QName(AttributeResolverNamespaceHandler.NAMESPACE,
"ComputedId");
- /** {@inheritDoc} */
- @Override protected Class<ComputedIDDataConnector> getBeanClass(final Element element) {
- return ComputedIDDataConnector.class;
- }
-
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(ComputedIDDataConnectorParser.class);
+
/** {@inheritDoc} */
@Override protected void doParse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
@Nonnull final BeanDefinitionBuilder builder) {
super.doParse(config, parserContext, builder, "computedId");
+
+ builder.addPropertyValue("pairwiseIdStore", doComputedPairwiseIdStore(config, parserContext));
+ }
+
+ /**
+ * Parse the config and define a bean for a {@link ComputedPairwiseIdStore}.
+ *
+ * @param config the XML element being parsed
+ * @param parserContext the object encapsulating the current state of the parsing process
+ * @return bean definition for the store object to inject
+ */
+ @Nonnull protected BeanDefinition doComputedPairwiseIdStore(@Nonnull final Element config,
+ @Nonnull final ParserContext parserContext) {
+
+ final BeanDefinitionBuilder builder =
+ BeanDefinitionBuilder.genericBeanDefinition(ComputedPairwiseIdStore.class);
+ builder.setInitMethodName("initialize");
+ builder.setDestroyMethodName("destroy");
+
+ if (config.hasAttributeNS(null, "algorithm")) {
+ builder.addPropertyValue("algorithm", config.getAttributeNS(null, "algorithm"));
+ }
+
+ if (config.hasAttributeNS(null, "encoding")) {
+ builder.addPropertyValue("encoding", config.getAttributeNS(null, "encoding"));
+ }
+
+ final String salt;
+ if (config.hasAttributeNS(null, "salt")) {
+ salt = config.getAttributeNS(null, "salt");
+ } else {
+ salt = null;
+ }
+
+ if (null == salt) {
+ log.debug("{} No salt provided", getLogPrefix());
+ } else {
+ log.debug("{} See TRACE log for the salt value", getLogPrefix());
+ log.trace("{} Salt: '{}'", getLogPrefix(), salt);
+ }
+
+ builder.addPropertyValue("salt", salt);
+
+ return builder.getBeanDefinition();
}
- }
\ No newline at end of file
+
+}
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/BaseComputedIDDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/PairwiseIdDataConnectorParser.java
similarity index 67%
rename from idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/BaseComputedIDDataConnectorParser.java
rename to idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/PairwiseIdDataConnectorParser.java
index 62923e6..d2bb323 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/BaseComputedIDDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/PairwiseIdDataConnectorParser.java
@@ -29,33 +29,46 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
+import net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector;
import net.shibboleth.idp.attribute.resolver.spring.BaseResolverPluginParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.AbstractDataConnectorParser;
+import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
-import net.shibboleth.utilities.java.support.xml.AttributeSupport;
import net.shibboleth.utilities.java.support.xml.ElementSupport;
/**
* Spring bean definition parser for configuring
- * {@link net.shibboleth.idp.saml.attribute.resolver.impl.ComputedIDDataConnector} and
- * {@link net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector}.
+ * {@link net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector} variants.
*/
-public abstract class BaseComputedIDDataConnectorParser extends BaseResolverPluginParser {
+public class PairwiseIdDataConnectorParser extends BaseResolverPluginParser {
+ /** Schema type - resolver. */
+ @Nonnull public static final QName TYPE_NAME_RESOLVER = new QName(AttributeResolverNamespaceHandler.NAMESPACE,
+ "PairwiseId");
+
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(BaseComputedIDDataConnectorParser.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PairwiseIdDataConnectorParser.class);
+
+ /** {@inheritDoc} */
+ @Override protected Class<PairwiseIdDataConnector> getBeanClass(final Element element) {
+ return PairwiseIdDataConnector.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doParse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
+ @Nonnull final BeanDefinitionBuilder builder) {
+ doParse(config, parserContext, builder, "pairwiseId");
+ }
/**
- * Parse the common definitions for {@link net.shibboleth.idp.saml.attribute.resolver.impl.ComputedIDDataConnector}
- * and {@link net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector}.
+ * Parse any common material for {@link net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector}.
*
* @param config the DOM element under consideration.
* @param parserContext Spring's context.
* @param builder Spring's bean builder.
* @param generatedIdDefaultName the name to give the generated Attribute if none was provided.
*/
- // Checkstyle: CyclomaticComplexity|MethodLength OFF
protected void doParse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
@Nonnull final BeanDefinitionBuilder builder, @Nullable final String generatedIdDefaultName) {
super.doParse(config, parserContext, builder);
@@ -66,50 +79,28 @@ public abstract class BaseComputedIDDataConnectorParser extends BaseResolverPlug
} else {
generatedAttribute = generatedIdDefaultName;
}
+ builder.addPropertyValue("generatedAttributeId", generatedAttribute);
+
+ // If this isn't one of the older hard-wired types, inject an arbitrary ID store ref.
+ if (getClass().equals(PairwiseIdDataConnectorParser.class)) {
+ builder.addPropertyReference("pairwiseIdStore", config.getAttributeNS(null, "pairwiseIdStoreRef"));
+ }
final List<Element> failoverConnector = ElementSupport.getChildElements(config,
AbstractDataConnectorParser.FAILOVER_DATA_CONNECTOR_ELEMENT_NAME);
if (failoverConnector != null && !failoverConnector.isEmpty()) {
if (failoverConnector.size() > 1) {
- log.warn("{} More than one failover data connector specified, taking the first",
- getLogPrefix());
+ log.warn("{} More than one failover data connector specified, taking the first", getLogPrefix());
}
final String connectorId = StringSupport.trimOrNull(failoverConnector.get(0).getAttributeNS(null, "ref"));
log.debug("{} Setting the following failover data connector dependencies: {}", getLogPrefix(), connectorId);
builder.addPropertyValue("failoverDataConnectorId", connectorId);
}
-
- if (config.hasAttributeNS(null, "algorithm")) {
- builder.addPropertyValue("algorithm", config.getAttributeNS(null, "algorithm"));
- }
-
- if (config.hasAttributeNS(null, "encoding")) {
- builder.addPropertyValue("encoding", config.getAttributeNS(null, "encoding"));
- }
-
- final String salt;
- if (AttributeSupport.hasAttribute(config, new QName("salt"))) {
- salt = config.getAttributeNS(null, "salt");
- } else {
- salt = null;
- }
-
- if (null == salt) {
- log.debug("{} Generated Attribute: '{}', no salt provided", getLogPrefix(), generatedAttribute);
- } else {
- log.debug("{} Generated Attribute: '{}', see TRACE log for the salt value",
- getLogPrefix(), generatedAttribute);
- log.trace("{} salt: '{}'", getLogPrefix(), salt);
- }
-
- builder.addPropertyValue("generatedAttributeId", generatedAttribute);
- builder.addPropertyValue("salt", salt);
}
- // Checkstyle: CyclomaticComplexity|MethodLength ON
/**
- * return a string which is to be prepended to all log messages.
+ * Return a string which is to be prepended to all log messages.
*
* @return "Attribute Definition: '<definitionID>' :"
*/
@@ -117,4 +108,5 @@ public abstract class BaseComputedIDDataConnectorParser extends BaseResolverPlug
final StringBuilder builder = new StringBuilder("Data Connector '").append(getDefinitionId()).append("':");
return builder.toString();
}
+
}
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/StoredIDDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/StoredIDDataConnectorParser.java
index 2ea9850..ee77c0c 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/StoredIDDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/StoredIDDataConnectorParser.java
@@ -18,32 +18,24 @@
package net.shibboleth.idp.attribute.resolver.spring.dc.impl;
import javax.annotation.Nonnull;
-import javax.sql.DataSource;
import javax.xml.namespace.QName;
-import net.shibboleth.ext.spring.context.FilesystemGenericApplicationContext;
import net.shibboleth.ext.spring.util.SpringSupport;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
-import net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector;
-import net.shibboleth.utilities.java.support.primitive.DeprecationSupport;
-import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.ObjectType;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
-import net.shibboleth.utilities.java.support.xml.AttributeSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
-import org.springframework.context.support.GenericApplicationContext;
import org.w3c.dom.Element;
/**
* Spring bean definition parser for {@link StoredIDDataConnector}.
*/
-public class StoredIDDataConnectorParser extends BaseComputedIDDataConnectorParser {
+public class StoredIDDataConnectorParser extends ComputedIDDataConnectorParser {
/** Schema type - resolver. */
@Nonnull public static final QName TYPE_NAME_RESOLVER =
@@ -53,23 +45,30 @@ public class StoredIDDataConnectorParser extends BaseComputedIDDataConnectorPars
@Nonnull private final Logger log = LoggerFactory.getLogger(StoredIDDataConnectorParser.class);
/** {@inheritDoc} */
- @Override protected Class<StoredIDDataConnector> getBeanClass(final Element element) {
- return StoredIDDataConnector.class;
- }
-
- /** {@inheritDoc} */
@Override protected void doParse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
@Nonnull final BeanDefinitionBuilder builder) {
super.doParse(config, parserContext, builder, "storedId");
- log.debug("{} doParse {}", getLogPrefix(), config);
- final String springResources = AttributeSupport.getAttributeValue(config, new QName("springResources"));
+ builder.addPropertyValue("pairwiseIdStore", doJDBCPairwiseIdStore(config, parserContext));
+ }
+
+ /**
+ * Parse the config and define a bean for a {@link JDBCPairwiseIdStore}.
+ *
+ * @param config the XML element being parsed
+ * @param parserContext the object encapsulating the current state of the parsing process
+ * @return bean definition for the store object to inject
+ */
+ @Nonnull protected BeanDefinition doJDBCPairwiseIdStore(@Nonnull final Element config,
+ @Nonnull final ParserContext parserContext) {
+
+ final BeanDefinitionBuilder builder =
+ BeanDefinitionBuilder.genericBeanDefinition(JDBCPairwiseIdStore.class);
+ builder.setInitMethodName("initialize");
+ builder.setDestroyMethodName("destroy");
+
final String beanDataSource = ManagedConnectionParser.getBeanDataSourceID(config);
- if (springResources != null) {
- DeprecationSupport.warnOnce(ObjectType.ATTRIBUTE, "springResources in StoredIDDataConnector",
- parserContext.getReaderContext().getResource().getDescription(), "<BeanManagedConnection> element");
- builder.addPropertyValue("dataSource", getDataSource(springResources.split(";")));
- } else if (beanDataSource != null) {
+ if (beanDataSource != null) {
builder.addPropertyReference("dataSource", beanDataSource);
} else {
builder.addPropertyValue("dataSource", getv2DataSource(config));
@@ -85,7 +84,7 @@ public class StoredIDDataConnectorParser extends BaseComputedIDDataConnectorPars
}
if (config.hasAttributeNS(null, "failFast")) {
- builder.addPropertyValue("failFast",
+ builder.addPropertyValue("verifyDatabase",
StringSupport.trimOrNull(config.getAttributeNS(null, "failFast")));
}
@@ -93,37 +92,14 @@ public class StoredIDDataConnectorParser extends BaseComputedIDDataConnectorPars
builder.addPropertyValue("retryableErrors",
SpringSupport.getAttributeValueAsList(config.getAttributeNodeNS(null, "retryableErrors")));
}
- }
- /**
- * Creates a Spring bean factory from the supplied spring resources.
- *
- * @param springResources to load bean definitions from
- *
- * @return bean factory
- */
- @Nonnull protected BeanFactory createBeanFactory(@Nonnull final String... springResources) {
- final GenericApplicationContext ctx = new FilesystemGenericApplicationContext();
- final XmlBeanDefinitionReader definitionReader = new XmlBeanDefinitionReader(ctx);
- definitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
- definitionReader.setNamespaceAware(true);
- definitionReader.loadBeanDefinitions(springResources);
- ctx.refresh();
- return ctx.getBeanFactory();
- }
-
- /**
- * Get the dataSource from the configuration.
- *
- * @param springResource location of a spring resource.
- * @return the DataSource
- */
- protected DataSource getDataSource(@Nonnull final String... springResource) {
- final BeanFactory beanFactory = createBeanFactory(springResource);
- return beanFactory.getBean(DataSource.class);
+ if (config.hasAttributeNS(null, "salt")) {
+ builder.addPropertyValue("initialValueStore", doComputedPairwiseIdStore(config, parserContext));
+ }
+
+ return builder.getBeanDefinition();
}
-
-
+
/**
* Get the dataSource from a v2 configuration.
*
@@ -135,4 +111,5 @@ public class StoredIDDataConnectorParser extends BaseComputedIDDataConnectorPars
final ManagedConnectionParser parser = new ManagedConnectionParser(config);
return parser.createDataSource();
}
+
}
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ComputedIDDataConnectorParserTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ComputedIDDataConnectorParserTest.java
index 42efc8a..09f9757 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ComputedIDDataConnectorParserTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ComputedIDDataConnectorParserTest.java
@@ -27,46 +27,51 @@ import org.testng.annotations.Test;
import net.shibboleth.ext.spring.context.FilesystemGenericApplicationContext;
import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore.Encoding;
+import net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector;
import net.shibboleth.idp.attribute.resolver.spring.BaseAttributeDefinitionParserTest;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ComputedIDDataConnectorParser;
-import net.shibboleth.idp.saml.attribute.resolver.impl.ComputedIDDataConnector;
-import net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
/**
- * test for {@link ComputedIDDataConnectorParser}
+ * Test for {@link ComputedIDDataConnectorParser}.
*/
public class ComputedIDDataConnectorParserTest extends BaseAttributeDefinitionParserTest {
@Test public void withSalt() throws ComponentInitializationException {
- final ComputedIDDataConnector connector = getDataConnector("resolver/computed.xml", ComputedIDDataConnector.class);
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/computed.xml", PairwiseIdDataConnector.class);
+ final ComputedPairwiseIdStore store = (ComputedPairwiseIdStore) connector.getPairwiseIdStore();
Assert.assertEquals(connector.getId(), "computed");
Assert.assertEquals(connector.getGeneratedAttributeId(), "jenny");
- Assert.assertEquals(connector.getSalt(), "abcdefghijklmnopqrst ".getBytes());
+ Assert.assertEquals(store.getSalt(), "abcdefghijklmnopqrst ".getBytes());
Assert.assertEquals(connector.getSourceAttributeInformation(), "theSourceRemainsTheSame");
- Assert.assertEquals(connector.getAlgorithm(), "SHA256");
- Assert.assertEquals(connector.getEncoding(), Encoding.BASE32);
+ Assert.assertEquals(store.getAlgorithm(), "SHA256");
+ Assert.assertEquals(store.getEncoding(), Encoding.BASE32);
Assert.assertTrue(connector.isInitialized());
}
@Test public void resolverDataConnector() throws ComponentInitializationException {
- final ComputedIDDataConnector connector = getDataConnector("resolver/computedDataConnector.xml", ComputedIDDataConnector.class);
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/computedDataConnector.xml", PairwiseIdDataConnector.class);
+ final ComputedPairwiseIdStore store = (ComputedPairwiseIdStore) connector.getPairwiseIdStore();
Assert.assertEquals(connector.getId(), "computed");
Assert.assertEquals(connector.getGeneratedAttributeId(), "jenny");
- Assert.assertEquals(connector.getSalt(), "abcdefghijklmnopqrst ".getBytes());
+ Assert.assertEquals(store.getSalt(), "abcdefghijklmnopqrst ".getBytes());
Assert.assertEquals(connector.getSourceAttributeInformation(), "DC/theSourceRemainsTheSame");
Assert.assertTrue(connector.isInitialized());
}
@Test public void resolverNoSourceDependency() {
- final ComputedIDDataConnector connector = getDataConnector("resolver/computedNoSource1.xml", ComputedIDDataConnector.class);
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/computedNoSource1.xml", PairwiseIdDataConnector.class);
+ final ComputedPairwiseIdStore store = (ComputedPairwiseIdStore) connector.getPairwiseIdStore();
+
Assert.assertEquals(connector.getId(), "computed");
Assert.assertEquals(connector.getGeneratedAttributeId(), "jenny");
- Assert.assertEquals(connector.getSalt(), "abcdefghijklmnopqrst ".getBytes());
+ Assert.assertEquals(store.getSalt(), "abcdefghijklmnopqrst ".getBytes());
Assert.assertEquals(connector.getSourceAttributeInformation(), "theSourceRemainsTheSame");
}
@@ -101,9 +106,11 @@ public class ComputedIDDataConnectorParserTest extends BaseAttributeDefinitionPa
context.refresh();
- final ComputedIDDataConnector connector = context.getBean(ComputedIDDataConnector.class);
+ final PairwiseIdDataConnector connector = context.getBean(PairwiseIdDataConnector.class);
+ final ComputedPairwiseIdStore store = (ComputedPairwiseIdStore) connector.getPairwiseIdStore();
- Assert.assertEquals(connector.getSalt(), salt.getBytes());
+ Assert.assertEquals(store.getSalt(), salt.getBytes());
+ Assert.assertTrue(store.isInitialized());
Assert.assertTrue(connector.isInitialized());
}
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ManagedConnectionTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ManagedConnectionTest.java
index 3ede410..b972537 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ManagedConnectionTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ManagedConnectionTest.java
@@ -40,8 +40,9 @@ import javax.sql.DataSource;
import org.testng.annotations.Test;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
+import net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector;
import net.shibboleth.idp.attribute.resolver.spring.BaseAttributeDefinitionParserTest;
-import net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
/**
@@ -49,13 +50,13 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
*/
public class ManagedConnectionTest extends BaseAttributeDefinitionParserTest {
- @Test(enabled=false) public void simple() throws ComponentInitializationException, NamingException {
+ @Test(enabled=true) public void simple() throws ComponentInitializationException, NamingException {
if (!NamingManager.hasInitialContextFactoryBuilder()) {
NamingManager.setInitialContextFactoryBuilder(new ContextFactoryBuilder() );
}
- final StoredIDDataConnector connector = getDataConnector("resolver/containerManagedConnection.xml", StoredIDDataConnector.class);
- MyDataSource source = (MyDataSource) connector.getDataSource();
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/containerManagedConnection.xml", PairwiseIdDataConnector.class);
+ MyDataSource source = (MyDataSource) ((JDBCPairwiseIdStore) connector.getPairwiseIdStore()).getDataSource();
assertEquals(source.getEnvironment().size(), 2);
assertEquals(source.getEnvironment().get("foo"), "Bar");
assertEquals(source.getEnvironment().get("yellow"), "green");
@@ -98,115 +99,92 @@ public class ManagedConnectionTest extends BaseAttributeDefinitionParserTest {
/** {@inheritDoc} */
public Object addToEnvironment(String propName, Object propVal) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public void bind(Name name, Object obj) throws NamingException {
- // TODO Auto-generated method stub
}
/** {@inheritDoc} */
public void bind(String name, Object obj) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void close() throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public Name composeName(Name name, Name prefix) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public String composeName(String name, String prefix) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public Context createSubcontext(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public Context createSubcontext(String name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public void destroySubcontext(Name name) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void destroySubcontext(String name) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public Hashtable<?, ?> getEnvironment() throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public String getNameInNamespace() throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NameParser getNameParser(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NameParser getNameParser(String name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public Object lookup(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
@@ -220,56 +198,41 @@ public class ManagedConnectionTest extends BaseAttributeDefinitionParserTest {
/** {@inheritDoc} */
public Object lookupLink(Name name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public Object lookupLink(String name) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public void rebind(Name name, Object obj) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void rebind(String name, Object obj) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public Object removeFromEnvironment(String propName) throws NamingException {
- // TODO Auto-generated method stub
return null;
}
/** {@inheritDoc} */
public void rename(Name oldName, Name newName) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void rename(String oldName, String newName) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void unbind(Name name) throws NamingException {
- // TODO Auto-generated method stub
-
}
/** {@inheritDoc} */
public void unbind(String name) throws NamingException {
- // TODO Auto-generated method stub
-
}
}
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/StoredIDDataConnectorParserTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/StoredIDDataConnectorParserTest.java
index fea4f9a..4bd2498 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/StoredIDDataConnectorParserTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/StoredIDDataConnectorParserTest.java
@@ -30,39 +30,46 @@ import net.shibboleth.ext.spring.config.DurationToLongConverter;
import net.shibboleth.ext.spring.config.StringToIPRangeConverter;
import net.shibboleth.ext.spring.config.StringToResourceConverter;
import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.attribute.resolver.ResolverAttributeDefinitionDependency;
+import net.shibboleth.idp.attribute.resolver.dc.impl.PairwiseIdDataConnector;
import net.shibboleth.idp.attribute.resolver.spring.BaseAttributeDefinitionParserTest;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.StoredIDDataConnectorParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.rdbms.RDBMSDataConnectorParserTest;
-import net.shibboleth.idp.saml.attribute.resolver.impl.StoredIDDataConnector;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
/**
- * test for {@link StoredIDDataConnectorParser}
+ * Test for {@link StoredIDDataConnectorParser}.
*/
public class StoredIDDataConnectorParserTest extends BaseAttributeDefinitionParserTest {
- private void testIt(final StoredIDDataConnector connector) throws ComponentInitializationException {
+ private void testIt(final PairwiseIdDataConnector connector) throws ComponentInitializationException {
+
+ final JDBCPairwiseIdStore store = (JDBCPairwiseIdStore) connector.getPairwiseIdStore();
+
Assert.assertEquals(connector.getId(), "stored");
Assert.assertEquals(connector.getGeneratedAttributeId(), "jenny");
- Assert.assertEquals(connector.getTransactionRetries(), 5);
- Assert.assertEquals(connector.getQueryTimeout(), 5000);
- Assert.assertEquals(connector.getFailFast(), false);
- Assert.assertTrue(Arrays.equals(connector.getRetryableErrors().toArray(), new String[]{"25000", "25001"}));
+ Assert.assertEquals(store.getTransactionRetries(), 5);
+ Assert.assertEquals(store.getQueryTimeout(), 5000);
+ Assert.assertEquals(store.getVerifyDatabase(), false);
+ Assert.assertTrue(Arrays.equals(store.getRetryableErrors().toArray(), new String[]{"25000", "25001"}));
connector.initialize();
}
@Test public void withSalt() throws ComponentInitializationException {
- final StoredIDDataConnector connector = getDataConnector("resolver/stored.xml", StoredIDDataConnector.class);
-
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/stored.xml", PairwiseIdDataConnector.class);
+ final JDBCPairwiseIdStore store = (JDBCPairwiseIdStore) connector.getPairwiseIdStore();
+ final ComputedPairwiseIdStore store2 = (ComputedPairwiseIdStore) store.getInitialValueStore();
+
final ResolverAttributeDefinitionDependency attrib = connector.getAttributeDependencies().iterator().next();
Assert.assertEquals(attrib.getDependencyPluginId(), "theSourceRemainsTheSame");
- Assert.assertEquals(connector.getSalt(), "abcdefghijklmnopqrst".getBytes());
+ Assert.assertEquals(store2.getSalt(), "abcdefghijklmnopqrst".getBytes());
testIt(connector);
}
- protected StoredIDDataConnector getStoredDataConnector(final String... beanDefinitions) throws IOException {
+ protected PairwiseIdDataConnector getStoredDataConnector(final String... beanDefinitions) throws IOException {
final GenericApplicationContext context = new GenericApplicationContext();
setTestContext(context);
context.setDisplayName("ApplicationContext: " + RDBMSDataConnectorParserTest.class);
@@ -81,22 +88,25 @@ public class StoredIDDataConnectorParserTest extends BaseAttributeDefinitionPars
beanDefinitionReader.loadBeanDefinitions(beanDefinitions);
context.refresh();
- return (StoredIDDataConnector) context.getBean(StoredIDDataConnector.class);
+ return (PairwiseIdDataConnector) context.getBean(PairwiseIdDataConnector.class);
}
@Test public void beanManaged() throws ComponentInitializationException, IOException {
- final StoredIDDataConnector connector = getStoredDataConnector(DATACONNECTOR_FILE_PATH + "resolver/storedBeanManaged.xml",
+ final PairwiseIdDataConnector connector = getStoredDataConnector(DATACONNECTOR_FILE_PATH + "resolver/storedBeanManaged.xml",
DATACONNECTOR_FILE_PATH + "rdbms/rdbms-attribute-resolver-spring-context.xml");
+ final JDBCPairwiseIdStore store = (JDBCPairwiseIdStore) connector.getPairwiseIdStore();
+ final ComputedPairwiseIdStore store2 = (ComputedPairwiseIdStore) store.getInitialValueStore();
+
final ResolverAttributeDefinitionDependency attrib = connector.getAttributeDependencies().iterator().next();
Assert.assertEquals(attrib.getDependencyPluginId(), "theSourceRemainsTheSame");
- Assert.assertEquals(connector.getSalt(), "abcdefghijklmnopqrst".getBytes());
+ Assert.assertEquals(store2.getSalt(), "abcdefghijklmnopqrst".getBytes());
testIt(connector);
}
@Test public void withOutSalt() throws ComponentInitializationException {
- final StoredIDDataConnector connector = getDataConnector("resolver/storedNoSalt.xml", StoredIDDataConnector.class);
+ final PairwiseIdDataConnector connector = getDataConnector("resolver/storedNoSalt.xml", PairwiseIdDataConnector.class);
final ResolverAttributeDefinitionDependency attrib = connector.getAttributeDependencies().iterator().next();
Assert.assertEquals(attrib.getDependencyPluginId(), "theSourceRemainsTheSame");
testIt(connector);
diff --git a/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml b/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
index b8e02f5..6f69cda 100644
--- a/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
+++ b/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
@@ -28,7 +28,7 @@
<bean id="shibboleth.SAML2PersistentGenerator" lazy-init="true"
class="net.shibboleth.idp.saml.nameid.impl.PersistentSAML2NameIDGenerator"
p:useUnfilteredAttributes="%{idp.persistentId.useUnfilteredAttributes:true}"
- p:persistentIdGenerator-ref="#{'%{idp.persistentId.generator:shibboleth.ComputedPersistentIdGenerator}'.trim()}">
+ p:persistentIdStore-ref="#{'%{idp.persistentId.store:%{idp.persistentId.generator:shibboleth.ComputedPersistentIdGenerator}}'.trim()}">
<property name="attributeSourceIds">
<bean parent="shibboleth.CommaDelimStringArray" c:_0="#{'%{idp.persistentId.sourceAttribute:}'.trim()}" />
</property>
@@ -58,22 +58,20 @@
p:dataSealer-ref="shibboleth.DataSealer" />
<bean id="shibboleth.ComputedPersistentIdGenerator" lazy-init="true"
- class="net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy"
+ class="net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore"
p:salt="%{idp.persistentId.salt:}"
p:encodedSalt="%{idp.persistentId.encodedSalt:}"
p:exceptionMap="#{getObject('%{idp.persistentId.exceptionMap:shibboleth.ComputedIdExceptionMap}'.trim())}"
p:algorithm="%{idp.persistentId.algorithm:SHA}"
- p:encoding="#{ T(net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding).%{idp.persistentId.encoding:BASE64} }" />
+ p:encoding="#{ T(net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore.Encoding).%{idp.persistentId.encoding:BASE64} }" />
- <bean id="shibboleth.StoredPersistentIdGenerator" lazy-init="true"
- class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdGenerationStrategy"
- p:computedIdStrategy="#{getObject('%{idp.persistentId.computed:shibboleth.ComputedPersistentIdGenerator}'.trim())}"
- p:IDStore="#{getObject('%{idp.persistentId.store:undefined}'.trim())}"
+ <bean id="shibboleth.StoredPersistentIdGenerator" parent="shibboleth.JDBCPersistentIdStore" lazy-init="true"
p:dataSource="#{getObject('%{idp.persistentId.dataSource:undefined}'.trim())}" />
<!-- Parent bean for users to configure a custom ID store rather than a data source only. -->
<bean id="shibboleth.JDBCPersistentIdStore" abstract="true"
- class="net.shibboleth.idp.saml.nameid.impl.JDBCPersistentIdStoreEx" />
+ class="net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore"
+ p:initialValueStore="#{getObject('%{idp.persistentId.computed:shibboleth.ComputedPersistentIdGenerator}'.trim())}" />
<!--
This is the actual service being exposed, and it takes a pair of generators that are
diff --git a/idp-parent/pom.xml b/idp-parent/pom.xml
index bc5099a..2ff2209 100644
--- a/idp-parent/pom.xml
+++ b/idp-parent/pom.xml
@@ -40,6 +40,7 @@
<module>../idp-admin-impl</module>
<module>../idp-authn-impl</module>
+ <module>../idp-attribute-impl</module>
<module>../idp-attribute-resolver-impl</module>
<module>../idp-attribute-filter-impl</module>
<module>../idp-cas-impl</module>
diff --git a/idp-saml-impl/pom.xml b/idp-saml-impl/pom.xml
index 71e95cc..51acbd8 100644
--- a/idp-saml-impl/pom.xml
+++ b/idp-saml-impl/pom.xml
@@ -46,6 +46,11 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>idp-attribute-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>idp-profile-api</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/ComputedIDDataConnector.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/ComputedIDDataConnector.java
deleted file mode 100644
index dbc8768..0000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/ComputedIDDataConnector.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.saml.attribute.resolver.impl;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import net.shibboleth.idp.attribute.IdPAttribute;
-import net.shibboleth.idp.attribute.resolver.ResolutionException;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
-import net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy;
-import net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-
-import org.opensaml.saml.common.SAMLException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Strings;
-
-/**
- * A data connector that delegates generation of IDs to a {@link ComputedPersistentIdGenerationStrategy}.
- */
-public class ComputedIDDataConnector extends AbstractPersistentIdDataConnector {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(ComputedIDDataConnector.class);
-
- /** Generation strategy for IDs. */
- @Nullable private ComputedPersistentIdGenerationStrategy idStrategy;
-
- /** Constructor. */
- public ComputedIDDataConnector() {
- idStrategy = new ComputedPersistentIdGenerationStrategy();
- }
-
- /**
- * Get the strategy plugin that generates computed IDs.
- *
- * @return strategy for computing IDs
- */
- @Nullable public ComputedPersistentIdGenerationStrategy getComputedIdStrategy() {
- return idStrategy;
- }
-
- /**
- * Clear the strategy plugin that generates computed IDs. This is needed
- * to allow the {@link StoredIDDataConnector}to work if no salt is configured.
- */
- @Nullable protected void clearComputedIdStrategy() {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- idStrategy = null;
- }
-
- /**
- * Get the salt used when computing the ID.
- *
- * @return salt used when computing the ID
- */
- @Nullable public byte[] getSalt() {
- if (null == idStrategy) {
- return null;
- }
- return idStrategy.getSalt();
- }
-
- /**
- * Set the salt used when computing the ID.
- *
- * @param salt used when computing the ID
- */
- public void setSalt(@Nullable final byte[] salt) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- if (null != salt) {
- log.debug("{} Salt set (secret is logged at TRACE)", getLogPrefix());
- log.trace("{} Salt set as bytes to {}", getLogPrefix(), Arrays.toString(salt));
- idStrategy.setSalt(salt);
- } else {
- log.debug("{} Null salt passed, nothing set", getLogPrefix());
- }
- }
-
- /**
- * Set the salt used when computing the ID.
- *
- * @param salt used when computing the ID
- */
- public void setSalt(@Nullable final String salt) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- if (null != salt) {
- setSalt(salt.getBytes());
- } else {
- log.debug("{} Null salt passed, nothing set", getLogPrefix());
- }
- }
-
- /**
- * Get the JCE algorithm name of the digest algorithm to use (default is SHA).
- *
- * @return JCE message digest algorithm
- */
- @Nullable @NotEmpty public String getAlgorithm() {
- if (null == idStrategy) {
- return null;
- }
- return idStrategy.getAlgorithm();
- }
-
- /**
- * Set the JCE algorithm name of the digest algorithm to use (default is SHA).
- *
- * @param alg JCE message digest algorithm
- */
- public void setAlgorithm(@Nonnull @NotEmpty final String alg) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStrategy.setAlgorithm(alg);
- }
-
- /**
- * Get the post-digest encoding to use.
- *
- * @return encoding
- *
- * @since 3.4.0
- */
- @Nullable public Encoding getEncoding() {
- if (null == idStrategy) {
- return null;
- }
- return idStrategy.getEncoding();
- }
-
- /**
- * Set the post-digest encoding to use.
- *
- * @param enc encoding
- *
- * @since 3.4.0
- */
- public void setEncoding(@Nonnull final Encoding enc) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStrategy.setEncoding(enc);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (null != idStrategy) {
- idStrategy.initialize();
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doDestroy() {
- if (null != idStrategy) {
- idStrategy.destroy();
- }
-
- super.doDestroy();
- }
-
- /** {@inheritDoc} */
- @Override
- @Nullable protected Map<String, IdPAttribute> doDataConnectorResolve(
- @Nonnull final AttributeResolutionContext resolutionContext,
- @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {
-
- ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- if (null == idStrategy) {
- log.error("{} Resolve called for seedless stored ID", getLogPrefix());
- throw new ResolutionException(getLogPrefix() + " Resolve called for seedless stored ID");
- }
-
- final String principalName = resolutionContext.getPrincipal();
- if (Strings.isNullOrEmpty(principalName)) {
- log.warn("{} No principal name located, unable to compute ID", getLogPrefix());
- return null;
- }
-
- final String attributeIssuerId = resolutionContext.getAttributeIssuerID();
- if (Strings.isNullOrEmpty(attributeIssuerId)) {
- log.warn("{} No Attribute issuer ID located, unable to compute ID", getLogPrefix());
- return null;
- }
-
- String attributeRecipientID = resolutionContext.getAttributeRecipientGroupID();
- if (Strings.isNullOrEmpty(attributeRecipientID)) {
- attributeRecipientID = resolutionContext.getAttributeRecipientID();
- }
- if (Strings.isNullOrEmpty(attributeRecipientID)) {
- log.warn("{} No Attribute recipient or group ID located, unable to compute ID", getLogPrefix());
- return null;
- }
-
- final String sourceId = resolveSourceAttribute(workContext);
- if (Strings.isNullOrEmpty(sourceId)) {
- return null;
- }
-
- try {
- return encodeAsAttribute(idStrategy.generate(attributeIssuerId, attributeRecipientID, principalName,
- sourceId));
- } catch (final SAMLException e) {
- throw new ResolutionException(e);
- }
- }
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/StoredIDDataConnector.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/StoredIDDataConnector.java
deleted file mode 100644
index bb5aa19..0000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/attribute/resolver/impl/StoredIDDataConnector.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.saml.attribute.resolver.impl;
-
-import java.util.Collection;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.sql.DataSource;
-
-import net.shibboleth.idp.attribute.IdPAttribute;
-import net.shibboleth.idp.attribute.resolver.ResolutionException;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
-import net.shibboleth.idp.saml.nameid.impl.JDBCPersistentIdStoreEx;
-import net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdGenerationStrategy;
-import net.shibboleth.utilities.java.support.annotation.Duration;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-
-import org.opensaml.saml.common.SAMLException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Strings;
-
-/**
- * A data connector that delegates generation of IDs to a {@link StoredPersistentIdGenerationStrategy}
- * that makes use of a {@link JDBCPersistentIdStoreEx}.
- */
-public class StoredIDDataConnector extends ComputedIDDataConnector {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(StoredIDDataConnector.class);
-
- /** The {@link JDBCPersistentIdStoreEx} used to manage IDs. */
- @Nonnull private final JDBCPersistentIdStoreEx idStore;
-
- /** Persistent ID generation mechanism. */
- @Nonnull private final StoredPersistentIdGenerationStrategy storedIdStrategy;
-
- /** Constructor. */
- public StoredIDDataConnector() {
- idStore = new JDBCPersistentIdStoreEx();
- idStore.setVerifyDatabase(false);
- storedIdStrategy = new StoredPersistentIdGenerationStrategy();
- }
-
- /**
- * Get the {@link DataSource} used to communicate with the database.
- *
- * @return the {@link DataSource}
- */
- @NonnullAfterInit public DataSource getDataSource() {
- return idStore.getDataSource();
- }
-
- /**
- * Set the {@link DataSource} used to communicate with the database.
- *
- * @param source the {@link DataSource}.
- */
- public void setDataSource(@Nonnull final DataSource source) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStore.setDataSource(source);
- }
-
- /**
- * Get the data store used to manage stored IDs.
- *
- * @return data store used to manage stored IDs
- */
- @Nonnull public JDBCPersistentIdStoreEx getStoredIDStore() {
- return idStore;
- }
-
- /**
- * 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.
- *
- * @return retryable messages
- */
- @Nonnull @NonnullElements public Collection<String> getRetryableErrors() {
- return idStore.getRetryableErrors();
- }
-
- /**
- * 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.
- *
- * @param errors retryable messages
- */
- public void setRetryableErrors(@Nullable @NonnullElements final Collection<String> errors) {
- idStore.setRetryableErrors(errors);
- }
-
- /**
- * Get the SQL query timeout.
- *
- * @return the timeout in milliseconds
- */
- @Duration @NonNegative public long getQueryTimeout() {
- return idStore.getQueryTimeout();
- }
-
- /**
- * Set the SQL query timeout.
- *
- * @param timeout the timeout to set in seconds
- */
- @Duration public void setQueryTimeout(@Duration @NonNegative final long timeout) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStore.setQueryTimeout(timeout);
- }
-
- /**
- * Get the number of retries to attempt for a failed transaction.
- *
- * @return number of retries
- */
- public int getTransactionRetries() {
- return idStore.getTransactionRetries();
- }
-
- /**
- * Set the number of retries to attempt for a failed transaction. Defaults to 3.
- *
- * @param retries the number of retries
- */
- public void setTransactionRetries(@NonNegative final int retries) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStore.setTransactionRetries(retries);
- }
-
- /**
- * Get whether to allow startup if the database cannot be verified.
- *
- * @return whether to allow startup if the database cannot be verified
- */
- public boolean getFailFast() {
- return idStore.getVerifyDatabase();
- }
-
- /**
- * Set whether to allow startup if the database cannot be verified.
- *
- * <p>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.</p>
- *
- * @param flag flag to set
- */
- public void setFailFast(final boolean flag) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idStore.setVerifyDatabase(flag);
- }
-
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
- if (getSalt() == null) {
- clearComputedIdStrategy();
- }
- super.doInitialize();
-
- idStore.initialize();
-
- storedIdStrategy.setIDStore(idStore);
- storedIdStrategy.setComputedIdStrategy(getComputedIdStrategy());
- storedIdStrategy.initialize();
- }
-
- /** {@inheritDoc} */
- @Override protected void doDestroy() {
- storedIdStrategy.destroy();
- idStore.destroy();
-
- super.doDestroy();
- }
-
- /** {@inheritDoc} */
- @Override @Nullable protected Map<String, IdPAttribute> doDataConnectorResolve(
- @Nonnull final AttributeResolutionContext resolutionContext,
- @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {
-
- ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- final String principalName = resolutionContext.getPrincipal();
- if (Strings.isNullOrEmpty(principalName)) {
- log.warn("{} No principal available, skipping ID creation", getLogPrefix());
- return null;
- }
-
- final String sourceId = resolveSourceAttribute(workContext);
- if (Strings.isNullOrEmpty(sourceId)) {
- return null;
- }
-
- final String attributeIssuerID = resolutionContext.getAttributeIssuerID();
- if (Strings.isNullOrEmpty(attributeIssuerID)) {
- log.warn("{} Could not get attribute issuer ID, skipping ID creation", getLogPrefix());
- return null;
- }
-
- String attributeRecipientID = resolutionContext.getAttributeRecipientGroupID();
- if (Strings.isNullOrEmpty(attributeRecipientID)) {
- attributeRecipientID = resolutionContext.getAttributeRecipientID();
- }
- if (Strings.isNullOrEmpty(attributeRecipientID)) {
- log.warn("{} Could not get attribute recipient or group ID, skipping ID creation", getLogPrefix());
- return null;
- }
-
- try {
- return encodeAsAttribute(storedIdStrategy.generate(attributeIssuerID, attributeRecipientID, principalName,
- sourceId));
- } catch (final SAMLException e) {
- throw new ResolutionException(e);
- }
- }
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdGenerationStrategy.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdGenerationStrategy.java
deleted file mode 100644
index 63a5755..0000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdGenerationStrategy.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.saml.nameid.impl;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.saml.common.SAMLException;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-
-/**
- * Generates and manages persistent identifiers according to specific strategies.
- */
-public interface PersistentIdGenerationStrategy {
-
- /**
- * Get a Persistent ID that corresponds to the inputs.
- *
- * <p>This may be generated directly from the inputs or retrieved from some other source.</p>
- *
- * @param assertingPartyId the asserting party providing the identifier
- * @param relyingPartyId the relying party for whom we're obtaining the identifier
- * @param principalName name of the subject
- * @param sourceId an underlying identifier for the subject
- *
- * @return the identifier
- * @throws SAMLException if an error occurs generating the identifier
- */
- @Nonnull @NotEmpty String generate(@Nonnull @NotEmpty final String assertingPartyId,
- @Nonnull @NotEmpty final String relyingPartyId, @Nonnull @NotEmpty final String principalName,
- @Nonnull @NotEmpty final String sourceId) throws SAMLException;
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdStoreEx.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdStoreEx.java
deleted file mode 100644
index 1605e0a..0000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentIdStoreEx.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.saml.nameid.impl;
-
-import java.io.IOException;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import net.shibboleth.idp.saml.nameid.PersistentIdEntry;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-
-import org.joda.time.DateTime;
-
-/**
- * Storage and retrieval interface for SAML persistent IDs redesigned to support appropriately
- * atomic behavior.
- */
-public interface PersistentIdStoreEx {
-
- /**
- * Get the {@link PersistentIdEntry} for a previously issued ID triple.
- *
- * @param nameQualifier the NameQualifier value
- * @param spNameQualifier the SPNameQualifier value
- * @param persistentId the persistent ID value
- *
- * @return {@link PersistentIdEntry} for the given inputs or null if none exists
- * @throws IOException if an error occurs accessing the store
- */
- @Nullable PersistentIdEntry getByIssuedValue(@Nonnull @NotEmpty final String nameQualifier,
- @Nonnull @NotEmpty final String spNameQualifier, @Nonnull @NotEmpty final String persistentId)
- throws IOException;
-
-// Checkstyle: ParameterNumber OFF
- /**
- * Get the {@link PersistentIdEntry} for a given subject and audience, creating one if allowable
- * and necessary.
- *
- * @param nameQualifier the NameQualifier value
- * @param spNameQualifier the SPNameQualifier value
- * @param sourceId source attribute underlying the persistent ID
- * @param principal principal name of subject (may or may not be the same as the sourceId)
- * @param allowCreate whether it's permissible to establish/issue a new identifier
- * @param computedIdStrategy optional source of initial computed IDs for compatibilty with that mechanism
- *
- * @return {@link PersistentIdEntry} for the given inputs, or null if none exists and allowCreate is false
- * @throws IOException if an error occurs accessing the store
- */
- @Nullable PersistentIdEntry getBySourceValue(@Nonnull @NotEmpty final String nameQualifier,
- @Nonnull @NotEmpty final String spNameQualifier, @Nonnull @NotEmpty final String sourceId,
- @Nonnull @NotEmpty final String principal, final boolean allowCreate,
- @Nullable final ComputedPersistentIdGenerationStrategy computedIdStrategy) throws IOException;
-// Checkstyle: ParameterNumber ON
-
- /**
- * Deactivate/revoke a persistent ID.
- *
- * @param nameQualifier the NameQualifier value
- * @param spNameQualifier the SPNameQualifier value
- * @param persistentId ID to deactivate
- * @param deactivation deactivation time (if null the current time is used)
- *
- * @throws IOException if there is an error updating the store
- */
- void deactivate(@Nonnull @NotEmpty final String nameQualifier, @Nonnull @NotEmpty final String spNameQualifier,
- @Nonnull @NotEmpty final String persistentId, @Nullable final DateTime deactivation) throws IOException;
-
- /**
- * Attach an SPProvidedID value to an existing entry.
- *
- * @param nameQualifier the NameQualifier value
- * @param spNameQualifier the SPNameQualifier value
- * @param persistentId ID to deactivate
- * @param spProvidedId the value to attach
- *
- * @throws IOException if there is an error updating the store
- */
- void attach(@Nonnull @NotEmpty final String nameQualifier, @Nonnull @NotEmpty final String spNameQualifier,
- @Nonnull @NotEmpty final String persistentId, @Nonnull @NotEmpty final String spProvidedId)
- throws IOException;
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
index e223e29..9db0aaf 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
@@ -17,6 +17,7 @@
package net.shibboleth.idp.saml.nameid.impl;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -25,12 +26,16 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.sql.DataSource;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.PairwiseIdStore;
import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
import net.shibboleth.idp.attribute.StringAttributeValue;
import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.profile.context.navigate.RelyingPartyIdLookupFunction;
@@ -65,16 +70,19 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
@Nonnull private final Logger log = LoggerFactory.getLogger(PersistentSAML2NameIDGenerator.class);
/** Strategy function to lookup SubjectContext. */
- @Nonnull private Function<ProfileRequestContext, SubjectContext> subjectContextLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext,SubjectContext> subjectContextLookupStrategy;
/** Strategy function to lookup AttributeContext. */
- @Nonnull private Function<ProfileRequestContext, AttributeContext> attributeContextLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext,AttributeContext> attributeContextLookupStrategy;
/** Attribute(s) to use as an identifier source. */
@Nonnull @NonnullElements private List<String> attributeSourceIds;
- /** Generation strategy for IDs. */
- @NonnullAfterInit private PersistentIdGenerationStrategy persistentIdStrategy;
+ /** Store for IDs. */
+ @NonnullAfterInit private PairwiseIdStore pidStore;
+
+ /** A DataSource to auto-provision a {@link JDBCPairwiseIdStore} instance. */
+ @Nullable private DataSource dataSource;
/** Predicate to select whether to look at filtered or unfiltered attributes. */
private boolean useUnfilteredAttributes;
@@ -98,7 +106,7 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
* @param strategy lookup function to use
*/
public void setSubjectContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, SubjectContext> strategy) {
+ @Nonnull final Function<ProfileRequestContext,SubjectContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
subjectContextLookupStrategy = Constraint.isNotNull(strategy, "SubjectContext lookup strategy cannot be null");
@@ -110,7 +118,7 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
* @param strategy lookup function to use
*/
public void setAttributeContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, AttributeContext> strategy) {
+ @Nonnull final Function<ProfileRequestContext,AttributeContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
attributeContextLookupStrategy =
@@ -130,17 +138,29 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
}
/**
- * Set the generation strategy for the persistent ID.
+ * Set a {@link PairwiseIdStore} to use.
*
- * @param strategy generation strategy
+ * @param store the id store
*/
- public void setPersistentIdGenerator(@Nonnull final PersistentIdGenerationStrategy strategy) {
+ public void setPersistentIdStore(@Nullable final PairwiseIdStore store) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- persistentIdStrategy = Constraint.isNotNull(strategy, "PersistentIdGenerationStrategy cannot be null");
+
+ pidStore = store;
}
/**
+ * Set a data source to inject into an auto-provisioned instance of {@link JDBCPairwiseIdStore}
+ * to use as the store.
+ *
+ * @param source data source
+ */
+ public void setDataSource(@Nullable final DataSource source) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ dataSource = source;
+ }
+
+ /**
* Set whether to source the input attributes from the unfiltered set.
*
* <p>Defaults to true, since the input is not directly exposed.</p>
@@ -155,11 +175,23 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
@Override protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
- if (persistentIdStrategy == null) {
- throw new ComponentInitializationException("PersistentIdGenerationStrategy cannot be null");
- } else if (attributeSourceIds.isEmpty()) {
+ if (attributeSourceIds.isEmpty()) {
throw new ComponentInitializationException("Attribute source ID list cannot be empty");
}
+
+ if (null == pidStore) {
+ if (dataSource != null) {
+ log.debug("Creating JDBCPersistentStoreEx instance around supplied DataSource");
+ final JDBCPairwiseIdStore newStore = new JDBCPairwiseIdStore();
+ newStore.setDataSource(dataSource);
+ newStore.initialize();
+ pidStore = newStore;
+ }
+
+ if (null == pidStore) {
+ throw new ComponentInitializationException("PairwiseIdStore cannot be null");
+ }
+ }
}
// Checkstyle: CyclomaticComplexity|MethodLength OFF
@@ -167,7 +199,7 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
@Override @Nullable protected String getIdentifier(@Nonnull final ProfileRequestContext profileRequestContext)
throws SAMLException {
- Function<ProfileRequestContext, String> lookup = getDefaultIdPNameQualifierLookupStrategy();
+ Function<ProfileRequestContext,String> lookup = getDefaultIdPNameQualifierLookupStrategy();
final String responderId = lookup != null ? lookup.apply(profileRequestContext) : null;
if (responderId == null) {
log.debug("No responder identifier, can't generate persistent ID");
@@ -208,24 +240,35 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
continue;
}
+ PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(responderId);
+ pid.setRecipientEntityID(relyingPartyId);
+ pid.setPrincipalName(subjectCtx.getPrincipalName());
+
final List<IdPAttributeValue<?>> values = attribute.getValues();
for (final IdPAttributeValue value : values) {
- if (value instanceof ScopedStringAttributeValue) {
- log.debug("Generating persistent NameID from Scoped String-valued attribute {}", sourceId);
- return persistentIdStrategy.generate(responderId, relyingPartyId, subjectCtx.getPrincipalName(),
- ((ScopedStringAttributeValue) value).getValue() + '@'
- + ((ScopedStringAttributeValue) value).getScope());
- } else if (value instanceof StringAttributeValue) {
- // Check for all whitespace, but don't trim the value used.
- if (StringSupport.trimOrNull((String) value.getValue()) == null) {
- log.debug("Skipping all-whitespace string value");
- continue;
+ try {
+ if (value instanceof ScopedStringAttributeValue) {
+ log.debug("Generating persistent NameID from Scoped String-valued attribute {}", sourceId);
+ pid.setSourceSystemId(((ScopedStringAttributeValue) value).getValue() + '@'
+ + ((ScopedStringAttributeValue) value).getScope());
+ pid = pidStore.getBySourceValue(pid, true);
+ return pid.getPairwiseId();
+ } else if (value instanceof StringAttributeValue) {
+ // Check for all whitespace, but don't trim the value used.
+ if (StringSupport.trimOrNull((String) value.getValue()) == null) {
+ log.debug("Skipping all-whitespace string value");
+ continue;
+ }
+ log.debug("Generating persistent NameID from String-valued attribute {}", sourceId);
+ pid.setSourceSystemId((String) value.getValue());
+ pid = pidStore.getBySourceValue(pid, true);
+ return pid.getPairwiseId();
+ } else {
+ log.info("Unrecognized attribute value type: {}", value.getClass().getName());
}
- log.debug("Generating persistent NameID from String-valued attribute {}", sourceId);
- return persistentIdStrategy.generate(responderId, relyingPartyId, subjectCtx.getPrincipalName(),
- (String) value.getValue());
- } else {
- log.info("Unrecognized attribute value type: {}", value.getClass().getName());
+ } catch (final IOException e) {
+ throw new SAMLException(e);
}
}
}
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
index 9bac79f..41d6c70 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
@@ -27,10 +27,12 @@ import org.opensaml.saml.saml2.core.NameID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import net.shibboleth.idp.attribute.DurablePairwiseIdStore;
+import net.shibboleth.idp.attribute.PairwiseId;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.saml.nameid.NameDecoderException;
import net.shibboleth.idp.saml.nameid.NameIDDecoder;
-import net.shibboleth.idp.saml.nameid.PersistentIdEntry;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
@@ -38,8 +40,8 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
import net.shibboleth.utilities.java.support.component.ComponentSupport;
/**
- * An abstract action which contains the logic to decode SAML persistent IDs that are managed with a store.
- * This reverses the work done by {@link StoredPersistentIdGenerationStrategy}.
+ * An abstract decoder which contains the logic to decode SAML persistent IDs that are managed with a
+ * {@link DurablePairwiseIdStore}.
*/
public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializableComponent implements NameIDDecoder {
@@ -47,27 +49,27 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
@Nonnull private final Logger log = LoggerFactory.getLogger(StoredPersistentIdDecoder.class);
/** Updated version of persistent identifier data store layer. */
- @NonnullAfterInit private PersistentIdStoreEx pidStore;
+ @NonnullAfterInit private DurablePairwiseIdStore pidStore;
- /** A DataSource to auto-provision a {@link JDBCPersistentIdStoreEx} instance. */
+ /** A DataSource to auto-provision a {@link JDBCPairwiseIdStore} instance. */
@Nullable private DataSource dataSource;
/**
- * Set a data store to use.
+ * Set a {@link DurablePairwiseIdStore} to use.
*
- * @param store the data store
+ * @param store the id store
*/
- public void setPersistentIdStore(@Nullable final PersistentIdStoreEx store) {
+ public void setPersistentIdStore(@Nullable final DurablePairwiseIdStore store) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- pidStore = (PersistentIdStoreEx) store;
+ pidStore = store;
}
/**
- * Set a data source to inject into an auto-provisioned instance of {@link JDBCPersistentIdStoreEx}
- * to use as the storage strategy.
+ * Set a data source to inject into an auto-provisioned instance of {@link JDBCPairwiseIdStore}
+ * to use as the store.
*
- * @param source the data source
+ * @param source data source
*/
public void setDataSource(@Nullable final DataSource source) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
@@ -81,8 +83,8 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
if (null == pidStore) {
if (dataSource != null) {
- log.debug("Creating JDBCPersistentStoreEx instance around supplied DataSource");
- final JDBCPersistentIdStoreEx newStore = new JDBCPersistentIdStoreEx();
+ log.debug("Creating JDBCPairwiseIdStore instance around supplied DataSource");
+ final JDBCPairwiseIdStore newStore = new JDBCPairwiseIdStore();
// Don't validate the database because this side is just reading data.
newStore.setVerifyDatabase(false);
newStore.setDataSource(dataSource);
@@ -91,7 +93,7 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
}
if (null == pidStore) {
- throw new ComponentInitializationException("PersistentIdStore cannot be null");
+ throw new ComponentInitializationException("PairwiseIdStore cannot be null");
}
}
}
@@ -122,12 +124,16 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
}
try {
- final PersistentIdEntry entry = pidStore.getByIssuedValue(issuerID, recipientID, nameID.getValue());
- if (entry == null || entry.getPrincipalName() == null) {
+ PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(issuerID);
+ pid.setRecipientEntityID(recipientID);
+ pid.setPairwiseId(nameID.getValue());
+ pid = pidStore.getByIssuedValue(pid);
+ if (pid == null || pid.getPrincipalName() == null) {
log.info("No entry found for persistent ID {}", nameID.getValue());
return null;
}
- return entry.getPrincipalName();
+ return pid.getPrincipalName();
} catch (final IOException e) {
log.error("I/O error looking up persistent ID", e);
return null;
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdGenerationStrategy.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdGenerationStrategy.java
deleted file mode 100644
index e8ea9b4..0000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdGenerationStrategy.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.saml.nameid.impl;
-
-import java.io.IOException;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.sql.DataSource;
-
-import net.shibboleth.idp.saml.nameid.PersistentIdEntry;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
-
-import org.opensaml.saml.common.SAMLException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Manages persistent IDs via a {@link PersistentIdStore}, generating them either randomly or via a
- * {@link ComputedPersistentIdGenerationStrategy} (for compatibility with existing data).
- */
-public class StoredPersistentIdGenerationStrategy extends AbstractInitializableComponent
- implements PersistentIdGenerationStrategy {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(StoredPersistentIdGenerationStrategy.class);
-
- /** Updated version of persistent identifier data store layer. */
- @NonnullAfterInit private PersistentIdStoreEx pidStore;
-
- /** A DataSource to auto-provision a {@link JDBCPersistentIdStoreEx} instance. */
- @Nullable private DataSource dataSource;
-
- /** Optional generator of computed ID values. */
- @Nullable private ComputedPersistentIdGenerationStrategy computedIdStrategy;
-
- /**
- * Set a {@link PersistentIdStoreEx} used to store the IDs.
- *
- * @param store the ID store to use
- */
- public void setIDStore(@Nullable final PersistentIdStoreEx store) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- pidStore = (PersistentIdStoreEx) store;
- }
-
- /**
- * Set a data source to inject into an auto-provisioned instance of {@link JDBCPersistentIdStoreEx}
- * to use as the storage strategy.
- *
- * @param source the data source
- */
- public void setDataSource(@Nullable final DataSource source) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- dataSource = source;
- }
-
- /**
- * Set a strategy to use to compute IDs for the first time.
- *
- * @param strategy computed ID strategy
- */
- public void setComputedIdStrategy(@Nullable final ComputedPersistentIdGenerationStrategy strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- computedIdStrategy = strategy;
- }
-
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (null == pidStore) {
- if (dataSource != null) {
- log.debug("Creating JDBCPersistentStoreEx instance around supplied DataSource");
- final JDBCPersistentIdStoreEx newStore = new JDBCPersistentIdStoreEx();
- newStore.setDataSource(dataSource);
- newStore.initialize();
- pidStore = newStore;
- }
-
- if (null == pidStore) {
- throw new ComponentInitializationException("PersistentIdStore cannot be null");
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- @Nonnull @NotEmpty public String generate(@Nonnull @NotEmpty final String assertingPartyId,
- @Nonnull @NotEmpty final String relyingPartyId, @Nonnull @NotEmpty final String principalName,
- @Nonnull @NotEmpty final String sourceId) throws SAMLException {
- ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
- try {
- final PersistentIdEntry idEntry = pidStore.getBySourceValue(assertingPartyId, relyingPartyId, sourceId,
- principalName, true, computedIdStrategy);
- if (idEntry == null) {
- log.debug("No persistent ID returned from storage for '{}'", principalName);
- throw new SAMLException("No persistent ID returned from storage");
- }
-
- log.debug("Obtained persistent ID entry: {}", idEntry);
-
- final String pid = StringSupport.trimOrNull(idEntry.getPersistentId());
- if (null == pid) {
- log.debug("Returned persistent ID was null");
- throw new SAMLException("Returned persistent ID was null");
- }
-
- return pid;
- } catch (final IOException e) {
- log.debug("ID storage error obtaining persistent identifier", e);
- throw new SAMLException("ID storage error obtaining persistent identifier", e);
- }
- }
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
index efc669d..8dd787d 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
@@ -22,21 +22,21 @@ import java.util.Collections;
import javax.sql.DataSource;
import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.PairwiseId;
import net.shibboleth.idp.attribute.StringAttributeValue;
import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.RequestContextBuilder;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.saml.impl.TestSources;
-import net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding;
import net.shibboleth.idp.testing.DatabaseTestingSupport;
-import net.shibboleth.utilities.java.support.codec.Base64Support;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import org.opensaml.core.OpenSAMLInitBaseTestCase;
import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.saml.common.SAMLException;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.saml.saml2.core.NameIDPolicy;
@@ -54,14 +54,8 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
/** Value calculated using V2 version. DO NOT CHANGE WITHOUT TESTING AGAINST 2.0 */
private static final String RESULT = "Vl6z6K70iLc4AuBoNeb59Dj1rGw=";
- private static final String RESULT2 = "kLyH1uEvYigEvg1ZLh/QXeW1VAs=";
-
- private static final String B32RESULT = "KZPLH2FO6SELOOAC4BUDLZXZ6Q4PLLDM";
-
private static final byte salt[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
- private static final String salt2 = "thisisaspecialsalt";
-
public static final String INIT_FILE = "/net/shibboleth/idp/saml/impl/nameid/StoredIdStore.sql";
public static final String DELETE_FILE = "/net/shibboleth/idp/saml/impl/nameid/DeleteStore.sql";
@@ -90,28 +84,18 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
@Test(expectedExceptions = ComponentInitializationException.class)
public void testInvalidConfig() throws ComponentInitializationException {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
+ final ComputedPairwiseIdStore strategy = new ComputedPairwiseIdStore();
strategy.setSalt(salt);
strategy.initialize();
generator.initialize();
- generator.setPersistentIdGenerator(strategy);
+ generator.setPersistentIdStore(strategy);
generator.initialize();
}
@Test
- public void testSaltSetters() throws ComponentInitializationException {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- Assert.assertEquals(salt, strategy.getSalt());
-
- strategy.setEncodedSalt(Base64Support.encode(salt, false));
- Assert.assertEquals(salt, strategy.getSalt());
- }
-
- @Test
public void testNoResponderId() throws Exception {
- generator.setPersistentIdGenerator(new ComputedPersistentIdGenerationStrategy());
+ generator.setPersistentIdStore(new ComputedPairwiseIdStore());
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
generator.initialize();
@@ -120,7 +104,7 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
@Test
public void testNoRequesterId() throws Exception {
- generator.setPersistentIdGenerator(new ComputedPersistentIdGenerationStrategy());
+ generator.setPersistentIdStore(new ComputedPairwiseIdStore());
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
generator.initialize();
@@ -131,7 +115,7 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
@Test
public void testNoSubject() throws Exception {
- generator.setPersistentIdGenerator(new ComputedPersistentIdGenerationStrategy());
+ generator.setPersistentIdStore(new ComputedPairwiseIdStore());
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
generator.initialize();
@@ -140,7 +124,7 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
@Test
public void testNoSource() throws Exception {
- generator.setPersistentIdGenerator(new ComputedPersistentIdGenerationStrategy());
+ generator.setPersistentIdStore(new ComputedPairwiseIdStore());
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
generator.initialize();
@@ -151,80 +135,14 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
Collections.singleton(new IdPAttribute("SOURCE")));
Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
}
-
- @Test(expectedExceptions=SAMLException.class)
- public void testRevoked() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- strategy.setExceptionMap(Collections.singletonMap("foo",
- Collections.<String,String>singletonMap(TestSources.SP_ENTITY_ID, null)));
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
- generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
- generator.initialize();
-
- prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
- Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
-
- final IdPAttribute source = new IdPAttribute("SOURCE");
- source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
- prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
- Collections.singleton(source));
- generator.generate(prc, NameID.PERSISTENT);
- }
-
- @Test(expectedExceptions=SAMLException.class)
- public void testRevokedWildcardRP() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- strategy.setExceptionMap(Collections.singletonMap("foo",
- Collections.<String,String>singletonMap(ComputedPersistentIdGenerationStrategy.WILDCARD_OVERRIDE, null)));
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
- generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
- generator.initialize();
-
- prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
- Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
-
- final IdPAttribute source = new IdPAttribute("SOURCE");
- source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
- prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
- Collections.singleton(source));
- generator.generate(prc, NameID.PERSISTENT);
- }
-
- @Test(expectedExceptions=SAMLException.class)
- public void testRevokedWildcardUser() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- strategy.setExceptionMap(Collections.singletonMap(ComputedPersistentIdGenerationStrategy.WILDCARD_OVERRIDE,
- Collections.<String,String>singletonMap(TestSources.SP_ENTITY_ID, null)));
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
- generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
- generator.initialize();
-
- prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
- Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
-
- final IdPAttribute source = new IdPAttribute("SOURCE");
- source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
- prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
- Collections.singleton(source));
- generator.generate(prc, NameID.PERSISTENT);
- }
@Test
public void testComputedId() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
+ final ComputedPairwiseIdStore strategy = new ComputedPairwiseIdStore();
strategy.setSalt(salt);
strategy.initialize();
- generator.setPersistentIdGenerator(strategy);
+ generator.setPersistentIdStore(strategy);
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
generator.initialize();
@@ -244,89 +162,32 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
}
@Test
- public void testComputedIdOverride() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- strategy.setExceptionMap(Collections.singletonMap(ComputedPersistentIdGenerationStrategy.WILDCARD_OVERRIDE,
- Collections.<String,String>singletonMap(TestSources.SP_ENTITY_ID, salt2)));
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
- generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
- generator.initialize();
-
- prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
- Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
-
- final IdPAttribute source = new IdPAttribute("SOURCE");
- source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
- prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
- Collections.singleton(source));
- final NameID id = generator.generate(prc, NameID.PERSISTENT);
- Assert.assertNotNull(id);
- Assert.assertEquals(id.getValue(), RESULT2);
- Assert.assertEquals(id.getFormat(), NameID.PERSISTENT);
- Assert.assertEquals(id.getNameQualifier(), TestSources.IDP_ENTITY_ID);
- Assert.assertEquals(id.getSPNameQualifier(), TestSources.SP_ENTITY_ID);
- }
-
- @Test
- public void testBase32ComputedId() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
- strategy.setSalt(salt);
- strategy.setEncoding(Encoding.BASE32);
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
- generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
- generator.initialize();
-
- prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
- Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
-
- final IdPAttribute source = new IdPAttribute("SOURCE");
- source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
- prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
- Collections.singleton(source));
- final NameID id = generator.generate(prc, NameID.PERSISTENT);
- Assert.assertNotNull(id);
- Assert.assertEquals(id.getValue(), B32RESULT);
- Assert.assertEquals(id.getFormat(), NameID.PERSISTENT);
- Assert.assertEquals(id.getNameQualifier(), TestSources.IDP_ENTITY_ID);
- Assert.assertEquals(id.getSPNameQualifier(), TestSources.SP_ENTITY_ID);
- }
-
- @Test
public void testStoredId() throws Exception {
- final StoredPersistentIdGenerationStrategy strategy = new StoredPersistentIdGenerationStrategy();
- strategy.setDataSource(testSource);
- strategy.initialize();
-
- generator.setPersistentIdGenerator(strategy);
+ generator.setDataSource(testSource);
testStoredIdLogic();
}
@Test
public void testComputedAndStoredId() throws Exception {
- final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
+ final ComputedPairwiseIdStore strategy = new ComputedPairwiseIdStore();
strategy.setSalt(salt);
strategy.initialize();
- final JDBCPersistentIdStoreEx store = new JDBCPersistentIdStoreEx();
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
store.setDataSource(testSource);
+ store.setInitialValueStore(strategy);
store.initialize();
- final StoredPersistentIdGenerationStrategy strategy2 = new StoredPersistentIdGenerationStrategy();
- strategy2.setIDStore(store);
- strategy2.setComputedIdStrategy(strategy);
- strategy2.initialize();
-
- generator.setPersistentIdGenerator(strategy2);
+ generator.setPersistentIdStore(store);
testComputedAndStoredIdLogic();
- store.deactivate(TestSources.IDP_ENTITY_ID, TestSources.SP_ENTITY_ID, RESULT, null);
+ final PairwiseId pid = new PairwiseId();
+ pid.setIssuerEntityID(TestSources.IDP_ENTITY_ID);
+ pid.setRecipientEntityID(TestSources.SP_ENTITY_ID);
+ pid.setPairwiseId(RESULT);
+ store.deactivate(pid);
final NameID id = generator.generate(prc, NameID.PERSISTENT);
Assert.assertNotEquals(id.getValue(), RESULT);
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoderTest.java
index 6601f4c..2662dfe 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoderTest.java
@@ -26,6 +26,7 @@ import javax.sql.DataSource;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.StringAttributeValue;
import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.RequestContextBuilder;
@@ -67,17 +68,13 @@ public class StoredPersistentIdDecoderTest extends OpenSAMLInitBaseTestCase {
@BeforeMethod public void setUp() throws SQLException, IOException, ComponentInitializationException {
- final JDBCPersistentIdStoreEx store = new JDBCPersistentIdStoreEx();
+ final JDBCPairwiseIdStore store = new JDBCPairwiseIdStore();
store.setDataSource(testSource);
store.initialize();
- final StoredPersistentIdGenerationStrategy strategy = new StoredPersistentIdGenerationStrategy();
- strategy.setIDStore(store);
- strategy.initialize();
-
generator = new PersistentSAML2NameIDGenerator();
generator.setId("test");
- generator.setPersistentIdGenerator(strategy);
+ generator.setPersistentIdStore(store);
generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
decoder = new StoredPersistentIdDecoder();
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list