You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@axis.apache.org by ro...@apache.org on 2024/11/06 21:00:05 UTC
(axis-axis2-java-rampart) 01/02: RAMPART-234 Allow custom https listeners to populate the client certificate chain in the message context
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git
commit f8dcc7460487a18382320a0a553781e914fafb31
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Wed Nov 6 10:41:26 2024 -1000
RAMPART-234 Allow custom https listeners to populate the client certificate chain in the message context
---
.../java/org/apache/rampart/RampartConstants.java | 5 +
.../java/org/apache/rampart/util/RampartUtil.java | 114 +++++++++++++++++----
.../resources/org/apache/rampart/errors.properties | 5 +-
3 files changed, 102 insertions(+), 22 deletions(-)
diff --git a/modules/rampart-core/src/main/java/org/apache/rampart/RampartConstants.java b/modules/rampart-core/src/main/java/org/apache/rampart/RampartConstants.java
index e280d746..a7741f10 100644
--- a/modules/rampart-core/src/main/java/org/apache/rampart/RampartConstants.java
+++ b/modules/rampart-core/src/main/java/org/apache/rampart/RampartConstants.java
@@ -5,6 +5,11 @@ public class RampartConstants {
public static final String TIME_LOG = "org.apache.rampart.TIME";
public static final String MESSAGE_LOG = "org.apache.rampart.MESSAGE";
public static final String SEC_FAULT = "SECURITY_VALIDATION_FAILURE";
+ /**
+ * The key under which the HTTPS client certificate, determened by the https listener, may
+ * be populated as a property of the message context.
+ */
+ public static final String HTTPS_CLIENT_CERT_KEY = "https.client.cert.key";
public static final String MERLIN_CRYPTO_IMPL = "org.apache.ws.security.components.crypto.Merlin";
public static final String MERLIN_CRYPTO_IMPL_CACHE_KEY = "org.apache.ws.security.crypto.merlin.file";
diff --git a/modules/rampart-core/src/main/java/org/apache/rampart/util/RampartUtil.java b/modules/rampart-core/src/main/java/org/apache/rampart/util/RampartUtil.java
index 2ed59869..c09ca1ab 100644
--- a/modules/rampart-core/src/main/java/org/apache/rampart/util/RampartUtil.java
+++ b/modules/rampart-core/src/main/java/org/apache/rampart/util/RampartUtil.java
@@ -31,11 +31,14 @@ import org.apache.axis2.dataretrieval.DRConstants;
import org.apache.axis2.dataretrieval.client.MexClient;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
+import org.apache.axis2.description.TransportInDescription;
+import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.mex.MexConstants;
import org.apache.axis2.mex.MexException;
import org.apache.axis2.mex.om.Metadata;
import org.apache.axis2.mex.om.MetadataReference;
import org.apache.axis2.mex.om.MetadataSection;
+import org.apache.axis2.kernel.TransportListener;
import org.apache.axis2.kernel.http.HTTPConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -58,7 +61,14 @@ import org.apache.rampart.policy.model.CryptoConfig;
import org.apache.rampart.policy.model.KerberosConfig;
import org.apache.rampart.policy.model.RampartConfig;
import org.apache.ws.secpolicy.SPConstants;
-import org.apache.ws.secpolicy.model.*;
+import org.apache.ws.secpolicy.model.HttpsToken;
+import org.apache.ws.secpolicy.model.IssuedToken;
+import org.apache.ws.secpolicy.model.SecureConversationToken;
+import org.apache.ws.secpolicy.model.SupportingToken;
+import org.apache.ws.secpolicy.model.UsernameToken;
+import org.apache.ws.secpolicy.model.Wss10;
+import org.apache.ws.secpolicy.model.Wss11;
+import org.apache.ws.secpolicy.model.X509Token;
import org.apache.wss4j.dom.message.WSSecBase;
import org.apache.wss4j.common.crypto.CryptoType;
import org.apache.wss4j.common.crypto.Crypto;
@@ -1814,29 +1824,91 @@ public class RampartUtil {
return null;
}
- public static void validateTransport(RampartMessageData rmd) throws RampartException {
-
- RampartPolicyData rpd = rmd.getPolicyData();
-
- if (rpd == null) {
- return;
- }
-
- if (rpd.isTransportBinding() && !rmd.isInitiator()) {
- if (rpd.getTransportToken() instanceof HttpsToken) {
- String incomingTransport = rmd.getMsgContext().getIncomingTransportName();
- if (!incomingTransport.equals(org.apache.axis2.Constants.TRANSPORT_HTTPS)) {
- throw new RampartException("invalidTransport",
- new String[]{incomingTransport});
+ /**
+ * Validate transport binding policy assertions.
+ * In case an HttpsToken is required by the security policy the method will verify that the
+ * HTTPS transport was used indeed. Furthermore if the assertion requires a client certificate
+ * being used, the method will try to obtain the client certificate chain first from the
+ * message context properties directly under the key {@link RampartConstants#HTTPS_CLIENT_CERT_KEY}
+ * and, if the property is not available, will try to get the HttpsServletRequest from the
+ * message context properties (populated there by the AxisServlet if axis2 is running inside a servlet
+ * engine) and retrieve the https client certificate chain from its attributes. The client certificate
+ * chain is expected to be available under the <code>javax.servlet.request.X509Certificate</code>
+ * attribute of the servlet request. No further trust verification is done for the client
+ * certificate - the transport listener should have already verified this.
+ *
+ * @param messageData
+ * @throws RampartException
+ */
+ public static void validateTransport(RampartMessageData messageData) throws RampartException {
+
+ MessageContext msgContext = messageData.getMsgContext();
+ RampartPolicyData policyData = messageData.getPolicyData();
+ AxisConfiguration axisConf = msgContext.getConfigurationContext().getAxisConfiguration();
+
+ if(policyData != null && policyData.isTransportBinding() && !messageData.isInitiator()){
+ if (policyData.getTransportToken() instanceof HttpsToken) {
+ try {
+ TransportInDescription transportIn = msgContext.getTransportIn();
+ if (transportIn == null) {
+ transportIn = msgContext.getOptions().getTransportIn();
+ }
+
+ //maybe the transportIn was not populated by the receiver
+ if (transportIn == null) {
+ transportIn = axisConf.getTransportIn(msgContext.getIncomingTransportName());
+ }
+
+ if (transportIn == null) {
+ throw new RampartException("httpsVerificationFailed");
+ }
+
+ TransportListener receiver = transportIn.getReceiver();
+ String incomingEPR = receiver.getEPRsForService(msgContext.getAxisService().getName(),
+ null)[0].getAddress();
+ if (incomingEPR == null) {
+ incomingEPR = msgContext.getIncomingTransportName();
+ }
+
+ if (!incomingEPR.startsWith(org.apache.axis2.Constants.TRANSPORT_HTTPS)) {
+ if (incomingEPR.indexOf(':') > 0) {
+ incomingEPR = incomingEPR.substring(0, incomingEPR.indexOf(':'));
+ }
+ throw new RampartException("invalidTransport", new String[] { incomingEPR });
+ }
+ } catch (AxisFault af) {
+ String incomingTransport = msgContext.getIncomingTransportName();
+ if (!incomingTransport.equals(org.apache.axis2.Constants.TRANSPORT_HTTPS)) {
+ throw new RampartException("invalidTransport", new String[] { incomingTransport });
+ }
}
- if (((HttpsToken) rpd.getTransportToken()).isRequireClientCertificate()) {
- MessageContext messageContext = rmd.getMsgContext();
- HttpServletRequest request = ((HttpServletRequest) messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST));
- if (request == null || request.getAttribute("javax.servlet.request.X509Certificate") == null) {
- throw new RampartException("clientAuthRequired");
+ MessageContext messageContext = messageData.getMsgContext();
+ HttpServletRequest request = ((HttpServletRequest) messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST));
+
+ // verify client certificate used
+ // try to obtain the client certificate chain directly from the message context
+ // and then from the servlet request
+ HttpsToken token = (HttpsToken)policyData.getTransportToken();
+ if (token.isRequireClientCertificate()) {
+ Object certificateChainProperty = msgContext.getProperty(RampartConstants.HTTPS_CLIENT_CERT_KEY);
+ if (certificateChainProperty instanceof X509Certificate[]) {
+ // HTTPS client certificate chain found
+ return;
+ } else {
+ Object requestProperty = msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
+ if (requestProperty instanceof HttpServletRequest) {
+ Object certificateChain = request.getAttribute("javax.servlet.request.X509Certificate"); //$NON-NLS-1$
+ if (certificateChain instanceof X509Certificate[]) {
+ // HTTPS client certificate chain found
+ return;
+ }
+ }
}
- }
+
+ // HTTPS client certificate chain NOT found
+ throw new RampartException("httpsClientCertValidationFailed");
+ }
}
}
diff --git a/modules/rampart-core/src/main/resources/org/apache/rampart/errors.properties b/modules/rampart-core/src/main/resources/org/apache/rampart/errors.properties
index 034b91d1..fea93359 100644
--- a/modules/rampart-core/src/main/resources/org/apache/rampart/errors.properties
+++ b/modules/rampart-core/src/main/resources/org/apache/rampart/errors.properties
@@ -101,6 +101,9 @@ bodyNotSigned = Soap Body must be signed
unexprectedSignature = Unexpected signature
invalidTransport = Expected transport is "https" but incoming transport found : \"{0}\"
requiredElementsMissing = Required Elements not found in the incoming message : {0}
+httpsVerificationFailed = Unable to verify HTTPS transport usage: incoming transport description is unavailable
+httpsClientCertValidationFailed = Unable to verify HTTPS client certificate usage: client certificate chain is not available.
+requiredElementsMissing = Required Elements not found in the incoming message : {0}
repeatingNonceValue = Nonce value : {0}, already seen before for user name : {1}. Possibly this could be a replay attack.
invalidNonceLifeTime = Invalid value for nonceLifeTime in rampart configuration file.
invalidIssuerAddress = Invalid value for Issuer
@@ -112,4 +115,4 @@ invalidServicePrincipalNameForm = Invalid servicePrincipalNameForm found in Ramp
noKerberosConfigDefined = No kerberosConfig policy assertion defined in rampart config.
errorInBuildingKereberosToken = Error in building kereberos token.
cannotLoadKrbTokenDecoderClass = Cannot load Kerberos token decoder class: {0}
-cannotCreateKrbTokenDecoderInstance = Cannot create instance of Kerberos token decoder : {0}
\ No newline at end of file
+cannotCreateKrbTokenDecoderInstance = Cannot create instance of Kerberos token decoder : {0}