[java-idp-integration-tests] 01/02: Add invalid record and pruning consent tests for Postgres.
Tom Zeller
tzeller at dragonacea.biz
Tue Jun 3 23:22:27 UTC 2025
This is an automated email from the git hooks/post-receive script.
tzeller pushed a commit to branch main
in repository java-idp-integration-tests.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-integration-tests.git;a=commit;h=3d8ea0c04d1e27fe06c73c3ead043667b4a83dce
commit 3d8ea0c04d1e27fe06c73c3ead043667b4a83dce
Author: Tom Zeller <tzeller at dragonacea.biz>
AuthorDate: Tue Jun 3 18:01:48 2025 -0500
Add invalid record and pruning consent tests for Postgres.
https://shibboleth.atlassian.net/browse/IDP-2323
---
.../shibboleth/idp/integration/tests/BaseTest.java | 72 +++++
.../tests/consent/BasePostgresConsentTest.java | 334 +++++++++++++++++++++
.../tests/consent/PostgresConsentTest.java | 209 ++++---------
.../consent/PruneRecordsPostgresConsentTest.java | 124 ++++++++
.../tests/util/TestbedStorageServiceClient.java | 193 ++++++++++++
5 files changed, 777 insertions(+), 155 deletions(-)
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/BaseTest.java b/src/test/java/net/shibboleth/idp/integration/tests/BaseTest.java
index 5e4e0ca..82ee0fa 100644
--- a/src/test/java/net/shibboleth/idp/integration/tests/BaseTest.java
+++ b/src/test/java/net/shibboleth/idp/integration/tests/BaseTest.java
@@ -54,8 +54,10 @@ import java.util.Random;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.function.IntConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
@@ -91,8 +93,10 @@ import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.opensaml.core.config.InitializationException;
import org.opensaml.core.config.InitializationService;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.UnmarshallerFactory;
+import org.opensaml.saml.metadata.resolver.impl.DefaultLocalDynamicSourceKeyGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
@@ -123,6 +127,7 @@ import net.shibboleth.shared.httpclient.HttpClientBuilder;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.net.URLBuilder;
import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
import net.shibboleth.shared.xml.ParserPool;
@@ -3556,4 +3561,71 @@ public abstract class BaseTest {
logProcess(process, "Download artifact :");
}
+ /**
+ * Set up local dynamic metadata provider using idp.home/dynamic/metadata source
+ * directory.
+ *
+ * @throws Exception
+ * if an error occurs
+ */
+ public void setUpLocalDynamicMetadataProvider() throws Exception {
+ final Path pathToMetadataProvidersXML = Paths.get("conf", "metadata-providers.xml");
+ final String oldText = "</MetadataProvider>";
+ final String newText = "<MetadataProvider id=\"LocalDynamic\" xsi:type=\"LocalDynamicMetadataProvider\" sourceDirectory=\"%{idp.home}/metadata/dynamic\" />";
+ replaceIdPHomeFile(pathToMetadataProvidersXML, oldText, newText + System.lineSeparator() + oldText);
+ }
+
+ /**
+ * Set up local dynamic metadata in idp.home/dynamic/metadata source directory.
+ *
+ * Copies metadata/example-metadata.xml and replaces entityID and endpoint URLs.
+ *
+ * @param numberToCreate
+ * number of SPs to create
+ * @throws Exception
+ * if an error occurs
+ */
+ public void setUpLocalDynamicSPMetadata(int numberToCreate) throws Exception {
+
+ final Path pathToMetadataDirectory = pathToIdPHome.resolve("metadata");
+
+ final Path pathToExampleMetadata = pathToMetadataDirectory.resolve("example-metadata.xml");
+
+ final Path pathToDynamicMetadataDirectory = pathToMetadataDirectory.resolve("dynamic");
+
+ Files.createDirectory(pathToDynamicMetadataDirectory);
+
+ final DefaultLocalDynamicSourceKeyGenerator gen = new DefaultLocalDynamicSourceKeyGenerator(null, ".xml", null);
+
+ final IntConsumer intConsumer = value -> {
+
+ final String entityID = "https://sp" + value + ".example.org";
+
+ final String metadataFileName = gen.apply(new CriteriaSet(new EntityIdCriterion(entityID)));
+
+ final Path pathToMetadataFile = pathToDynamicMetadataDirectory.resolve(metadataFileName);
+
+ try {
+ log.debug("Creating example metadata for {} to {}", entityID, pathToMetadataFile);
+ Files.copy(pathToExampleMetadata, pathToMetadataFile);
+
+ // Replace entityID
+ replaceFile(pathToMetadataFile, "entityID=\"https://sp.example.org\"", "entityID=\"" + entityID + "\"");
+
+ // Replace text
+ replaceFile(pathToMetadataFile, " SP ", " SP" + value + " ");
+
+ // Replace URLs
+ replaceFile(pathToMetadataFile, "/sp/", "/sp/sp" + value + "/");
+ } catch (final IOException e) {
+ log.error("Unable to copy example metadata to {}", pathToMetadataFile, e);
+ throw new RuntimeException(e);
+ }
+ };
+
+ IntStream.range(1, numberToCreate + 1).forEach(intConsumer);
+
+ setUpLocalDynamicMetadataProvider();
+ }
+
}
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/BasePostgresConsentTest.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/BasePostgresConsentTest.java
new file mode 100644
index 0000000..bf69eba
--- /dev/null
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/BasePostgresConsentTest.java
@@ -0,0 +1,334 @@
+/*
+ * 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.integration.tests.consent;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.saml.saml2.core.AuthnContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+
+import net.shibboleth.idp.integration.tests.saml2.AbstractSAML2IntegrationTest;
+import net.shibboleth.idp.integration.tests.util.TestbedStorageServiceClient;
+import net.shibboleth.idp.test.flows.saml2.SAML2TestResponseValidator;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.collection.LazyList;
+
+/** Base class to test consent with a Postgres storage service. */
+public abstract class BasePostgresConsentTest extends AbstractSAML2IntegrationTest {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(BasePostgresConsentTest.class);
+
+ /** Postgres container. */
+ private PostgreSQLContainer<?> postgresContainer;
+
+ /** Postgres connection URL from container. */
+ private String jdbcUrl;
+
+ @BeforeClass
+ public void setUpURLs() throws Exception {
+
+ startFlowURLPath = "/sp/SAML2/InitSSO/Redirect";
+
+ loginPageURLPath = "/idp/profile/SAML2/Redirect/SSO";
+
+ responsePageURLPath = "/sp/SAML2/POST/ACS";
+
+ isPassiveRequestURLPath = "/sp/SAML2/InitSSO/Passive";
+
+ forceAuthnRequestURLPath = "/sp/SAML2/InitSSO/ForceAuthn";
+
+ idpLogoutURLPath = "/idp/profile/SAML2/Redirect/SLO";
+
+ spLogoutURLPath = "/sp/SAML2/Redirect/SLO";
+
+ logoutTransientIDInputID = "InitSLO_Redirect";
+ }
+
+ /**
+ * Set up Postgres storage service.
+ *
+ * Install JDBC Plugin.
+ *
+ * Add testbed storage servlet to the IdP.
+ *
+ * Add Postgres and HikariCP drivers to the IdP.
+ *
+ * @throws IOException
+ * if an error occurs
+ */
+ @BeforeClass
+ public void setUpPostgresStorageService() throws IOException {
+
+ installPlugin("net.shibboleth.plugin.storage.jdbc");
+
+ setUpStorageServlet();
+
+ downloadPostgresqlDriver();
+
+ downloadHikariCPDriver();
+
+ buildWAR();
+
+ enablePostgresStorageService();
+
+ replaceIdPProperty("idp.consent.StorageService", "my.JDBCStorageService");
+
+ enableAmbiguousPathSeparator();
+
+ // server.getAdditionalCommands().add("-Didp.loglevel.spring=DEBUG");
+ }
+
+ /**
+ * Build local dynamic SP response validator.
+ *
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public SAML2TestResponseValidator buildLocalDynamicSpValidator(@Nonnull final String spId) throws IOException {
+ final SAML2TestResponseValidator validator = new SAML2TestResponseValidator();
+ validator.spEntityID = "https://" + spId + ".example.org";
+ validator.nameID.setSPNameQualifier("https://" + spId + ".example.org");
+ validator.spCredential = getSPCredential();
+ validator.authnContextClassRef = AuthnContext.PPT_AUTHN_CTX;
+ validator.expectedAttributes.clear();
+ validator.expectedAttributes.add(validator.eppnAttribute);
+ validator.expectedAttributes.add(validator.homeOrgAttribute);
+ validator.expectedAttributes.add(validator.mailAttribute);
+ return validator;
+ }
+
+ /**
+ * Download latest Postgres driver to edit-webapp/WEB-INF/lib.
+ *
+ * @throws IOException
+ * if an error occurs
+ */
+ public void downloadPostgresqlDriver() throws IOException {
+ copyDependency("org.postgresql", "postgresql");
+ }
+
+ /**
+ * Download latest HikariCP driver to edit-webapp/WEB-INF/lib.
+ *
+ * @throws IOException
+ * if an error occurs
+ */
+ public void downloadHikariCPDriver() throws IOException {
+ copyDependency("com.zaxxer", "HikariCP");
+ }
+
+ /**
+ * Enable JDBC storage using Postgres and HikariCP.
+ *
+ * Enables beans from
+ * "/net/shibboleth/idp/integration/tests/postgres/global.xml".
+ *
+ * @throws IOException
+ * if an error occurs
+ * @throws URISyntaxException
+ * if an error occurs
+ */
+ public void enablePostgresStorageService() throws IOException {
+ try {
+ final Path pathToGlobalXML = pathToIdPHome.resolve(Paths.get("conf", "global.xml"));
+
+ assert pathToGlobalXML.toAbsolutePath().toFile().exists() : "Path to global.xml not found";
+
+ final String oldText = "</beans>";
+
+ final String resourcePath = "/net/shibboleth/idp/integration/tests/postgres/global.xml";
+
+ final Path pathToSnippetForGlobalXML = Paths.get(this.getClass().getResource(resourcePath).toURI());
+
+ final String newText = Files.readString(pathToSnippetForGlobalXML);
+
+ replaceFile(pathToGlobalXML, oldText, newText + "\n" + oldText);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Enable ambiguous path separator in Jetty for testbed storage service client.
+ *
+ * @throws IOException
+ * of an error occurs
+ */
+ public void enableAmbiguousPathSeparator() throws IOException {
+ if (Boolean.getBoolean("tomcat")) {
+ return;
+ } else {
+ final Path idpIni = pathToJettyBase.resolve(Paths.get("start.d", "idp.ini"));
+ replaceFile(idpIni, "\\z",
+ System.lineSeparator() + "jetty.httpConfig.uriCompliance=DEFAULT,AMBIGUOUS_PATH_SEPARATOR");
+ }
+ }
+
+ /**
+ * Log in to local dynamic SP with given id.
+ *
+ * @param spId
+ * the numerical id of the SP
+ * @throws Exception
+ * if an error occurs
+ */
+ public void loginToLocalDynamicSP(@Nonnull final String spId) throws Exception {
+
+ log.debug("Log in to SP '{}'", spId);
+
+ // login to sp
+
+ driver.get(getBaseURL() + "/sp/" + spId + "/SAML2/InitSSO/Redirect");
+
+ // attribute release
+
+ waitForAttributeReleasePage();
+
+ releaseAllAttributes();
+
+ rememberConsent();
+
+ submitForm();
+
+ // response
+
+ responsePageURLPath = "/sp/" + spId + "/SAML2/POST/ACS";
+
+ waitForResponsePage();
+
+ buildLocalDynamicSpValidator(spId).validateResponse(unmarshallResponse(getPageSource()));
+ }
+
+ /**
+ * Query database for a list of storage record rows represented as a map with
+ * column names as keys.
+ *
+ * @return list of rows represented as a map with column names as keys
+ * @throws SQLException
+ * if an error occurs
+ */
+ public List<Map<String, String>> queryDatabase() throws SQLException {
+ final String context = "intercept/attribute-release";
+ final String query = "SELECT * from storagerecords";
+ final List<String> columns = CollectionSupport.listOf("context", "id", "expires", "value");
+ final List<Map<String, String>> results = new LazyList<>();
+ log.debug("Query for '{}' records from '{}'", context, jdbcUrl);
+ try (final Connection conn = DriverManager.getConnection(jdbcUrl, "test", "test")) {
+ final Statement statement = conn.createStatement();
+ try (final ResultSet resultSet = statement.executeQuery(query)) {
+ while (resultSet.next()) {
+ if (resultSet.getString("context").equals(context)) {
+ final Map<String, String> row = new HashMap<>(columns.size());
+ for (final String column : columns) {
+ row.put(column, resultSet.getString(column));
+ }
+ results.add(row);
+ log.trace("Found row {}", row);
+ }
+ }
+ }
+ } catch (final SQLException e) {
+ log.error("Unable to query database '{}'", jdbcUrl, e);
+ throw e;
+ }
+ return results;
+ }
+
+ /**
+ * Start Postgres container.
+ *
+ * Creates "StorageRecords" table.
+ *
+ * @return the JDBC URL to connect to the Postgres container
+ * @throws IOException
+ */
+ @SuppressWarnings("resource")
+ @BeforeMethod()
+ public void startPostgres() throws IOException {
+
+ final String initScriptPath = "net/shibboleth/idp/integration/tests/postgres/create-table.sql";
+
+ postgresContainer = new PostgreSQLContainer<>("postgres").withInitScript(initScriptPath);
+
+ log.debug("{} Starting Postgres ...");
+ postgresContainer.start();
+ log.debug("{} Started Postgres : '{}'", postgresContainer.getContainerName());
+
+ jdbcUrl = postgresContainer.getJdbcUrl();
+ log.info("{} Postgres JDBC URL : '{}'", jdbcUrl);
+
+ replaceIdPHomeFile(Paths.get("conf", "global.xml"), "jdbc:postgresql://localhost:\\d+/test\\?loggerLevel=OFF", jdbcUrl);
+ }
+
+ /**
+ * Stop Postgres.
+ */
+ @AfterMethod()
+ public void stopPostgres() {
+ if (postgresContainer != null) {
+ log.debug("{} Stopping Postgres ...");
+ postgresContainer.stop();
+ log.debug("{} Postgres stopped");
+ postgresContainer.close();
+ }
+ }
+
+ /**
+ * Write invalid JSON to a storage record value using testbed storage service
+ * wrapper to the IdP.
+ *
+ * @throws IOException
+ * if an error occurs
+ */
+ public void writeInvalidDataToIndexRecord() throws IOException {
+
+ final TestbedStorageServiceClient storageServiceClient = new TestbedStorageServiceClient() //
+ .setBaseUrl(getBaseURL(true)) //
+ .setStorageServiceId("my.JDBCStorageService") //
+ .setContext("intercept/attribute-release") //
+ .setKey("jdoe:_key_idx") //
+ .setValue("not JSON");
+
+ boolean result = storageServiceClient.create();
+
+ Assert.assertTrue(result);
+ }
+
+}
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/PostgresConsentTest.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/PostgresConsentTest.java
index 03dafeb..c2e4610 100644
--- a/src/test/java/net/shibboleth/idp/integration/tests/consent/PostgresConsentTest.java
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/PostgresConsentTest.java
@@ -17,203 +17,102 @@
package net.shibboleth.idp.integration.tests.consent;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.testcontainers.containers.PostgreSQLContainer;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import net.shibboleth.idp.integration.tests.saml2.AbstractSAML2IntegrationTest;
import net.shibboleth.idp.integration.tests.util.testng.annotation.LinuxOnly;
/** Test consent with a Postgres storage service. */
-public class PostgresConsentTest extends AbstractSAML2IntegrationTest {
+public class PostgresConsentTest extends BasePostgresConsentTest {
/** Class logger. */
@Nonnull
private final Logger log = LoggerFactory.getLogger(PostgresConsentTest.class);
- /** Postgres container. */
- private PostgreSQLContainer<?> postgresContainer;
-
- @BeforeClass
- public void setUpURLs() throws Exception {
-
- startFlowURLPath = "/sp/SAML2/InitSSO/Redirect";
-
- loginPageURLPath = "/idp/profile/SAML2/Redirect/SSO";
-
- responsePageURLPath = "/sp/SAML2/POST/ACS";
-
- isPassiveRequestURLPath = "/sp/SAML2/InitSSO/Passive";
-
- forceAuthnRequestURLPath = "/sp/SAML2/InitSSO/ForceAuthn";
-
- idpLogoutURLPath = "/idp/profile/SAML2/Redirect/SLO";
-
- spLogoutURLPath = "/sp/SAML2/Redirect/SLO";
-
- logoutTransientIDInputID = "InitSLO_Redirect";
+ @Test
+ @LinuxOnly
+ public void testSSOReleaseAllAttributes() throws Exception {
+ super.testSSOReleaseAllAttributes();
}
- /**
- * Set up Postgres storage service.
- *
- * Install JDBC Plugin.
- *
- * Add testbed storage servlet to the IdP.
- *
- * Add Postgres and HikariCP drivers to the IdP.
- *
- * @throws IOException
- * if an error occurs
- */
- @BeforeClass
- public void setUpPostgresStorageService() throws IOException {
-
- installPlugin("net.shibboleth.plugin.storage.jdbc");
-
- setUpStorageServlet();
-
- downloadPostgresqlDriver();
-
- downloadHikariCPDriver();
-
- buildWAR();
-
- enablePostgresStorageService();
+ @Test
+ @LinuxOnly
+ public void testSSOReleaseOneAttribute() throws Exception {
+ super.testSSOReleaseOneAttribute();
+ }
- replaceIdPProperty("idp.consent.StorageService", "my.JDBCStorageService");
+ @Test
+ @LinuxOnly
+ public void testSSODoNotRememberConsent() throws Exception {
+ super.testSSODoNotRememberConsent();
}
- /**
- * Download latest Postgres driver to edit-webapp/WEB-INF/lib.
- *
- * @throws IOException
- * if an error occurs
- */
- public void downloadPostgresqlDriver() throws IOException {
- copyDependency("org.postgresql", "postgresql");
+ @Test
+ @LinuxOnly
+ public void testSSOGlobalConsent() throws Exception {
+ super.testSSOGlobalConsent();
}
- /**
- * Download latest HikariCP driver to edit-webapp/WEB-INF/lib.
- *
- * @throws IOException
- * if an error occurs
- */
- public void downloadHikariCPDriver() throws IOException {
- copyDependency("com.zaxxer", "HikariCP");
+ @Test
+ @LinuxOnly
+ public void testSSOTermsOfUse() throws Exception {
+ super.testSSOTermsOfUse();
}
- /**
- * Enable JDBC storage using Postgres and HikariCP.
- *
- * Enables beans from
- * "/net/shibboleth/idp/integration/tests/postgres/global.xml".
- *
- * @throws IOException
- * if an error occurs
- * @throws URISyntaxException
- * if an error occurs
- */
- public void enablePostgresStorageService() throws IOException {
- try {
- final Path pathToGlobalXML = pathToIdPHome.resolve(Paths.get("conf", "global.xml"));
+ @Test
+ @LinuxOnly
+ public void testInvalidData() throws Exception {
- assert pathToGlobalXML.toAbsolutePath().toFile().exists() : "Path to global.xml not found";
+ startServer();
- final String oldText = "</beans>";
+ writeInvalidDataToIndexRecord();
- final String resourcePath = "/net/shibboleth/idp/integration/tests/postgres/global.xml";
+ startBrowser();
- final Path pathToSnippetForGlobalXML = Paths.get(this.getClass().getResource(resourcePath).toURI());
+ startFlow();
- final String newText = Files.readString(pathToSnippetForGlobalXML);
+ waitForLoginPage();
- replaceFile(pathToGlobalXML, oldText, newText + "\n" + oldText);
+ login();
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
+ // attribute release
- /**
- * Start Postgres container.
- *
- * Creates "StorageRecords" table.
- *
- * @return the JDBC URL to connect to the Postgres container
- * @throws IOException
- */
- @BeforeMethod()
- public String startPostgres() throws IOException {
+ waitForAttributeReleasePage();
- final String initScriptPath = "net/shibboleth/idp/integration/tests/postgres/create-table.sql";
+ releaseAllAttributes();
- postgresContainer = new PostgreSQLContainer<>("postgres").withInitScript(initScriptPath);
+ rememberConsent();
- log.debug("{} Starting Postgres ...");
- postgresContainer.start();
- log.debug("{} Started Postgres : '{}'", postgresContainer.getContainerName());
+ submitForm();
- final String jdbcUrl = postgresContainer.getJdbcUrl();
- log.info("{} Postgres JDBC URL : '{}'", jdbcUrl);
+ if (true) {
+ sleep(1000);
+ }
- replaceIdPHomeFile(Paths.get("conf", "global.xml"), "jdbc:postgresql://localhost:\\d+/test\\?loggerLevel=OFF", jdbcUrl);
+ // expect JSON runtime exception for IdP 5.1 (or earlier)
+ // TODO remove "5.2" once fixed
+ // if (idpVersion.startsWith("5.1")) {
+ if (idpVersion.startsWith("5.1") || idpVersion.startsWith("5.2")) {
+ waitForPageBodyContains("jakarta.json.stream.JsonParsingException");
+ return;
+ }
- return jdbcUrl;
- }
+ // response
- /**
- * Stop Postgres.
- */
- @AfterMethod()
- public void stopPostgres() {
- if (postgresContainer != null) {
- log.debug("{} Stopping Postgres ...");
- postgresContainer.stop();
- log.debug("{} Postgres stopped");
- }
- }
+ waitForResponsePage();
- @Test
- @LinuxOnly
- public void testSSOReleaseAllAttributes() throws Exception {
- super.testSSOReleaseAllAttributes();
- }
+ validateResponse();
- @Test
- @LinuxOnly
- public void testSSOReleaseOneAttribute() throws Exception {
- super.testSSOReleaseOneAttribute();
- }
+ // twice
- @Test
- @LinuxOnly
- public void testSSODoNotRememberConsent() throws Exception {
- super.testSSODoNotRememberConsent();
- }
+ startFlow();
- @Test
- @LinuxOnly
- public void testSSOGlobalConsent() throws Exception {
- super.testSSOGlobalConsent();
- }
+ waitForResponsePage();
- @Test
- @LinuxOnly
- public void testSSOTermsOfUse() throws Exception {
- super.testSSOTermsOfUse();
+ validateResponse();
}
+
}
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/PruneRecordsPostgresConsentTest.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/PruneRecordsPostgresConsentTest.java
new file mode 100644
index 0000000..6c1fa68
--- /dev/null
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/PruneRecordsPostgresConsentTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.integration.tests.consent;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.annotation.Nonnull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.integration.tests.util.testng.annotation.LinuxOnly;
+
+/** Test pruning consent storage records with a Postgres storage service. */
+public class PruneRecordsPostgresConsentTest extends BasePostgresConsentTest {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(PruneRecordsPostgresConsentTest.class);
+
+ @Test
+ @LinuxOnly
+ public void testPruneStorageRecords() throws Exception {
+
+ setUpLocalDynamicSPMetadata(10);
+
+ startBrowser();
+
+ // TODO Assert that idp.consent.expandedMaxStoredRecords = 0
+
+ // Bump consent logging to TRACE
+ final Path pathToLogbackXML = Paths.get("conf", "logback.xml");
+ final String oldText = "</configuration>";
+ final String newText = "<logger name=\"net.shibboleth.idp.consent\" level=\"TRACE\"/>";
+ replaceIdPHomeFile(pathToLogbackXML, oldText, newText + System.lineSeparator() + oldText);
+
+ startServer();
+
+ // log in to sp.example.org
+
+ startFlow();
+
+ waitForLoginPage();
+
+ login();
+
+ // attribute release
+
+ waitForAttributeReleasePage();
+
+ releaseAllAttributes();
+
+ rememberConsent();
+
+ submitForm();
+
+ // response
+
+ waitForResponsePage();
+
+ validateResponse();
+
+ // log in to sp.example.org again
+
+ startFlow();
+
+ waitForResponsePage();
+
+ validateResponse();
+
+ // log in to more SPs
+
+ loginToLocalDynamicSP("sp1");
+
+ loginToLocalDynamicSP("sp2");
+
+ loginToLocalDynamicSP("sp3");
+
+ loginToLocalDynamicSP("sp4");
+
+ loginToLocalDynamicSP("sp5");
+
+ loginToLocalDynamicSP("sp6");
+
+ loginToLocalDynamicSP("sp7");
+
+ loginToLocalDynamicSP("sp8");
+
+ loginToLocalDynamicSP("sp9");
+
+ // Should be 10 records + 1 index record
+ Assert.assertEquals(queryDatabase().size(), 11);
+
+ stopServer();
+
+ replaceIdPProperty("idp.consent.expandedMaxStoredRecords", "5");
+
+ startServer();
+
+ loginToLocalDynamicSP("sp10");
+
+ // Should be max (5) + 1 records after pruning
+ Assert.assertEquals(queryDatabase().size(), 6);
+ }
+
+}
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/util/TestbedStorageServiceClient.java b/src/test/java/net/shibboleth/idp/integration/tests/util/TestbedStorageServiceClient.java
new file mode 100644
index 0000000..3de24dd
--- /dev/null
+++ b/src/test/java/net/shibboleth/idp/integration/tests/util/TestbedStorageServiceClient.java
@@ -0,0 +1,193 @@
+
+package net.shibboleth.idp.integration.tests.util;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.annotation.Nonnull;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.util.UriUtils;
+
+/** Storage service client for the testbed StorageServiceWrapperController. */
+public class TestbedStorageServiceClient {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(TestbedStorageServiceClient.class);
+
+ private String baseUrl = "https://idp.tests.shibboleth.net:8443";
+
+ /** Storage service ID. */
+ private String storageServiceId;
+
+ /** Storage service context. */
+ private String context;
+
+ /** Storage service key. */
+ private String key;
+
+ /** Storage service record value. */
+ private String value;
+
+ public TestbedStorageServiceClient setBaseUrl(@Nonnull final String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public TestbedStorageServiceClient setStorageServiceId(@Nonnull final String storageServiceId) {
+ this.storageServiceId = storageServiceId;
+ return this;
+ }
+
+ public TestbedStorageServiceClient setContext(@Nonnull final String context) {
+ this.context = context;
+ return this;
+ }
+
+ public TestbedStorageServiceClient setKey(@Nonnull final String key) {
+ this.key = key;
+ return this;
+ }
+
+ public TestbedStorageServiceClient setValue(@Nonnull final String value) {
+ this.value = value;
+ return this;
+ }
+
+ public boolean create() throws IOException {
+
+ log.debug("Create '{}' context='{}' '{}'='{}'", storageServiceId, context, key, value);
+
+ try {
+ final String encodedStorageServiceId = UriUtils.encode(storageServiceId, "UTF-8");
+
+ final String encodedContext = UriUtils.encode(context, "UTF-8");
+
+ final String encodedKey = UriUtils.encode(key, "UTF-8");
+
+ final String encodedValue = UriUtils.encode(value, "UTF-8");
+
+ final String url = baseUrl + //
+ "/idp/storage/create/" + //
+ String.join("/", encodedStorageServiceId, encodedContext, encodedKey) + //
+ "?value=" + encodedValue;
+
+ log.debug("Create URL '{}'", url);
+
+ final HttpRequest request = HttpRequest.newBuilder() //
+ .version(HttpClient.Version.HTTP_2) //
+ .uri(URI.create(url)) //
+ .POST(HttpRequest.BodyPublishers.noBody()) //
+ .build();
+
+ final HttpClient client = trustAnyHttpClient();
+
+ final HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
+
+ log.debug("Create response :\n{}", response.body());
+
+ final int responseStatusCode = response.statusCode();
+
+ log.debug("Create response status code '{}'", responseStatusCode);
+
+ if (response.statusCode() == 201) {
+ log.info("Created storage '{}' '{}' '{}'='{}'", storageServiceId, context, key, value);
+ return true;
+ }
+
+ } catch (final InterruptedException e) {
+ log.error("Unable to create '{}' context='{}' '{}'='{}'", storageServiceId, context, key, value, e);
+ }
+
+ return false;
+ }
+
+ /**
+ * An {@link HttpClient} that accepts any certificate as trusted.
+ */
+ public static HttpClient trustAnyHttpClient() {
+ return HttpClient.newBuilder().sslContext(trustAnyCertificateSSLContext()).build();
+ }
+
+ /**
+ * An {@link SSLContext} that accepts any certificate as trusted.
+ */
+ public static SSLContext trustAnyCertificateSSLContext() {
+ try {
+ final SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, new TrustManager[] { new TrustAnyCertificate() }, null);
+ return context;
+ } catch (final NoSuchAlgorithmException | KeyManagementException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * An {@link X509TrustManager} that accepts any certificate as trusted.
+ */
+ public static class TrustAnyCertificate extends X509ExtendedTrustManager {
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[] {};
+ }
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list