This is an automated email from the ASF dual-hosted git repository. billblough pushed a commit to branch RAMPART-234 in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git
commit 82605dd9646ad089ac7e5ce7cf866c52586d5f37 Author: Andreas Veithen <veit...@apache.org> AuthorDate: Sun Jan 29 13:34:11 2017 +0000 RAMPART-234: Commit patch provided by Stefan Vladov. --- .../java/org/apache/rampart/RampartConstants.java | 6 ++ .../java/org/apache/rampart/util/RampartUtil.java | 105 ++++++++++++++++----- .../resources/org/apache/rampart/errors.properties | 2 + 3 files changed, 92 insertions(+), 21 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 e280d74..3b980d3 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 @@ -10,4 +10,10 @@ public class RampartConstants { public static final String XML_ENCRYPTION_MODIFIER_CONTENT = "Content"; public static final String XML_ENCRYPTION_MODIFIER_ELEMENT = "Element"; + + /** + * 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"; } 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 6035981..50b96eb 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.transport.TransportListener; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.logging.Log; @@ -1801,31 +1804,91 @@ public class RampartUtil { return wssConfig; } + - 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"); + + // 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) { + HttpServletRequest request = (HttpServletRequest)requestProperty; + 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 034b91d..d21571f 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 @@ -106,6 +106,8 @@ invalidNonceLifeTime = Invalid value for nonceLifeTime in rampart configuration invalidIssuerAddress = Invalid value for Issuer invalidSignatureAlgo=Invalid signature algorithm for Asymmetric binding invalidUsernameTokenType = Invalid UsernameToken Type. +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. #Rampart Kerberos-specific errors invalidServicePrincipalNameForm = Invalid servicePrincipalNameForm found in Rampart configuration ({0}). The supported service principal name forms are: \"{1}\", \"{2}\".