[java-identity-provider] branch master updated: IDP-644 Use SAML metadata as source of CAS proxy trust.
Marvin S. Addison
marvin.addison at gmail.com
Fri Sep 21 12:10:57 EDT 2018
This is an automated email from the git hooks/post-receive script.
serac 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=a9e8a35f36fc502b002cc54f047ad81ab3317a11
The following commit(s) were added to refs/heads/master by this push:
new a9e8a35 IDP-644 Use SAML metadata as source of CAS proxy trust.
a9e8a35 is described below
commit a9e8a35f36fc502b002cc54f047ad81ab3317a11
Author: Marvin S. Addison <serac at vt.edu>
AuthorDate: Tue Jun 19 17:03:40 2018 -0400
IDP-644 Use SAML metadata as source of CAS proxy trust.
Leverage a chaining trust engine to search SAML metadata for
explicitly trusted certificates with fallback to PKIX-based validation
over a list of CA certificates.
The ProxyAuthenticator interface was deprecated by this work; it is
superseded by ProxyValidator. The ability to customize the proxy
validation component in user-space configuration has been replaced
by a facility to edit the list of trusted CA certificates, which is
the commonplace configuration requirement. The default is an empty
list.
See https://issues.shibboleth.net/jira/browse/IDP-644
See https://issues.shibboleth.net/jira/browse/IDP-701
---
.../idp/cas/proxy/ProxyAuthenticator.java | 4 +
...ProxyAuthenticator.java => ProxyValidator.java} | 21 +-
.../cas/flow/impl/ValidateProxyCallbackAction.java | 18 +-
.../cas/proxy/impl/AbstractProxyAuthenticator.java | 95 -------
.../proxy/impl/HttpClientProxyAuthenticator.java | 193 --------------
.../cas/proxy/impl/HttpClientProxyValidator.java | 282 +++++++++++++++++++++
.../idp/cas/flow/impl/AbstractFlowActionTest.java | 13 +
.../flow/impl/ValidateProxyCallbackActionTest.java | 13 +-
...Test.java => HttpClientProxyValidatorTest.java} | 79 +++---
.../src/test/resources/credentials/key.pem | 27 --
.../src/test/resources/credentials/nobody-1.p12 | Bin 3005 -> 2437 bytes
.../src/test/resources/credentials/nobody-1.pem | 48 ++--
.../test/resources/metadata/cas-test-metadata.xml | 38 +++
.../src/test/resources/spring/proxy-authn-test.xml | 59 -----
.../src/test/resources/spring/test-flow-beans.xml | 102 +++++++-
idp-conf/src/main/resources/conf/cas-protocol.xml | 19 +-
.../resources/system/conf/cas-protocol-system.xml | 31 ++-
.../idp/test/flows/cas/ProxyValidateFlowTest.java | 6 +-
.../test/flows/cas/ServiceValidateFlowTest.java | 6 +-
...yAuthenticator.java => TestProxyValidator.java} | 12 +-
.../src/test/resources/test/test-cas-beans.xml | 4 +-
21 files changed, 579 insertions(+), 491 deletions(-)
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java
index f15e777..882df01 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java
@@ -22,12 +22,16 @@ import java.net.URI;
import java.security.GeneralSecurityException;
/**
+ * Deprecated as of 3.4.0. Superseded by {@link ProxyValidator} interface.
+ * <p>
* Strategy pattern component for proxy callback authentication.
*
* @param <CriteriaType> Proxy validation criteria type.
*
* @author Marvin S. Addison
+ * @see ProxyValidator
*/
+ at Deprecated
public interface ProxyAuthenticator<CriteriaType> {
/**
* Authenticates the proxy callback URI.
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyValidator.java
similarity index 66%
copy from idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java
copy to idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyValidator.java
index f15e777..3b66e9d 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyAuthenticator.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/proxy/ProxyValidator.java
@@ -17,25 +17,26 @@
package net.shibboleth.idp.cas.proxy;
-import javax.annotation.Nonnull;
import java.net.URI;
import java.security.GeneralSecurityException;
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
/**
- * Strategy pattern component for proxy callback authentication.
- *
- * @param <CriteriaType> Proxy validation criteria type.
+ * Strategy pattern component for proxy callback endpoint validation.
*
* @author Marvin S. Addison
*/
-public interface ProxyAuthenticator<CriteriaType> {
+public interface ProxyValidator {
/**
- * Authenticates the proxy callback URI.
+ * Validates the proxy callback endpoint.
*
- * @param uri Proxy callback URI to validate.
- * @param criteria Validation criteria.
+ * @param profileRequestContext Profile request context.
+ * @param proxyCallbackUri Proxy callback URI to validate.
*
- * @throws java.security.GeneralSecurityException On authentication failure.
+ * @throws GeneralSecurityException On validation failure.
*/
- void authenticate(@Nonnull URI uri, CriteriaType criteria) throws GeneralSecurityException;
+ void validate(@Nonnull ProfileRequestContext profileRequestContext, @Nonnull URI proxyCallbackUri)
+ throws GeneralSecurityException;
}
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
index 7b81ef7..a8abb17 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
@@ -26,6 +26,7 @@ import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
import net.shibboleth.idp.cas.config.impl.ValidateConfiguration;
import net.shibboleth.idp.cas.proxy.ProxyAuthenticator;
import net.shibboleth.idp.cas.proxy.ProxyIdentifiers;
+import net.shibboleth.idp.cas.proxy.ProxyValidator;
import net.shibboleth.idp.cas.ticket.ProxyTicket;
import net.shibboleth.idp.cas.ticket.ServiceTicket;
import net.shibboleth.idp.cas.ticket.Ticket;
@@ -72,7 +73,7 @@ public class ValidateProxyCallbackAction
/** Validates the proxy callback endpoint. */
@Nonnull
- private final ProxyAuthenticator<TrustEngine<? super X509Credential>> proxyAuthnticator;
+ private final ProxyValidator proxyValidator;
/** Manages CAS tickets. */
@Nonnull
@@ -82,13 +83,13 @@ public class ValidateProxyCallbackAction
/**
* Creates a new instance.
*
- * @param proxyAuthenticator Component that validates the proxy callback endpoint.
+ * @param validator Component that validates the proxy callback endpoint.
* @param ticketService Ticket service component.
*/
public ValidateProxyCallbackAction(
- @Nonnull final ProxyAuthenticator<TrustEngine<? super X509Credential>> proxyAuthenticator,
+ @Nonnull final ProxyValidator validator,
@Nonnull final TicketServiceEx ticketService) {
- proxyAuthnticator = Constraint.isNotNull(proxyAuthenticator, "ProxyAuthenticator cannot be null");
+ proxyValidator = Constraint.isNotNull(validator, "ProxyValidator cannot be null");
ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
}
@@ -126,14 +127,7 @@ public class ValidateProxyCallbackAction
}
try {
log.debug("Attempting proxy authentication to {}", proxyCallbackUri);
- final TrustEngine<? super X509Credential> engine;
- if (config.getSecurityConfiguration().getClientTLSValidationConfiguration() != null) {
- engine = config.getSecurityConfiguration().getClientTLSValidationConfiguration().getX509TrustEngine();
- } else {
- log.debug("Proxy-granting ticket configuration does not define ClientTLSValidationConfiguration");
- engine = null;
- }
- proxyAuthnticator.authenticate(proxyCallbackUri, engine);
+ proxyValidator.validate(profileRequestContext, proxyCallbackUri);
final Instant expiration = DateTime.now().plus(config.getTicketValidityPeriod()).toInstant();
if (ticket instanceof ServiceTicket) {
ticketServiceEx.createProxyGrantingTicket(proxyIds.getPgtId(), expiration, (ServiceTicket) ticket);
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/AbstractProxyAuthenticator.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/AbstractProxyAuthenticator.java
deleted file mode 100644
index 19d4a30..0000000
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/AbstractProxyAuthenticator.java
+++ /dev/null
@@ -1,95 +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.cas.proxy.impl;
-
-import java.net.URI;
-import java.security.GeneralSecurityException;
-import java.util.Collections;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.security.auth.login.FailedLoginException;
-
-import net.shibboleth.idp.cas.proxy.ProxyAuthenticator;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.security.x509.X509Credential;
-
-/**
- * Base class for CAS proxy authenticators that make an HTTPS connection to the endpoint at the callback URI.
- * The response code and TLS certificate are examined as the basis for authentication.
- *
- * @author Marvin S. Addison
- */
-public abstract class AbstractProxyAuthenticator implements ProxyAuthenticator<TrustEngine<? super X509Credential>> {
-
- /** Required https scheme for proxy callbacks. */
- protected static final String HTTPS_SCHEME = "https";
-
- /** List of HTTP response codes permitted for successful proxy callback. */
- @NotEmpty
- @NonnullElements
- private Set<Integer> allowedResponseCodes = Collections.singleton(200);
-
- /**
- * Sets the HTTP response codes permitted for successful authentication of the proxy callback URL.
- *
- * @param responseCodes One or more HTTP response codes.
- */
- public void setAllowedResponseCodes(@NotEmpty @NonnullElements final Set<Integer> responseCodes) {
- Constraint.isNotEmpty(responseCodes, "Response codes cannot be null or empty.");
- Constraint.noNullItems(responseCodes.toArray(), "Response codes cannot contain null elements.");
- this.allowedResponseCodes = responseCodes;
- }
-
- @Override public final void authenticate(@Nonnull final URI credential,
- @Nullable final TrustEngine<? super X509Credential> criteria) throws GeneralSecurityException {
-
- Constraint.isNotNull(credential, "URI to authenticate cannot be null.");
- if (!HTTPS_SCHEME.equalsIgnoreCase(credential.getScheme())) {
- throw new GeneralSecurityException(credential + " is not an https URI as required.");
- }
- final int status = authenticateProxyCallback(credential, criteria);
- if (!allowedResponseCodes.contains(status)) {
- throw new FailedLoginException(credential + " returned unacceptable HTTP status code " + status);
- }
- }
-
- /**
- * Authenticates the proxy callback URI by making an HTTP GET request and returning the HTTP response code.
- * The TLS trust evaluation on the certificate at the HTTPS endpoint MUST be performed as part of the request
- * process.
- *
- * @param callbackUri Proxy callback URI containing requisite CAS protocol parameters, <code>pgtId</code> and
- * <code>pgtIou</code>.
- * @param x509TrustEngine X.509 trust engine used to perform trust calcluation on TLS certificate of URI endpoint.
- *
- * @return Status code from HTTP GET request.
- *
- * @throws GeneralSecurityException On a failure related to establishing the HTTP connection due to SSL/TLS errors.
- * @throws RuntimeException On networking errors (IO, HTTP protocol).
- */
- protected abstract int authenticateProxyCallback(
- @Nonnull URI callbackUri,
- @Nullable TrustEngine<? super X509Credential> x509TrustEngine)
- throws GeneralSecurityException;
-
-}
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticator.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticator.java
deleted file mode 100644
index 9647804..0000000
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticator.java
+++ /dev/null
@@ -1,193 +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.cas.proxy.impl;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.net.URI;
-import java.security.GeneralSecurityException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.annotation.Nonnull;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-
-import com.beust.jcommander.internal.Nullable;
-import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContexts;
-import org.apache.http.conn.ssl.TrustStrategy;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
-import org.opensaml.security.SecurityException;
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.security.x509.BasicX509Credential;
-import org.opensaml.security.x509.X509Credential;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Authenticates a CAS proxy callback endpoint using an {@link org.apache.http.client.HttpClient} instance.
- *
- * @author Marvin S. Addison
- */
-public class HttpClientProxyAuthenticator extends AbstractProxyAuthenticator {
-
- /**
- * Delegates X.509 certificate trust to an underlying OpenSAML <code>TrustEngine</code>.
- */
- private static class TrustEngineTrustStrategy implements TrustStrategy {
-
- /** Trust engine. */
- private final TrustEngine<? super X509Credential> trustEngine;
-
- /** Class logger. */
- private final Logger log = LoggerFactory.getLogger(TrustEngineTrustStrategy.class);
-
- /**
- * Constructor.
- *
- * @param engine trust engine
- */
- public TrustEngineTrustStrategy(final TrustEngine<? super X509Credential> engine) {
- trustEngine = engine;
- }
-
- @Override
- public boolean isTrusted(final X509Certificate[] certificates, final String authType)
- throws CertificateException {
- if (trustEngine == null || certificates == null || certificates.length < 1) {
- return false;
- }
- // Assume the first certificate is the end-entity cert
- try {
- log.debug("Validating cert {} issued by {}",
- certificates[0].getSubjectDN().getName(),
- certificates[0].getIssuerDN().getName());
- return trustEngine.validate(new BasicX509Credential(certificates[0]), new CriteriaSet());
- } catch (final SecurityException e) {
- throw new CertificateException("X509 validation error", e);
- }
- }
- }
-
- /** Default connection and socket timeout in ms. */
- private static final int DEFAULT_TIMEOUT = 800;
-
- /** Class logger. */
- private final Logger log = LoggerFactory.getLogger(HttpClientProxyAuthenticator.class);
-
- /** Connection and socket timeout. */
- @Positive
- private int t = DEFAULT_TIMEOUT;
-
-
- /**
- * Sets connect and socket timeouts for HTTP connection to proxy callback endpoint.
- *
- * @param timeout Non-zero timeout in milliseconds for both connection and socket timeouts.
- */
- public void setTimeout(@Positive final int timeout) {
- t = (int) Constraint.isGreaterThan(0, timeout, "Timeout must be positive");
- }
-
- @Override
- protected int authenticateProxyCallback(
- @Nonnull final URI callbackUri,
- @Nullable final TrustEngine<? super X509Credential> x509TrustEngine)
- throws GeneralSecurityException {
-
- CloseableHttpClient httpClient = null;
- CloseableHttpResponse response = null;
- try {
- httpClient = createHttpClient(x509TrustEngine);
- log.debug("Attempting to connect to {}", callbackUri);
- final HttpGet request = new HttpGet(callbackUri);
- request.setConfig(
- RequestConfig.custom()
- .setConnectTimeout(t)
- .setSocketTimeout(t)
- .build());
- response = httpClient.execute(request);
- return response.getStatusLine().getStatusCode();
- } catch (final ClientProtocolException e) {
- throw new GeneralSecurityException("HTTP protocol error", e);
- } catch (final SSLException e) {
- if (e.getCause() instanceof CertificateException) {
- throw (CertificateException) e.getCause();
- }
- throw new GeneralSecurityException("SSL connection error", e);
- } catch (final IOException e) {
- throw new GeneralSecurityException("IO error", e);
- } finally {
- close(response);
- close(httpClient);
- }
- }
-
- /**
- * Build HTTP client.
- *
- * @param x509TrustEngine trust engine
- * @return HTTP client
- */
- private CloseableHttpClient createHttpClient(final TrustEngine<? super X509Credential> x509TrustEngine) {
- final SSLConnectionSocketFactory socketFactory;
- try {
- final SSLContext sslContext = SSLContexts.custom()
- .useTLS()
- .loadTrustMaterial(null, new TrustEngineTrustStrategy(x509TrustEngine))
- .build();
- socketFactory = new SSLConnectionSocketFactory(
- sslContext,
- SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
- } catch (final Exception e) {
- throw new RuntimeException("SSL initialization error", e);
- }
- final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
- .register(HTTPS_SCHEME, socketFactory).build();
- final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(registry);
- return HttpClients.custom().setConnectionManager(connectionManager).build();
- }
-
- /**
- * Close the resource.
- *
- * @param resource the resource to close
- */
- private void close(final Closeable resource) {
- if (resource != null) {
- try {
- resource.close();
- } catch (final IOException e) {
- log.warn("Error closing " + resource, e);
- }
- }
- }
-}
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidator.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidator.java
new file mode 100644
index 0000000..32a733c
--- /dev/null
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidator.java
@@ -0,0 +1,282 @@
+/*
+ * 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.cas.proxy.impl;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.security.auth.login.FailedLoginException;
+
+import com.google.common.base.Function;
+import net.shibboleth.idp.cas.config.impl.AbstractProtocolConfiguration;
+import net.shibboleth.idp.cas.proxy.ProxyValidator;
+import net.shibboleth.idp.cas.service.Service;
+import net.shibboleth.idp.cas.service.ServiceContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.criterion.EntityRoleCriterion;
+import org.opensaml.saml.criterion.ProtocolCriterion;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.security.SecurityException;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.criteria.UsageCriterion;
+import org.opensaml.security.trust.TrustEngine;
+import org.opensaml.security.x509.BasicX509Credential;
+import org.opensaml.security.x509.X509Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Authenticates a CAS proxy callback endpoint using an {@link org.apache.http.client.HttpClient} instance to establish
+ * the connection and a {@link TrustEngine} to verify the TLS certificate presented by the remote peer. The endpoint
+ * is validated if and only if the following requirements are met:
+ *
+ * <ol>
+ * <li>Proxy callback URI specifies the <code>https</code> scheme.</li>
+ * <li>The TLS certificate presented by the remote peer is trusted.</li>
+ * <li>The HTTP response status code is in the set of {@link #allowedResponseCodes} (only 200 by default).</li>
+ * </ol>
+ *
+ * @author Marvin S. Addison
+ */
+public class HttpClientProxyValidator implements ProxyValidator {
+
+ /** Required https scheme for proxy callbacks. */
+ protected static final String HTTPS_SCHEME = "https";
+
+ /** Default connection and socket timeout in ms. */
+ private static final int DEFAULT_TIMEOUT = 800;
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(HttpClientProxyValidator.class);
+
+ /** Trust engine that validates proxy endpoint TLS certificates. */
+ @Nonnull
+ private final TrustEngine<? super X509Credential> trustEngine;
+
+ /** Looks up a ServiceContext from the profile request context. */
+ private final Function<ProfileRequestContext, ServiceContext> serviceCtxLookupFunction =
+ new ChildContextLookup<>(ServiceContext.class);
+
+ /** List of HTTP response codes permitted for successful proxy callback. */
+ @NotEmpty
+ @NonnullElements
+ private Set<Integer> allowedResponseCodes = Collections.singleton(200);
+
+ /** Connection and socket timeout. */
+ @Positive
+ private int timeout = DEFAULT_TIMEOUT;
+
+
+ /**
+ * Creates a new instance.
+ *
+ * @param engine Trust engine to use for validating proxy X.509 certificate credentials.
+ */
+ public HttpClientProxyValidator(@Nonnull final TrustEngine<? super X509Credential> engine) {
+ trustEngine = Constraint.isNotNull(engine, "Trust engine cannot be null");
+ }
+
+ /**
+ * Sets connect and socket timeouts for HTTP connection to proxy callback endpoint.
+ *
+ * @param timeoutMillis Non-zero timeout in milliseconds for both connection and socket timeouts.
+ */
+ public void setTimeout(@Positive final int timeoutMillis) {
+ timeout = (int) Constraint.isGreaterThan(0, timeoutMillis, "Timeout must be positive");
+ }
+
+ /**
+ * Sets the HTTP response codes permitted for successful authentication of the proxy callback URL.
+ *
+ * @param responseCodes One or more HTTP response codes.
+ */
+ public void setAllowedResponseCodes(@NotEmpty @NonnullElements final Set<Integer> responseCodes) {
+ Constraint.isNotEmpty(responseCodes, "Response codes cannot be null or empty.");
+ Constraint.noNullItems(responseCodes.toArray(), "Response codes cannot contain null elements.");
+ allowedResponseCodes = responseCodes;
+ }
+
+ @Override
+ public void validate (
+ @Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final URI proxyCallbackUri)
+ throws GeneralSecurityException {
+
+ Constraint.isNotNull(proxyCallbackUri, "Proxy callback URI cannot be null");
+ if (!HTTPS_SCHEME.equalsIgnoreCase(proxyCallbackUri.getScheme())) {
+ throw new GeneralSecurityException(proxyCallbackUri + " is not an https URI as required.");
+ }
+ final ServiceContext serviceContext = serviceCtxLookupFunction.apply(profileRequestContext);
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context not found in profile request context as required");
+ }
+ final int status = connect(proxyCallbackUri, serviceContext.getService());
+ if (!allowedResponseCodes.contains(status)) {
+ throw new FailedLoginException(proxyCallbackUri + " returned unacceptable HTTP status code: " + status);
+ }
+ }
+
+ /**
+ * Connect to the given CAS proxy callback endpoint and return the HTTP response code. TLS peer certificate
+ * validation is an essential security aspect of establishing the connection.
+ *
+ * @param uri CAS proxy callback URI to connect to.
+ * @param service CAS service requesting the connection.
+ * @return HTTP response code.
+ * @throws GeneralSecurityException On connection errors, e.g. invalid/untrusted cert.
+ */
+ protected int connect(@Nonnull final URI uri, @Nonnull Service service) throws GeneralSecurityException {
+
+ CloseableHttpClient httpClient = null;
+ CloseableHttpResponse response = null;
+ try {
+ httpClient = createHttpClient(service);
+ log.debug("Attempting to connect to {}", uri);
+ final HttpGet request = new HttpGet(uri);
+ request.setConfig(
+ RequestConfig.custom()
+ .setConnectTimeout(timeout)
+ .setSocketTimeout(timeout)
+ .build());
+ response = httpClient.execute(request);
+ return response.getStatusLine().getStatusCode();
+ } catch (final ClientProtocolException e) {
+ throw new GeneralSecurityException("HTTP protocol error", e);
+ } catch (final SSLException e) {
+ if (e.getCause() instanceof CertificateException) {
+ throw (CertificateException) e.getCause();
+ }
+ throw new GeneralSecurityException("SSL connection error", e);
+ } catch (final IOException e) {
+ throw new GeneralSecurityException("IO error", e);
+ } finally {
+ close(response);
+ close(httpClient);
+ }
+ }
+
+ /**
+ * Build HTTP client.
+ *
+ * @param service CAS service.
+ * @return HTTP client
+ */
+ protected CloseableHttpClient createHttpClient(final Service service) {
+ final SSLConnectionSocketFactory socketFactory;
+ try {
+ final SSLContext sslContext = SSLContextBuilder.create()
+ .loadTrustMaterial(null, new TrustEngineTrustStrategy(service))
+ .build();
+ socketFactory = new SSLConnectionSocketFactory(sslContext);
+ } catch (final Exception e) {
+ throw new RuntimeException("SSL initialization error", e);
+ }
+ final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+ .register(HTTPS_SCHEME, socketFactory).build();
+ final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(registry);
+ return HttpClients.custom().setConnectionManager(connectionManager).build();
+ }
+
+ /**
+ * Close the resource.
+ *
+ * @param resource the resource to close
+ */
+ private void close(final Closeable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (final IOException e) {
+ log.warn("Error closing " + resource, e);
+ }
+ }
+ }
+
+ /**
+ * Delegates X.509 certificate trust to an underlying OpenSAML <code>TrustEngine</code>.
+ */
+ private class TrustEngineTrustStrategy implements TrustStrategy {
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(TrustEngineTrustStrategy.class);
+
+ /** CAS protocol service. */
+ private final Service service;
+
+
+ public TrustEngineTrustStrategy(final Service s) {
+ service = s;
+ }
+
+ @Override
+ public boolean isTrusted(final X509Certificate[] certificates, final String authType)
+ throws CertificateException {
+ if (certificates == null || certificates.length < 1) {
+ return false;
+ }
+ // Assume the first certificate is the end-entity cert
+ try {
+ log.debug("Validating cert {} issued by {}",
+ certificates[0].getSubjectDN().getName(),
+ certificates[0].getIssuerDN().getName());
+ final String entityID;
+ if (service.getEntityDescriptor() != null) {
+ entityID = service.getEntityDescriptor().getEntityID();
+ } else {
+ entityID = service.getName();
+ }
+ final CriteriaSet criteria = new CriteriaSet(
+ new EntityIdCriterion(entityID),
+ new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME),
+ new ProtocolCriterion(AbstractProtocolConfiguration.PROTOCOL_URI),
+ new UsageCriterion(UsageType.SIGNING));
+ return trustEngine.validate(new BasicX509Credential(certificates[0]), criteria);
+ } catch (final SecurityException e) {
+ throw new CertificateException("X509 validation error", e);
+ }
+ }
+ }
+}
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/AbstractFlowActionTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/AbstractFlowActionTest.java
index 11a184c..b3b6210 100644
--- a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/AbstractFlowActionTest.java
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/AbstractFlowActionTest.java
@@ -32,6 +32,8 @@ import net.shibboleth.idp.session.SessionException;
import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
import org.joda.time.DateTime;
import org.joda.time.Instant;
+import org.opensaml.core.config.InitializationException;
+import org.opensaml.core.config.InitializationService;
import org.opensaml.profile.context.ProfileRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
@@ -39,6 +41,7 @@ import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.webflow.execution.RequestContext;
+import org.testng.annotations.BeforeSuite;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -125,4 +128,14 @@ public abstract class AbstractFlowActionTest extends AbstractTestNGSpringContext
protected ProxyGrantingTicket createProxyGrantingTicket(final ProxyTicket pt) {
return ticketService.createProxyGrantingTicket(generateProxyGrantingTicketId(), expiry(), pt);
}
+
+ /**
+ * Initialize OpenSAML.
+ *
+ * @throws InitializationException
+ */
+ @BeforeSuite
+ public void initOpenSAML() throws InitializationException {
+ InitializationService.initialize();
+ }
}
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackActionTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackActionTest.java
index 8e14c0d..772fa64 100644
--- a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackActionTest.java
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackActionTest.java
@@ -24,12 +24,11 @@ import net.shibboleth.idp.cas.config.impl.ValidateConfiguration;
import net.shibboleth.idp.cas.protocol.ProtocolError;
import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
-import net.shibboleth.idp.cas.proxy.ProxyAuthenticator;
+import net.shibboleth.idp.cas.proxy.ProxyValidator;
import net.shibboleth.idp.cas.ticket.ServiceTicket;
import net.shibboleth.idp.cas.ticket.TicketState;
import org.joda.time.Instant;
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.security.x509.X509Credential;
+import org.opensaml.profile.context.ProfileRequestContext;
import org.springframework.webflow.execution.RequestContext;
import org.testng.annotations.Test;
@@ -65,13 +64,13 @@ public class ValidateProxyCallbackActionTest extends AbstractFlowActionTest {
ProtocolError.ProxyCallbackAuthenticationFailure.name());
}
- private static ProxyAuthenticator<TrustEngine<? super X509Credential>> mockProxyAuthenticator(final Exception toBeThrown)
+ private static ProxyValidator mockProxyAuthenticator(final Exception toBeThrown)
throws Exception {
- final ProxyAuthenticator<TrustEngine<? super X509Credential>> authenticator = mock(ProxyAuthenticator.class);
+ final ProxyValidator validator = mock(ProxyValidator.class);
if (toBeThrown != null) {
- doThrow(toBeThrown).when(authenticator).authenticate(any(URI.class), any(TrustEngine.class));
+ doThrow(toBeThrown).when(validator).validate(any(ProfileRequestContext.class), any(URI.class));
}
- return authenticator;
+ return validator;
}
private static RequestContext newRequestContext(final String pgtURL) {
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticatorTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidatorTest.java
similarity index 64%
rename from idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticatorTest.java
rename to idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidatorTest.java
index faa2036..09b6a36 100644
--- a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyAuthenticatorTest.java
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/proxy/impl/HttpClientProxyValidatorTest.java
@@ -26,13 +26,14 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import net.shibboleth.idp.cas.flow.impl.AbstractFlowActionTest;
+import net.shibboleth.idp.cas.service.Service;
+import net.shibboleth.idp.cas.service.ServiceContext;
import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.security.x509.X509Credential;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.opensaml.profile.context.ProfileRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
@@ -45,18 +46,14 @@ import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
- * Unit test for {@link HttpClientProxyAuthenticator} class.
+ * Unit test for {@link HttpClientProxyValidator} class.
*
* @author Marvin S. Addison
*/
- at ContextConfiguration(
- locations = "/spring/proxy-authn-test.xml",
- initializers = IdPPropertiesApplicationContextInitializer.class)
- at WebAppConfiguration
- at TestPropertySource(properties = {"idp.initializer.failFast = false"})
-public class HttpClientProxyAuthenticatorTest extends AbstractTestNGSpringContextTests {
+public class HttpClientProxyValidatorTest extends AbstractFlowActionTest {
- private HttpClientProxyAuthenticator authenticator = new HttpClientProxyAuthenticator();
+ @Autowired
+ private HttpClientProxyValidator validator;
@Autowired
private ApplicationContext context;
@@ -64,34 +61,46 @@ public class HttpClientProxyAuthenticatorTest extends AbstractTestNGSpringContex
@DataProvider(name = "data")
public Object[][] buildTestData() {
return new Object[][] {
- // Trusted cert and acceptable response code
- new Object[] { "testCase1", 200, null },
-
- // Trusted cert and unacceptable response code
- new Object[] { "testCase1", 404, new FailedLoginException() },
+ // Trusted cert from static trust source and acceptable response code
+ new Object[] { "https://localhost:8443", "src/test/resources/credentials/localhost.p12", 200, null },
+
+ // Trusted cert from metadata source and acceptable response code
+ new Object[] {
+ "https://nobody-1.middleware.vt.edu/",
+ "src/test/resources/credentials/nobody-1.p12",
+ 200,
+ null,
+ },
+
+ // Trusted cert from static trust source and unacceptable response code
+ new Object[] {
+ "https://localhost:8443",
+ "src/test/resources/credentials/localhost.p12",
+ 404,
+ new FailedLoginException()
+ },
// Untrusted cert
- new Object[] { "testCase2", 200, new CertificateException() },
-
- // Ensure cert is rejected when no trust engine is configured
- new Object[] { "doesNotExist", 200, new CertificateException() },
+ new Object[] {
+ "https://localhost:8443",
+ "src/test/resources/credentials/nobody-2.p12",
+ 200,
+ new CertificateException(),
+ },
};
}
@Test(dataProvider = "data")
- public void testAuthenticate(final String trustEngineBean, final int status, final Exception expected)
+ public void testAuthenticate(
+ final String serviceURL, final String keyStorePath, final int status, final Exception expected)
throws Exception {
Server server = null;
try {
- server = startServer(new ConfigurableStatusHandler(status));
- TrustEngine<X509Credential> trustEngine;
- try {
- trustEngine = context.getBean(trustEngineBean, TrustEngine.class);
- } catch (NoSuchBeanDefinitionException e) {
- trustEngine = null;
- }
- authenticator.setTimeout(5000); // 5s timeout for Windows
- authenticator.authenticate(new URI("https://localhost:8443/?pgtId=A&pgtIOU=B"), trustEngine);
+ server = startServer(keyStorePath, new ConfigurableStatusHandler(status));
+ validator.setTimeout(5000); // 5s timeout for Windows
+ validator.validate(
+ buildProfileRequestContext(serviceURL),
+ new URI("https://localhost:8443/?pgtId=A&pgtIOU=B"));
if (expected != null) {
fail("Proxy authentication should have failed with " + expected);
}
@@ -107,12 +116,12 @@ public class HttpClientProxyAuthenticatorTest extends AbstractTestNGSpringContex
}
}
- private Server startServer(final Handler handler) {
+ private Server startServer(final String keyStorePath, final Handler handler) {
final Server server = new Server();
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreType("PKCS12");
- sslContextFactory.setKeyStorePath("src/test/resources/credentials/localhost.p12");
+ sslContextFactory.setKeyStorePath(keyStorePath);
sslContextFactory.setKeyStorePassword("changeit");
final ServerConnector connector = new ServerConnector(server, sslContextFactory);
connector.setHost("127.0.0.1");
@@ -160,4 +169,10 @@ public class HttpClientProxyAuthenticatorTest extends AbstractTestNGSpringContex
servletResponse.getWriter().println("OK");
}
}
+
+ private ProfileRequestContext buildProfileRequestContext(final String serviceUrl) {
+ final ProfileRequestContext prc = new ProfileRequestContext();
+ prc.addSubcontext(new ServiceContext(new Service(serviceUrl, "unknown", true, false)));
+ return prc;
+ }
}
diff --git a/idp-cas-impl/src/test/resources/credentials/key.pem b/idp-cas-impl/src/test/resources/credentials/key.pem
deleted file mode 100644
index 72286ae..0000000
--- a/idp-cas-impl/src/test/resources/credentials/key.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpgIBAAKCAQEA6qltZdTHBsCtldcjb5ROMB+RBJRGIjO+n8E+IaIfu4AW/M7a
-eWBbQF7Mmq6cpxhxVBNqWdt0pDuvu9YRT8KwwCMMm+4BYh1a1aJrT+QNuQPCtx8Q
-LSRNAb8YFjnpX5Y92ZAGpHkLTZTUFXTM0mSWPLCiVcFHQjMdtFoQYk/PINvYoN//
-Mqb44Sas7JHccr17TCYDvh7G4yG+U2MFumD6Mnly4OCVnG04giPNBCCkdCt6p4tF
-uuoBTrTrGyN3Wd62cdHO5DBQ8b4ESjz6QutpIYOjJIFZYEW6OeKwiMDKgo4xaOzN
-4hIlBCj9j0Wfe9gGoHpKfirCxFOHSfOqB8OMSwIDAQABAoIBAQCCTTgw7ljhuAXr
-iT3lDF3qPO0CtO7IuSDlhqFgfazPKc4Z7SbFdSrWcI1+au0Tn+/19p38bW60b2wi
-ijisqHgLCKtMvnlIKPKyY/DguMqh7KOnmXkbB+g2ywyt8tRSvpNzhpUZqRkMqFKn
-42aEgVQnORG7Ooq+CLI63jPw0045eKm7qUZEYktW2zHnYe/0Zzyw1ZMMRemRN/0P
-osvNvvt6jWGLslQ9uikTEOhy/2R6/Zzt4Bf8I+UXbXVobk2mljEjmHLIJ6u7H6dW
-cvKXB4PPMi8yZ0QhlvqHufJMvsNSoh4E7n5y3LNNFUB3DcAbPuz47WB5OSBM6fF7
-yLitCCF5AoGBAP/Yg91Nll49ipViT9FHYfjSdjL7SvSpwad5CdXCZG6LBcFdfnyD
-rMmbkPKqj6GB0wvKVvNf2BlVrM5m/nE6vBIZIs6rsBJ/14Z0wwEJ+jRaM99fioYX
-8OTKrdi8HwRL967T+XaGx31uCKLM9PxjEkRTL9qlLMnDvqQXY3efquTXAoGBAOrN
-pJVWMzlKsb8YfmuOd9SrGMDFsNpQKCeDhR+A8I6Kpx+bF04zh624ETwebw8D+Ug9
-d5arCpTVmBCBm/y88/nFNf6FZrOjNgBng9QxIDv78DIKk4w7p3ECTkmNfrhIH1LQ
-2sCUSSe0OyVXpW6sleSwR9wAhBCGqx1HKNGTXHGtAoGBALq5c+wVT1Ryh+1k9iog
-dgGa4QduXhNYveyTqzjmilQfhNDOgp0voPD3Z/+jufY/AR/Oyk0Pu3EqFVgC1Vsg
-adivnbbGmVe3FD6egyAD/ycsWkWBvmEFohvpTJ4tFloVc6yWKrB1x6zknMrs2TRG
-vjM9n2RtPtX21fF+3GqXDqu7AoGBALRR/WVab7g97sdM7jl3jfta8oWIzMq76DqA
-PIn3Ica2IKabGojJ9hapV0MONEgZyyV5Xw/shxHJ/yAeCUdNbSiSFWdD1515aA1j
-cdBRcenfD5W+nZWCcpLNLIY8DedELBoTnwtqVcwSE6IX70pRbEPWRTllhAaVBXBU
-p7pbKxF5AoGBAMCm2RXJXd4HDfQLMpclvut4dw5vQazzzTYCTT9V+OIFGczzNO4N
-JGWFBVYE+Vi9LRXGAS22inqVx/krCUTsx0w6zSfB61jrbjDeYgMAL4JzbjtvzZlf
-k5XhGPwJETNjmX7w88m/Ps8R3Eb46OujXSZtHVpWLzV49ZsX+QkqzyDj
------END RSA PRIVATE KEY-----
diff --git a/idp-cas-impl/src/test/resources/credentials/nobody-1.p12 b/idp-cas-impl/src/test/resources/credentials/nobody-1.p12
index 268acd3..6f82ff3 100644
Binary files a/idp-cas-impl/src/test/resources/credentials/nobody-1.p12 and b/idp-cas-impl/src/test/resources/credentials/nobody-1.p12 differ
diff --git a/idp-cas-impl/src/test/resources/credentials/nobody-1.pem b/idp-cas-impl/src/test/resources/credentials/nobody-1.pem
index 6e650d4..3e64e95 100644
--- a/idp-cas-impl/src/test/resources/credentials/nobody-1.pem
+++ b/idp-cas-impl/src/test/resources/credentials/nobody-1.pem
@@ -1,32 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIFdTCCBF2gAwIBAgIJAMkgCRPPZlWUMA0GCSqGSIb3DQEBBQUAMIHWMRMwEQYK
-CZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJBgNVBAYTAlVT
-MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzE8MDoGA1UE
-ChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0ZSBVbml2
-ZXJzaXR5MRMwEQYDVQQLEwpNaWRkbGV3YXJlMSMwIQYDVQQDExpub2JvZHktMS5t
-aWRkbGV3YXJlLnZ0LmVkdTAeFw0xMzEwMjgxODI2NTRaFw0xMzEwMjkxODI2NTRa
-MIHWMRMwEQYKCZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJ
-BgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVy
-ZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBT
-dGF0ZSBVbml2ZXJzaXR5MRMwEQYDVQQLEwpNaWRkbGV3YXJlMSMwIQYDVQQDExpu
-b2JvZHktMS5taWRkbGV3YXJlLnZ0LmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAOqpbWXUxwbArZXXI2+UTjAfkQSURiIzvp/BPiGiH7uAFvzO2nlg
-W0BezJqunKcYcVQTalnbdKQ7r7vWEU/CsMAjDJvuAWIdWtWia0/kDbkDwrcfEC0k
-TQG/GBY56V+WPdmQBqR5C02U1BV0zNJkljywolXBR0IzHbRaEGJPzyDb2KDf/zKm
-+OEmrOyR3HK9e0wmA74exuMhvlNjBbpg+jJ5cuDglZxtOIIjzQQgpHQreqeLRbrq
-AU606xsjd1netnHRzuQwUPG+BEo8+kLraSGDoySBWWBFujnisIjAyoKOMWjszeIS
-JQQo/Y9Fn3vYBqB6Sn4qwsRTh0nzqgfDjEsCAwEAAaOCAUIwggE+MB0GA1UdDgQW
-BBTOwc8F7f3BuMpdBs+eqw9CJX9YOjCCAQ0GA1UdIwSCAQQwggEAgBTOwc8F7f3B
-uMpdBs+eqw9CJX9YOqGB3KSB2TCB1jETMBEGCgmSJomT8ixkARkWA2VkdTESMBAG
-CgmSJomT8ixkARkWAnZ0MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWEx
-EzARBgNVBAcTCkJsYWNrc2J1cmcxPDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNo
-bmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTETMBEGA1UECxMKTWlk
-ZGxld2FyZTEjMCEGA1UEAxMabm9ib2R5LTEubWlkZGxld2FyZS52dC5lZHWCCQDJ
-IAkTz2ZVlDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQDObMj/tqrx
-UATFvFEqtwX2+XAsARDkykVebmQ4FIdEXkHLaekDmD/F5iHA/8cx1njQZ7RKHmDh
-agVq4wl8SI+X30gcUHo9+YP/Eqkm6klb5zu8HzFdo1s5cqGs+VU24C8h15jDPvh9
-z39GX3i1KTiiiTqdws8ItTOmJZhNDGZKDEnLkADHY9fzX2X9z8BjY3HeM5MsOIhA
-WJF3u019zc/r090KB4KGQhkmgBCj+SNse2+whPJ/L+nEMt2oRqrmGlOHepFUJ8MP
-qTGyrndSW8Tbl7RT5Ajb8wrTbi/pG4XLiaCQc9EM+jzCFm6QlnfYAGK9/5mrbiUF
-flGs7q/KiJxm
+MIIDPDCCAiSgAwIBAgIGAWQZpmybMA0GCSqGSIb3DQEBCwUAMFIxIzAhBgNVBAMM
+Gm5vYm9keS0xLm1pZGRsZXdhcmUudnQuZWR1MRMwEQYDVQQLDApNaWRkbGV3YXJl
+MRYwFAYDVQQKDA1WaXJnaW5pYSBUZWNoMB4XDTE4MDYxOTIwMDQ1NFoXDTI4MDYx
+NjIwMDQ1NFowUjEjMCEGA1UEAwwabm9ib2R5LTEubWlkZGxld2FyZS52dC5lZHUx
+EzARBgNVBAsMCk1pZGRsZXdhcmUxFjAUBgNVBAoMDVZpcmdpbmlhIFRlY2gwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkGXo1bVrEJ2rc4SV2jREraYaE
+h2jJ+B+vCSq2HYEyfXQpqn+yZL+Uo2wI3P9KyS11KOMTG1u5d5DPx+r052BqgZoz
+AU1j/lRbrAS5dfHzXW9G15hrQ6S4YHCnweyPcpXNXLeFG1Gh0R/wdW6ZVNUZrQok
+Pb/a1MK+gDlIuIuK3VSQilEb9UN+xmuuETniqPuzwYW2LZorUIg1eb+qSUdV24OW
+neVxhdp4uHM/rAtEIyJaAmjv3CF85yJ2FqMPATtl886alMj4hNA4j3Cyz27hRcYN
+L/c9BDjBRa1O9/zoC5D780HcC1+XX5KdBx2QWy200mmOK23UpzPEx1x/lVRFAgMB
+AAGjGDAWMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEA
+bq4BNVm+sFivrX8gnwcB2rnJK42wD01ZRZvm+QfmrPvzn1VHFJOt4quqhcSBCwl1
+xLla2c5+EWFN8EP0RPJuna8h92QC5H6fmebKoY/h7QoUs0HcJYORyR2XcAnx35jw
+8gBqd5i+orLdHa2tYTrDjZ2H6BOc6+Hf/YdsPffokH9Fs+gRzMBLz8kwSJl+Wfq/
+Fdv2QemEzfjpK4cZ+fXfSQvAIvpO/AfA9V8pufzoKp/THd3F8LYpH0gpolLdMwFk
+vTfFHoBotoh4+zh6TJP0OMrm04etuBZ46BOAITqqaUDM6QPR6JrLNR8m4wDfeVFP
+tsnEAiP3/AthxkAp0iQhFQ==
-----END CERTIFICATE-----
diff --git a/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml b/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml
index 908a785..a8a2350 100644
--- a/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml
+++ b/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml
@@ -235,4 +235,42 @@
</SPSSODescriptor>
</EntityDescriptor>
+ <!--
+ | Nobody-1 (authorizedToProxy="true", singleLogoutParticipant="false")
+ -->
+ <EntityDescriptor entityID="https://nobody-1.middleware.vt.edu/">
+ <SPSSODescriptor protocolSupportEnumeration="https://www.apereo.org/cas/protocol">
+ <KeyDescriptor use="signing">
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+ MIIDPDCCAiSgAwIBAgIGAWQZpmybMA0GCSqGSIb3DQEBCwUAMFIxIzAhBgNVBAMM
+ Gm5vYm9keS0xLm1pZGRsZXdhcmUudnQuZWR1MRMwEQYDVQQLDApNaWRkbGV3YXJl
+ MRYwFAYDVQQKDA1WaXJnaW5pYSBUZWNoMB4XDTE4MDYxOTIwMDQ1NFoXDTI4MDYx
+ NjIwMDQ1NFowUjEjMCEGA1UEAwwabm9ib2R5LTEubWlkZGxld2FyZS52dC5lZHUx
+ EzARBgNVBAsMCk1pZGRsZXdhcmUxFjAUBgNVBAoMDVZpcmdpbmlhIFRlY2gwggEi
+ MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkGXo1bVrEJ2rc4SV2jREraYaE
+ h2jJ+B+vCSq2HYEyfXQpqn+yZL+Uo2wI3P9KyS11KOMTG1u5d5DPx+r052BqgZoz
+ AU1j/lRbrAS5dfHzXW9G15hrQ6S4YHCnweyPcpXNXLeFG1Gh0R/wdW6ZVNUZrQok
+ Pb/a1MK+gDlIuIuK3VSQilEb9UN+xmuuETniqPuzwYW2LZorUIg1eb+qSUdV24OW
+ neVxhdp4uHM/rAtEIyJaAmjv3CF85yJ2FqMPATtl886alMj4hNA4j3Cyz27hRcYN
+ L/c9BDjBRa1O9/zoC5D780HcC1+XX5KdBx2QWy200mmOK23UpzPEx1x/lVRFAgMB
+ AAGjGDAWMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEA
+ bq4BNVm+sFivrX8gnwcB2rnJK42wD01ZRZvm+QfmrPvzn1VHFJOt4quqhcSBCwl1
+ xLla2c5+EWFN8EP0RPJuna8h92QC5H6fmebKoY/h7QoUs0HcJYORyR2XcAnx35jw
+ 8gBqd5i+orLdHa2tYTrDjZ2H6BOc6+Hf/YdsPffokH9Fs+gRzMBLz8kwSJl+Wfq/
+ Fdv2QemEzfjpK4cZ+fXfSQvAIvpO/AfA9V8pufzoKp/THd3F8LYpH0gpolLdMwFk
+ vTfFHoBotoh4+zh6TJP0OMrm04etuBZ46BOAITqqaUDM6QPR6JrLNR8m4wDfeVFP
+ tsnEAiP3/AthxkAp0iQhFQ==
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://localhost:8443/"
+ index="1"/>
+ </SPSSODescriptor>
+ </EntityDescriptor>
+
</EntitiesDescriptor>
diff --git a/idp-cas-impl/src/test/resources/spring/proxy-authn-test.xml b/idp-cas-impl/src/test/resources/spring/proxy-authn-test.xml
deleted file mode 100644
index 2db9691..0000000
--- a/idp-cas-impl/src/test/resources/spring/proxy-authn-test.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:c="http://www.springframework.org/schema/c"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
- default-init-method="initialize"
- default-destroy-method="destroy">
-
-
- <bean id="testCase1" class="org.opensaml.security.x509.impl.PKIXX509CredentialTrustEngine">
- <constructor-arg name="resolver">
- <bean class="org.opensaml.security.x509.impl.StaticPKIXValidationInformationResolver"
- c:names="#{null}">
- <constructor-arg name="info">
- <bean class="org.opensaml.security.x509.impl.BasicPKIXValidationInformation"
- c:crls="#{null}"
- c:depth="5">
- <constructor-arg name="anchors">
- <list>
- <bean class="net.shibboleth.ext.spring.factory.X509CertificateFactoryBean"
- p:resource="classpath:credentials/localhost.pem" />
- </list>
- </constructor-arg>
- </bean>
- </constructor-arg>
- </bean>
- </constructor-arg>
- <constructor-arg name="pkixEvaluator">
- <bean class="org.opensaml.security.x509.impl.CertPathPKIXTrustEvaluator" />
- </constructor-arg>
- <constructor-arg name="nameEvaluator"><null/></constructor-arg>
- </bean>
-
- <bean id="testCase2" class="org.opensaml.security.x509.impl.PKIXX509CredentialTrustEngine">
- <constructor-arg name="resolver">
- <bean class="org.opensaml.security.x509.impl.StaticPKIXValidationInformationResolver"
- c:names="#{null}">
- <constructor-arg name="info">
- <bean class="org.opensaml.security.x509.impl.BasicPKIXValidationInformation"
- c:crls="#{null}"
- c:depth="5">
- <constructor-arg name="anchors">
- <list>
- <bean class="net.shibboleth.ext.spring.factory.X509CertificateFactoryBean"
- p:resource="classpath:credentials/nobody-2.pem" />
- </list>
- </constructor-arg>
- </bean>
- </constructor-arg>
- </bean>
- </constructor-arg>
- <constructor-arg name="pkixEvaluator">
- <bean class="org.opensaml.security.x509.impl.CertPathPKIXTrustEvaluator" />
- </constructor-arg>
- <constructor-arg name="nameEvaluator"><null/></constructor-arg>
- </bean>
-
-</beans>
\ No newline at end of file
diff --git a/idp-cas-impl/src/test/resources/spring/test-flow-beans.xml b/idp-cas-impl/src/test/resources/spring/test-flow-beans.xml
index 0addcd1..bb2aa42 100644
--- a/idp-cas-impl/src/test/resources/spring/test-flow-beans.xml
+++ b/idp-cas-impl/src/test/resources/spring/test-flow-beans.xml
@@ -3,9 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd"
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize"
default-destroy-method="destroy">
@@ -78,8 +81,97 @@
</property>
</bean>
- <bean id="shibboleth.DefaultCASProxyAuthenticator"
- class="net.shibboleth.idp.cas.proxy.impl.HttpClientProxyAuthenticator" />
+ <util:list id="shibboleth.DefaultCASServiceRegistries">
+ <ref bean="shibboleth.CASServiceRegistry" />
+ </util:list>
+
+ <util:list id="shibboleth.CASProxyTrustedCertificates">
+ <bean class="net.shibboleth.ext.spring.factory.X509CertificateFactoryBean"
+ p:resource="classpath:/credentials/localhost.pem" />
+ </util:list>
+
+ <bean id="shibboleth.MetadataCredentialResolver"
+ class="org.opensaml.saml.security.impl.MetadataCredentialResolver"
+ p:roleDescriptorResolver-ref="shibboleth.RoleDescriptorResolver"
+ p:keyInfoCredentialResolver-ref="shibboleth.KeyInfoCredentialResolver">
+ </bean>
+
+ <bean id="shibboleth.KeyInfoCredentialResolver"
+ class="org.opensaml.xmlsec.config.impl.DefaultSecurityConfigurationBootstrap"
+ factory-method="buildBasicInlineKeyInfoCredentialResolver" />
+
+ <bean id="shibboleth.MetadataResolver"
+ class="org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver"
+ p:parserPool-ref="shibboleth.ParserPool">
+ <constructor-arg name="metadata">
+ <bean class="java.io.File" c:pathname="src/test/resources/metadata/cas-test-metadata.xml" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="shibboleth.RoleDescriptorResolver"
+ class="org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver"
+ c:mdResolver-ref="shibboleth.MetadataResolver" />
+
+ <bean id="shibboleth.OpenSAMLConfig" class="net.shibboleth.idp.spring.OpenSAMLConfigBean"
+ depends-on="shibboleth.ParserPool"
+ p:parserPool-ref="shibboleth.ParserPool" />
+
+ <bean id="shibboleth.ParserPool" class="net.shibboleth.utilities.java.support.xml.BasicParserPool"
+ p:maxPoolSize="100"
+ p:coalescing="true"
+ p:ignoreComments="true"
+ p:ignoreElementContentWhitespace="true"
+ p:namespaceAware="true">
+ <property name="builderAttributes">
+ <map>
+ <!-- Sun/Oracle is the default, for Xerces, set property to org.apache.xerces.util.SecurityManager -->
+ <entry key="http://apache.org/xml/properties/security-manager">
+ <bean class="com.sun.org.apache.xerces.internal.util.SecurityManager" />
+ </entry>
+ </map>
+ </property>
+ <property name="builderFeatures">
+ <map>
+ <entry key="http://apache.org/xml/features/disallow-doctype-decl">
+ <util:constant static-field="java.lang.Boolean.TRUE" />
+ </entry>
+ <entry key="http://apache.org/xml/features/validation/schema/normalized-value">
+ <util:constant static-field="java.lang.Boolean.FALSE" />
+ </entry>
+ <entry key="http://javax.xml.XMLConstants/feature/secure-processing">
+ <util:constant static-field="java.lang.Boolean.TRUE" />
+ </entry>
+ </map>
+ </property>
+ </bean>
+
+ <bean id="proxyTrustEngine" class="org.opensaml.security.trust.impl.ChainingTrustEngine">
+ <constructor-arg name="chain">
+ <list>
+ <bean class="org.opensaml.security.trust.impl.ExplicitX509CertificateTrustEngine"
+ c:resolver-ref="shibboleth.MetadataCredentialResolver" />
+ <bean class="org.opensaml.security.x509.impl.PKIXX509CredentialTrustEngine" c:nameEvaluator="#{null}">
+ <constructor-arg name="resolver">
+ <bean class="org.opensaml.security.x509.impl.StaticPKIXValidationInformationResolver" c:names="#{null}">
+ <constructor-arg name="info">
+ <bean class="org.opensaml.security.x509.impl.BasicPKIXValidationInformation"
+ c:anchors="#{getObject('shibboleth.CASProxyTrustedCertificates') ?: getObject('shibboleth.DefaultCASProxyTrustedCertificates')}"
+ c:crls="#{null}"
+ c:depth="5" />
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg name="pkixEvaluator">
+ <bean class="org.opensaml.security.x509.impl.CertPathPKIXTrustEvaluator" />
+ </constructor-arg>
+ </bean>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ <bean id="proxyValidator"
+ class="net.shibboleth.idp.cas.proxy.impl.HttpClientProxyValidator"
+ c:engine-ref="proxyTrustEngine" />
<!-- Flow beans -->
@@ -89,7 +181,7 @@
<bean id="buildRelyingPartyContextAction"
class="net.shibboleth.idp.cas.flow.impl.BuildRelyingPartyContextAction"
- c:registry-ref="shibboleth.CASServiceRegistry"/>
+ c:registries-ref="shibboleth.DefaultCASServiceRegistries" />
<bean id="buildSAMLMetadataContextAction"
class="net.shibboleth.idp.cas.flow.impl.BuildSAMLMetadataContextAction" />
@@ -108,7 +200,7 @@
<bean id="validateProxyCallbackAction"
class="net.shibboleth.idp.cas.flow.impl.ValidateProxyCallbackAction"
- c:proxyAuthenticator-ref="shibboleth.DefaultCASProxyAuthenticator"
+ c:validator-ref="proxyValidator"
c:ticketService-ref="shibboleth.CASTicketService" />
<bean id="validateRenewAction"
diff --git a/idp-conf/src/main/resources/conf/cas-protocol.xml b/idp-conf/src/main/resources/conf/cas-protocol.xml
index bddae19..c7ece39 100644
--- a/idp-conf/src/main/resources/conf/cas-protocol.xml
+++ b/idp-conf/src/main/resources/conf/cas-protocol.xml
@@ -3,6 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
@@ -85,6 +86,18 @@
class="net.shibboleth.idp.cas.service.impl.DefaultServiceComparator"
c:parameterNames="[a-z]+sessionid" />-->
+ <!--
+ | Define the list of static certificates that you trust to secure CAS proxy callback endpoints.
+ | Typically these are CA certificates and apply to _all_ CAS proxy callback endpoints.
+ | This facility complements the capability to supply relying-party-specific certificates in SAML metadata,
+ | which is the preferred mechanism to specify CAS proxy trust material. In the case of metadata, self-signed
+ | certificates are recommended.
+ -->
+ <util:list id="shibboleth.CASProxyTrustedCertificates">
+ <!--<bean class="net.shibboleth.ext.spring.factory.X509CertificateFactoryBean"
+ p:resource="%{idp.home}/credentials/your_ca.pem" /> -->
+ </util:list>
+
<!-- ============== Advanced CAS Configuration ============== -->
@@ -93,10 +106,4 @@
<bean id="shibboleth.CASTicketService"
class="org.example.idp.cas.CustomTicketService" />
-->
-
- <!-- Configure a third-party proxy authenticator. -->
- <!--
- <bean id="shibboleth.CASProxyAuthenticator"
- class="org.example.idp.cas.CustomProxyAuthenticator" />
- -->
</beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml b/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
index a3661db..d388059 100644
--- a/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
+++ b/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
@@ -36,8 +36,33 @@
<alias name="simpleTicketService" alias="shibboleth.DefaultCASTicketService" />
- <bean id="shibboleth.DefaultCASProxyAuthenticator"
- class="net.shibboleth.idp.cas.proxy.impl.HttpClientProxyAuthenticator" />
+ <bean id="proxyTrustEngine" class="org.opensaml.security.trust.impl.ChainingTrustEngine">
+ <constructor-arg name="chain">
+ <list>
+ <bean class="org.opensaml.security.trust.impl.ExplicitX509CertificateTrustEngine"
+ c:resolver-ref="shibboleth.MetadataCredentialResolver" />
+ <bean class="org.opensaml.security.x509.impl.PKIXX509CredentialTrustEngine" c:nameEvaluator="#{null}">
+ <constructor-arg name="resolver">
+ <bean class="org.opensaml.security.x509.impl.StaticPKIXValidationInformationResolver" c:names="#{null}">
+ <constructor-arg name="info">
+ <bean class="org.opensaml.security.x509.impl.BasicPKIXValidationInformation"
+ c:anchors="#{getObject('shibboleth.CASProxyTrustedCertificates') ?: getObject('shibboleth.DefaultCASProxyTrustedCertificates')}"
+ c:crls="#{null}"
+ c:depth="5" />
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg name="pkixEvaluator">
+ <bean class="org.opensaml.security.x509.impl.CertPathPKIXTrustEvaluator" />
+ </constructor-arg>
+ </bean>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ <bean id="proxyValidator"
+ class="net.shibboleth.idp.cas.proxy.impl.HttpClientProxyValidator"
+ c:engine-ref="proxyTrustEngine" />
<bean id="shibboleth.DefaultCASProxyValidateIdPSessionPredicate"
class="com.google.common.base.Predicates"
@@ -61,6 +86,8 @@
<ref bean="shibboleth.CASMetadataIndex" />
</util:set>
+ <util:list id="shibboleth.DefaultCASProxyTrustedCertificates" />
+
<import resource="../../conf/cas-protocol.xml" />
</beans>
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ProxyValidateFlowTest.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ProxyValidateFlowTest.java
index 44dbcfb..26f6a29 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ProxyValidateFlowTest.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ProxyValidateFlowTest.java
@@ -61,7 +61,7 @@ public class ProxyValidateFlowTest extends AbstractFlowTest {
private SessionManager sessionManager;
@Autowired
- private TestProxyAuthenticator testProxyAuthenticator;
+ private TestProxyValidator testProxyValidator;
@Test
public void testSuccess() throws Exception {
@@ -105,7 +105,7 @@ public class ProxyValidateFlowTest extends AbstractFlowTest {
externalContext.getMockRequestParameterMap().put("ticket", ticket.getId());
externalContext.getMockRequestParameterMap().put("pgtUrl", "https://proxy.example.com/");
- testProxyAuthenticator.setFailureFlag(false);
+ testProxyValidator.setFailureFlag(false);
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -129,7 +129,7 @@ public class ProxyValidateFlowTest extends AbstractFlowTest {
externalContext.getMockRequestParameterMap().put("ticket", ticket.getId());
externalContext.getMockRequestParameterMap().put("pgtUrl", "https://proxy.example.com/");
- testProxyAuthenticator.setFailureFlag(true);
+ testProxyValidator.setFailureFlag(true);
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ServiceValidateFlowTest.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ServiceValidateFlowTest.java
index ad31bc7..54ec48c 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ServiceValidateFlowTest.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/ServiceValidateFlowTest.java
@@ -76,7 +76,7 @@ public class ServiceValidateFlowTest extends AbstractFlowTest {
private SessionResolver sessionResolver;
@Autowired
- private TestProxyAuthenticator testProxyAuthenticator;
+ private TestProxyValidator testProxyValidator;
@Test
public void testInvalidRequestNoTicket() throws Exception {
@@ -202,7 +202,7 @@ public class ServiceValidateFlowTest extends AbstractFlowTest {
externalContext.getMockRequestParameterMap().put("ticket", ticket.getId());
externalContext.getMockRequestParameterMap().put("pgtUrl", "https://proxy.example.com/");
- testProxyAuthenticator.setFailureFlag(false);
+ testProxyValidator.setFailureFlag(false);
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -232,7 +232,7 @@ public class ServiceValidateFlowTest extends AbstractFlowTest {
externalContext.getMockRequestParameterMap().put("pgtUrl", "https://proxy.example.com/");
overrideEndStateOutput(FLOW_ID, "ValidateSuccess");
- testProxyAuthenticator.setFailureFlag(true);
+ testProxyValidator.setFailureFlag(true);
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyAuthenticator.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyValidator.java
similarity index 78%
rename from idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyAuthenticator.java
rename to idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyValidator.java
index 9d12590..e28f169 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyAuthenticator.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/TestProxyValidator.java
@@ -17,18 +17,19 @@
package net.shibboleth.idp.test.flows.cas;
-import net.shibboleth.idp.cas.proxy.ProxyAuthenticator;
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.security.x509.X509Credential;
+import net.shibboleth.idp.cas.proxy.ProxyValidator;
+import org.opensaml.profile.context.ProfileRequestContext;
import javax.annotation.Nonnull;
import java.net.URI;
import java.security.GeneralSecurityException;
/**
+ * Test proxy validator component.
+ *
* @author Marvin S. Addison
*/
-public class TestProxyAuthenticator implements ProxyAuthenticator<TrustEngine<X509Credential>> {
+public class TestProxyValidator implements ProxyValidator {
/** Whether to fail or not. */
private boolean failureFlag;
@@ -38,7 +39,8 @@ public class TestProxyAuthenticator implements ProxyAuthenticator<TrustEngine<X5
}
@Override
- public void authenticate(@Nonnull URI uri, TrustEngine<X509Credential> criteria) throws GeneralSecurityException {
+ public void validate(@Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final URI uri)
+ throws GeneralSecurityException {
if (failureFlag) {
throw new GeneralSecurityException("Proxy callback authentication failed (failureFlag==true)");
}
diff --git a/idp-conf/src/test/resources/test/test-cas-beans.xml b/idp-conf/src/test/resources/test/test-cas-beans.xml
index d5d4a52..5f0e401 100644
--- a/idp-conf/src/test/resources/test/test-cas-beans.xml
+++ b/idp-conf/src/test/resources/test/test-cas-beans.xml
@@ -52,8 +52,8 @@
</property>
</bean>
- <bean id="shibboleth.CASProxyAuthenticator"
- class="net.shibboleth.idp.test.flows.cas.TestProxyAuthenticator" />
+ <bean id="proxyValidator"
+ class="net.shibboleth.idp.test.flows.cas.TestProxyValidator" />
<bean id="shibboleth.CASProxyValidateIdPSessionPredicate"
class="net.shibboleth.idp.test.flows.cas.ToggleablePredicate" />
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list