From 6b99b204a1cbcbf3b557665a8c43de497d45e5e0 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 25 Nov 2024 14:17:41 +0100 Subject: [PATCH] feat: backport to IdP 4 --- .github/workflows/build-snapshot.yml | 4 +- .github/workflows/release.yml | 6 +-- andrvotr-impl/pom.xml | 4 +- .../fmfi_svt/andrvotr/AndrvotrPlugin.java | 2 +- .../andrvotr/AuthorityTokenGenerator.java | 27 ++++++------ .../io/github/fmfi_svt/andrvotr/Config.java | 21 +++++----- .../andrvotr/FabricationWebflowListener.java | 21 +++++----- .../FabricationWebflowListenerInjector.java | 4 +- .../fmfi_svt/andrvotr/HttpController.java | 42 ++++++++++--------- .../net.shibboleth.idp/postconfig.xml | 2 +- pom.xml | 6 +-- 11 files changed, 72 insertions(+), 67 deletions(-) diff --git a/.github/workflows/build-snapshot.yml b/.github/workflows/build-snapshot.yml index 17947ff..3c52299 100644 --- a/.github/workflows/build-snapshot.yml +++ b/.github/workflows/build-snapshot.yml @@ -14,10 +14,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 11 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '11' distribution: 'temurin' cache: maven - name: Generate single-use GPG key diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48297c7..2732332 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,10 +21,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 11 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '11' distribution: 'temurin' cache: maven - name: Build with Maven @@ -35,5 +35,5 @@ jobs: subject-path: andrvotr-dist/target/*.tar.gz* - name: Release run: | - title="Andrvotr $GITHUB_REF_NAME (for IdP 5.x)" + title="Andrvotr $GITHUB_REF_NAME (for IdP 4.x)" gh release create "$GITHUB_REF_NAME" --title "$title" --verify-tag andrvotr-dist/target/*.tar.gz* diff --git a/andrvotr-impl/pom.xml b/andrvotr-impl/pom.xml index b16279c..ce20ca6 100644 --- a/andrvotr-impl/pom.xml +++ b/andrvotr-impl/pom.xml @@ -32,8 +32,8 @@ provided - jakarta.servlet - jakarta.servlet-api + javax.servlet + javax.servlet-api provided diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AndrvotrPlugin.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AndrvotrPlugin.java index 11d520a..3c20f5d 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AndrvotrPlugin.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AndrvotrPlugin.java @@ -1,8 +1,8 @@ package io.github.fmfi_svt.andrvotr; import java.io.IOException; +import net.shibboleth.idp.plugin.PluginException; import net.shibboleth.idp.plugin.PropertyDrivenIdPPlugin; -import net.shibboleth.profile.plugin.PluginException; public class AndrvotrPlugin extends PropertyDrivenIdPPlugin { public AndrvotrPlugin() throws IOException, PluginException { diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AuthorityTokenGenerator.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AuthorityTokenGenerator.java index daeaa68..38433d9 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AuthorityTokenGenerator.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/AuthorityTokenGenerator.java @@ -1,8 +1,6 @@ package io.github.fmfi_svt.andrvotr; import com.google.common.base.Strings; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.time.Duration; import java.time.Instant; import java.util.Collections; @@ -10,20 +8,23 @@ import java.util.function.Function; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import net.shibboleth.idp.attribute.IdPAttributeValue; import net.shibboleth.idp.attribute.StringAttributeValue; +import net.shibboleth.idp.profile.context.RelyingPartyContext; import net.shibboleth.idp.profile.context.SpringRequestContext; import net.shibboleth.idp.session.IdPSession; import net.shibboleth.idp.session.context.SessionContext; -import net.shibboleth.profile.context.RelyingPartyContext; -import net.shibboleth.shared.component.AbstractInitializableComponent; -import net.shibboleth.shared.component.ComponentInitializationException; -import net.shibboleth.shared.logic.Constraint; -import net.shibboleth.shared.primitive.LoggerFactory; -import net.shibboleth.shared.security.DataSealer; -import net.shibboleth.shared.security.DataSealerException; +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.logic.Constraint; +import net.shibboleth.utilities.java.support.security.DataSealer; +import net.shibboleth.utilities.java.support.security.DataSealerException; import org.opensaml.profile.context.ProfileRequestContext; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.execution.RequestContext; @@ -41,23 +42,23 @@ public final class AuthorityTokenGenerator extends AbstractInitializableComponen private Duration tokenLifetime; public void setConfig(@Nonnull Config newConfig) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); config = Constraint.isNotNull(newConfig, "Config cannot be null"); } public void setDataSealer(@Nonnull DataSealer sealer) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null"); } public void setIdpSessionCookieName(@Nonnull String name) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); Constraint.isFalse(Strings.isNullOrEmpty(name), "idpSessionCookieName cannot be null or empty"); idpSessionCookieName = name; } public void setTokenLifetime(@Nonnull Duration lifetime) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); Constraint.isNotNull(lifetime, "Lifetime cannot be null"); Constraint.isFalse(lifetime.isNegative() || lifetime.isZero(), "Lifetime must be positive"); tokenLifetime = lifetime; diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/Config.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/Config.java index 224febd..59b8d80 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/Config.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/Config.java @@ -1,36 +1,37 @@ package io.github.fmfi_svt.andrvotr; import com.google.common.base.Strings; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.shibboleth.shared.collection.CollectionSupport; -import net.shibboleth.shared.collection.Pair; -import net.shibboleth.shared.component.AbstractInitializableComponent; -import net.shibboleth.shared.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.collection.Pair; +import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.component.ComponentSupport; public final class Config extends AbstractInitializableComponent { private @Nullable String apiKeysString; - private @Nonnull Set> apiKeys = CollectionSupport.emptySet(); + private @Nonnull Set> apiKeys = Collections.emptySet(); - private @Nonnull Set apiKeyFronts = CollectionSupport.emptySet(); + private @Nonnull Set apiKeyFronts = Collections.emptySet(); private @Nullable String allowedConnectionsString; - private @Nonnull Set> allowedConnections = CollectionSupport.emptySet(); + private @Nonnull Set> allowedConnections = Collections.emptySet(); - private @Nonnull Set allowedConnectionFronts = CollectionSupport.emptySet(); + private @Nonnull Set allowedConnectionFronts = Collections.emptySet(); public void setApiKeys(@Nullable String string) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); apiKeysString = string; } public void setAllowedConnections(@Nullable String string) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); allowedConnectionsString = string; } diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListener.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListener.java index 8a8c845..f225446 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListener.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListener.java @@ -1,18 +1,19 @@ package io.github.fmfi_svt.andrvotr; import com.google.common.base.Strings; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.shibboleth.idp.profile.context.RelyingPartyContext; import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup; -import net.shibboleth.profile.context.RelyingPartyContext; -import net.shibboleth.shared.component.AbstractInitializableComponent; -import net.shibboleth.shared.component.ComponentInitializationException; -import net.shibboleth.shared.logic.Constraint; -import net.shibboleth.shared.primitive.LoggerFactory; -import net.shibboleth.shared.security.DataSealer; +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.logic.Constraint; +import net.shibboleth.utilities.java.support.security.DataSealer; import org.opensaml.profile.context.ProfileRequestContext; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.webflow.definition.StateDefinition; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionListener; @@ -46,12 +47,12 @@ public final class FabricationWebflowListener extends AbstractInitializableCompo private DataSealer dataSealer; public void setDataSealer(@Nonnull DataSealer sealer) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null"); } public void setConfig(@Nonnull Config newConfig) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); config = Constraint.isNotNull(newConfig, "Config cannot be null"); } diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListenerInjector.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListenerInjector.java index 108ca6a..3d27d12 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListenerInjector.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/FabricationWebflowListenerInjector.java @@ -2,9 +2,9 @@ import java.util.Map; import javax.annotation.Nonnull; -import net.shibboleth.shared.component.AbstractInitializableComponent; -import net.shibboleth.shared.primitive.LoggerFactory; +import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; diff --git a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/HttpController.java b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/HttpController.java index 2aa9853..b8188b1 100644 --- a/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/HttpController.java +++ b/andrvotr-impl/src/main/java/io/github/fmfi_svt/andrvotr/HttpController.java @@ -1,8 +1,6 @@ package io.github.fmfi_svt.andrvotr; import com.google.common.base.Strings; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.net.URL; @@ -13,18 +11,21 @@ import java.util.List; import java.util.stream.Collectors; import javax.annotation.Nonnull; -import net.shibboleth.shared.component.AbstractInitializableComponent; -import net.shibboleth.shared.component.ComponentInitializationException; -import net.shibboleth.shared.logic.Constraint; -import net.shibboleth.shared.primitive.LoggerFactory; -import net.shibboleth.shared.security.DataExpiredException; -import net.shibboleth.shared.security.DataSealer; -import net.shibboleth.shared.security.DataSealerException; -import org.apache.hc.client5.http.classic.HttpClient; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.io.entity.EntityUtils; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +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.logic.Constraint; +import net.shibboleth.utilities.java.support.security.DataExpiredException; +import net.shibboleth.utilities.java.support.security.DataSealer; +import net.shibboleth.utilities.java.support.security.DataSealerException; +import org.apache.http.Header; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.util.EntityUtils; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -44,22 +45,22 @@ public final class HttpController extends AbstractInitializableComponent { private String idpEntityID; public void setHttpClient(@Nonnull HttpClient client) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); httpClient = Constraint.isNotNull(client, "HttpClient cannot be null"); } public void setConfig(@Nonnull Config newConfig) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); config = Constraint.isNotNull(newConfig, "Config cannot be null"); } public void setDataSealer(@Nonnull DataSealer sealer) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null"); } public void setIdpEntityID(@Nonnull String id) { - checkSetterPreconditions(); + ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); Constraint.isFalse(Strings.isNullOrEmpty(id), "idpEntityId cannot be null or empty"); idpEntityID = id; } @@ -176,8 +177,9 @@ public void fabricate(@Nonnull HttpServletRequest httpRequest, @Nonnull HttpServ nestedRequest.addHeader(Constants.HEADER_ANDRVOTR_INTERNAL_FABRICATION_FRONT, frontEntityID); httpClient.execute(nestedRequest, (nestedResponse) -> { - int statusCode = nestedResponse.getCode(); - String contentType = nestedResponse.getEntity().getContentType(); + int statusCode = nestedResponse.getStatusLine().getStatusCode(); + Header contentTypeHeader = nestedResponse.getEntity().getContentType(); + String contentType = contentTypeHeader == null ? null : contentTypeHeader.getValue(); long contentLength = nestedResponse.getEntity().getContentLength(); List trace = Arrays.stream( @@ -207,7 +209,7 @@ public void fabricate(@Nonnull HttpServletRequest httpRequest, @Nonnull HttpServ try { if ((contentType != null && contentType.startsWith("text/")) || nestedResponse.getEntity().getContentEncoding() != null) { - String body = EntityUtils.toString(nestedResponse.getEntity(), 4096); + String body = EntityUtils.toString(nestedResponse.getEntity()); log.warn("andrvotr/fabricate error body: [{}]", body.replace("\n", "[\\n]")); } } catch (Exception e) { diff --git a/andrvotr-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/andrvotr-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml index c93102e..960cfc9 100644 --- a/andrvotr-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml +++ b/andrvotr-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml @@ -19,7 +19,7 @@ class="io.github.fmfi_svt.andrvotr.AuthorityTokenGenerator" p:config-ref="andrvotr.Config" p:dataSealer-ref="shibboleth.DataSealer" - p:idpSessionCookieName="%{idp.session.cookieName:__Host-shib_idp_session}" + p:idpSessionCookieName="%{idp.session.cookieName:shib_idp_session}" p:tokenLifetime="%{andrvotr.authorityTokenLifetime:PT5M}" /> UTF-8 - 17 + 11 3.3.0 1.0.16 @@ -35,9 +35,9 @@ 2.18.0 net.shibboleth.idp - 5.0.0 + 4.2.0 org.opensaml - 5.0.0 + 4.2.0 ${project.basedir}/resources/checkstyle/checkstyle.xml