diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml
index 5bcded821d..d840ba4938 100644
--- a/modules/commons/pom.xml
+++ b/modules/commons/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/core/pom.xml b/modules/core/pom.xml
index a088dbbd44..c72e875bca 100644
--- a/modules/core/pom.xml
+++ b/modules/core/pom.xml
@@ -16,7 +16,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/HTTPEndpoint.java b/modules/core/src/main/java/org/apache/synapse/endpoints/HTTPEndpoint.java
index 6ff090c09c..ab5387f98b 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/HTTPEndpoint.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/HTTPEndpoint.java
@@ -140,7 +140,18 @@ private String decodeString(String value) {
}
}
- private void processUrlTemplate(MessageContext synCtx) throws VariableExpansionException {
+ protected void processUrlTemplate(MessageContext synCtx) throws VariableExpansionException {
+
+ String evaluatedUri = resolveUrlTemplate(synCtx);
+ if (evaluatedUri != null) {
+ synCtx.setTo(new EndpointReference(evaluatedUri));
+ if (super.getDefinition() != null) {
+ synCtx.setProperty(EndpointDefinition.DYNAMIC_URL_VALUE, evaluatedUri);
+ }
+ }
+ }
+
+ protected String resolveUrlTemplate(MessageContext synCtx) throws VariableExpansionException {
Map variables = new HashMap();
/*The properties with uri.var.* are only considered for Outbound REST Endpoints*/
@@ -162,10 +173,10 @@ private void processUrlTemplate(MessageContext synCtx) throws VariableExpansionE
if (objProperty != null) {
if (objProperty instanceof String) {
variables.put(propertyKey.toString(),
- decodeString((String) synCtx.getProperty(propertyKey.toString())));
+ decodeString((String) synCtx.getProperty(propertyKey.toString())));
} else {
variables.put(propertyKey.toString(),
- decodeString(String.valueOf(synCtx.getProperty(propertyKey.toString()))));
+ decodeString(String.valueOf(synCtx.getProperty(propertyKey.toString()))));
}
}
}
@@ -224,14 +235,14 @@ private void processUrlTemplate(MessageContext synCtx) throws VariableExpansionE
(propertyKey.toString().startsWith(RESTConstants.REST_URI_VARIABLE_PREFIX)
|| propertyKey.toString().startsWith(RESTConstants.REST_QUERY_PARAM_PREFIX))) {
Object objProperty =
- synCtx.getProperty(propertyKey.toString());
+ synCtx.getProperty(propertyKey.toString());
if (objProperty != null) {
if (objProperty instanceof String) {
variables.put(propertyKey.toString(),
- (String) synCtx.getProperty(propertyKey.toString()));
+ (String) synCtx.getProperty(propertyKey.toString()));
} else {
variables.put(propertyKey.toString(),
- (String) String.valueOf(synCtx.getProperty(propertyKey.toString())));
+ (String) String.valueOf(synCtx.getProperty(propertyKey.toString())));
}
}
}
@@ -282,14 +293,7 @@ private void processUrlTemplate(MessageContext synCtx) throws VariableExpansionE
}
}
}
-
-
- if (evaluatedUri != null) {
- synCtx.setTo(new EndpointReference(evaluatedUri));
- if (super.getDefinition() != null) {
- synCtx.setProperty(EndpointDefinition.DYNAMIC_URL_VALUE, evaluatedUri);
- }
- }
+ return evaluatedUri;
}
/**
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/OAuthConfiguredHTTPEndpoint.java b/modules/core/src/main/java/org/apache/synapse/endpoints/OAuthConfiguredHTTPEndpoint.java
index adac33de58..2e218b2983 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/OAuthConfiguredHTTPEndpoint.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/OAuthConfiguredHTTPEndpoint.java
@@ -18,7 +18,9 @@
package org.apache.synapse.endpoints;
+import com.damnhandy.uri.template.VariableExpansionException;
import org.apache.axis2.AxisFault;
+import org.apache.axis2.addressing.EndpointReference;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.endpoints.auth.AuthHandler;
@@ -46,6 +48,7 @@ public OAuthConfiguredHTTPEndpoint(AuthHandler authHandler) {
public void send(MessageContext synCtx) {
try {
+ setResolvedUrlTemplate(synCtx);
oAuthHandler.setAuthHeader(synCtx);
// If this a blocking call, add 401 as a non error http status code
@@ -77,17 +80,22 @@ public void send(MessageContext synCtx) {
*/
public MessageContext retryCallWithNewToken(MessageContext synCtx) {
// remove the existing token from the cache so that a new token is generated
- oAuthHandler.removeTokenFromCache();
- // set RETRIED_ON_OAUTH_FAILURE property to true
- synCtx.setProperty(AuthConstants.RETRIED_ON_OAUTH_FAILURE, true);
- send(synCtx);
+ try {
+ // set RETRIED_ON_OAUTH_FAILURE property to true
+ synCtx.setProperty(AuthConstants.RETRIED_ON_OAUTH_FAILURE, true);
+ oAuthHandler.removeTokenFromCache(synCtx);
+ send(synCtx);
+ } catch (AuthException e) {
+ handleError(synCtx,
+ "Error removing access token for oauth configured http endpoint " + this.getName(), e);
+ }
return synCtx;
}
@Override
public void destroy() {
- oAuthHandler.removeTokenFromCache();
+ oAuthHandler.removeTokensFromCache();
super.destroy();
}
@@ -109,4 +117,21 @@ private void handleError(MessageContext synCtx, String message, Exception except
log.error(errorMsg);
informFailure(synCtx, SynapseConstants.ENDPOINT_AUTH_FAILURE, errorMsg);
}
+
+ private void setResolvedUrlTemplate(MessageContext messageContext) {
+ String resolvedUrl = resolveUrlTemplate(messageContext);
+ if (resolvedUrl != null) {
+ messageContext.setTo(new EndpointReference(resolvedUrl));
+ if (super.getDefinition() != null) {
+ messageContext.setProperty(EndpointDefinition.DYNAMIC_URL_VALUE, resolvedUrl);
+ }
+ }
+ }
+
+ @Override
+ protected void processUrlTemplate(MessageContext synCtx) throws VariableExpansionException {
+ // Since we set the resolved URL in the OAuthConfiguredHTTPEndpoint.send method
+ // return the processUrlTemplate to skip re-resolving at HTTPEndpoint.
+ return;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/AuthorizationCodeHandler.java b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/AuthorizationCodeHandler.java
index 7d6c4a5800..dc3432e41a 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/AuthorizationCodeHandler.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/AuthorizationCodeHandler.java
@@ -26,6 +26,8 @@
import org.apache.synapse.endpoints.auth.AuthConstants;
import org.apache.synapse.endpoints.auth.AuthException;
+import java.util.Objects;
+
/**
* This class is used to handle Authorization code grant oauth.
*/
@@ -74,6 +76,15 @@ protected OMElement serializeSpecificOAuthConfigs(OMFactory omFactory) {
return authCode;
}
+ @Override
+ protected int getHash(MessageContext messageContext) throws AuthException {
+ return Objects.hash(messageContext.getTo().getAddress(), OAuthUtils.resolveExpression(getTokenUrl(), messageContext),
+ OAuthUtils.resolveExpression(getClientId(), messageContext), OAuthUtils.resolveExpression(getClientSecret(),
+ messageContext), OAuthUtils.resolveExpression(getRefreshToken(), messageContext),
+ getRequestParametersAsString(messageContext), getResolvedCustomHeadersMap(getCustomHeadersMap(),
+ messageContext));
+ }
+
/**
* Return the refresh token secret relevant to the Authorization Code Handler.
*
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/ClientCredentialsHandler.java b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/ClientCredentialsHandler.java
index 2a1d21831e..df95cf1e81 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/ClientCredentialsHandler.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/ClientCredentialsHandler.java
@@ -26,6 +26,8 @@
import org.apache.synapse.endpoints.auth.AuthConstants;
import org.apache.synapse.endpoints.auth.AuthException;
+import java.util.Objects;
+
/**
* This class is used to handle Client Credentials grant oauth.
*/
@@ -60,4 +62,12 @@ protected OMElement serializeSpecificOAuthConfigs(OMFactory omFactory) {
return omFactory.createOMElement(AuthConstants.CLIENT_CREDENTIALS, SynapseConstants.SYNAPSE_OMNAMESPACE);
}
+
+ @Override
+ protected int getHash(MessageContext messageContext) throws AuthException {
+ return Objects.hash(messageContext.getTo().getAddress(), OAuthUtils.resolveExpression(getTokenUrl(), messageContext),
+ OAuthUtils.resolveExpression(getClientId(), messageContext), OAuthUtils.resolveExpression(getClientSecret(),
+ messageContext), getRequestParametersAsString(messageContext),
+ getResolvedCustomHeadersMap(getCustomHeadersMap(), messageContext));
+ }
}
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/OAuthHandler.java b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/OAuthHandler.java
index 83ddf7ca21..b9d8f957da 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/OAuthHandler.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/OAuthHandler.java
@@ -46,7 +46,6 @@
public abstract class OAuthHandler implements AuthHandler {
private final String id;
-
private final String tokenApiUrl;
private final String clientId;
private final String clientSecret;
@@ -89,7 +88,7 @@ public void setAuthHeader(MessageContext messageContext) throws AuthException {
private String getToken(final MessageContext messageContext) throws AuthException {
try {
- return TokenCache.getInstance().getToken(id, new Callable() {
+ return TokenCache.getInstance().getToken(getId(messageContext), new Callable() {
@Override
public String call() throws AuthException, IOException {
return OAuthClient.generateToken(OAuthUtils.resolveExpression(tokenApiUrl, messageContext),
@@ -129,12 +128,20 @@ public int compare(String o1, String o2) {
}
}
+ /**
+ * Method to remove the token from the cache when the token is invalid.
+ */
+ public void removeTokenFromCache(MessageContext messageContext) throws AuthException {
+
+ TokenCache.getInstance().removeToken(getId(messageContext));
+ }
+
/**
* Method to remove the token from the cache when the endpoint is destroyed.
*/
- public void removeTokenFromCache() {
+ public void removeTokensFromCache() {
- TokenCache.getInstance().removeToken(id);
+ TokenCache.getInstance().removeTokens(id.concat("_"));
}
/**
@@ -313,7 +320,7 @@ public void setCustomHeaders(Map customHeadersMap) {
* @param messageContext Message Context of the request which will be used to resolve dynamic expressions
* @return Map Resolved custom headers
*/
- private Map getResolvedCustomHeadersMap(Map customHeadersMap,
+ protected Map getResolvedCustomHeadersMap(Map customHeadersMap,
MessageContext messageContext) throws AuthException {
Map resolvedCustomHeadersMap = null;
@@ -339,4 +346,9 @@ public int getSocketTimeout() {
return socketTimeout;
}
+ protected abstract int getHash(MessageContext messageContext) throws AuthException;
+
+ private String getId(MessageContext messageContext) throws AuthException {
+ return id.concat("_").concat(String.valueOf(getHash(messageContext)));
+ }
}
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/PasswordCredentialsHandler.java b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/PasswordCredentialsHandler.java
index 928fce7d5c..07f48e2916 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/PasswordCredentialsHandler.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/PasswordCredentialsHandler.java
@@ -26,6 +26,8 @@
import org.apache.synapse.endpoints.auth.AuthConstants;
import org.apache.synapse.endpoints.auth.AuthException;
+import java.util.Objects;
+
/**
* This class is used to handle Password Credentials grant oauth.
*/
@@ -78,6 +80,16 @@ protected OMElement serializeSpecificOAuthConfigs(OMFactory omFactory) {
return passwordCredentials;
}
+ @Override
+ protected int getHash(MessageContext messageContext) throws AuthException {
+ return Objects.hash(messageContext.getTo().getAddress(), OAuthUtils.resolveExpression(getTokenUrl(), messageContext),
+ OAuthUtils.resolveExpression(getClientId(), messageContext), OAuthUtils.resolveExpression(getClientSecret(),
+ messageContext), OAuthUtils.resolveExpression(getUsername(), messageContext),
+ OAuthUtils.resolveExpression(getPassword(), messageContext),
+ getRequestParametersAsString(messageContext), getResolvedCustomHeadersMap(getCustomHeadersMap(),
+ messageContext));
+ }
+
public String getUsername() {
return username;
diff --git a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/TokenCache.java b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/TokenCache.java
index 61fc973d60..6537c11db3 100644
--- a/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/TokenCache.java
+++ b/modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/TokenCache.java
@@ -82,7 +82,7 @@ public String getToken(String id, Callable callable) throws ExecutionExc
}
/**
- * This method is called to remove the token from the cache when the endpoint is destroyed
+ * This method is called to remove the token from the cache when the token is invalid
*
* @param id id of the endpoint
*/
@@ -91,4 +91,12 @@ public void removeToken(String id) {
tokenMap.invalidate(id);
}
+ /**
+ * This method is called to remove the tokens from the cache when the endpoint is destroyed
+ *
+ * @param oauthHandlerId id of the OAuth handler bounded to the endpoint
+ */
+ public void removeTokens(String oauthHandlerId) {
+ tokenMap.asMap().entrySet().removeIf(entry -> entry.getKey().startsWith(oauthHandlerId));
+ }
}
diff --git a/modules/core/src/main/java/org/apache/synapse/util/InlineExpressionUtil.java b/modules/core/src/main/java/org/apache/synapse/util/InlineExpressionUtil.java
index 78157194b8..e340cc87e3 100644
--- a/modules/core/src/main/java/org/apache/synapse/util/InlineExpressionUtil.java
+++ b/modules/core/src/main/java/org/apache/synapse/util/InlineExpressionUtil.java
@@ -92,6 +92,14 @@ private static String replaceValue(MessageContext messageContext, String text, b
Matcher matcher = EXPRESSION_PATTERN.matcher(text);
while (matcher.find()) {
String matchSeq = matcher.group();
+ String surroundedString;
+ try {
+ surroundedString = text.substring(text.indexOf(matchSeq) - 1, text.indexOf(matchSeq) + matchSeq
+ .length() + 1);
+ } catch (IndexOutOfBoundsException e) {
+ // catch index out of bound exception when the expression is at the beginning or end of the text
+ surroundedString = StringUtils.EMPTY;
+ }
String value = getDynamicValue(messageContext, matchSeq.substring(1, matchSeq.length() - 1));
if (value == null) {
value = StringUtils.EMPTY;
@@ -99,7 +107,7 @@ private static String replaceValue(MessageContext messageContext, String text, b
// If the string is neither XML or JSON, it is considered a String and must be wrapped in double quotes
// If it is an empty string returned from a json-eval expression it must be wrapped in double quotes
if (isInline && ((value.isEmpty() && matchSeq.contains(EXPRESSION_JSON_EVAL))
- || (!isValidXML(value) && !isValidJson(value)))) {
+ || (!isValidXML(value) && !isValidJson(value) && !isSurroundedByQuotes(surroundedString)))) {
value = "\"" + value + "\"";
}
text = text.replace(matchSeq, value);
@@ -107,6 +115,10 @@ private static String replaceValue(MessageContext messageContext, String text, b
return text;
}
+ private static boolean isSurroundedByQuotes(String text) {
+
+ return text.startsWith("\"") && text.endsWith("\"");
+ }
/**
* Replaces Dynamic Values represented by expressions inside json-eval.
*
diff --git a/modules/coverage-report/pom.xml b/modules/coverage-report/pom.xml
index 7fdde64b1b..0dadd42316 100644
--- a/modules/coverage-report/pom.xml
+++ b/modules/coverage-report/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/distribution/pom.xml b/modules/distribution/pom.xml
index c9e3421161..259f97bb83 100644
--- a/modules/distribution/pom.xml
+++ b/modules/distribution/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/experimental/pom.xml b/modules/experimental/pom.xml
index b6721038bd..8218aed984 100644
--- a/modules/experimental/pom.xml
+++ b/modules/experimental/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/extensions/pom.xml b/modules/extensions/pom.xml
index 0cb332769e..8caf399983 100644
--- a/modules/extensions/pom.xml
+++ b/modules/extensions/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/features/org.apache.synapse.samples.feature/pom.xml b/modules/features/org.apache.synapse.samples.feature/pom.xml
index 2303377d32..7e95924648 100644
--- a/modules/features/org.apache.synapse.samples.feature/pom.xml
+++ b/modules/features/org.apache.synapse.samples.feature/pom.xml
@@ -19,7 +19,7 @@
synapse-features
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
org.apache.synapse
diff --git a/modules/features/org.apache.synapse.transport.fix.feature/pom.xml b/modules/features/org.apache.synapse.transport.fix.feature/pom.xml
index e3a7a78c76..ecb4e10197 100644
--- a/modules/features/org.apache.synapse.transport.fix.feature/pom.xml
+++ b/modules/features/org.apache.synapse.transport.fix.feature/pom.xml
@@ -19,7 +19,7 @@
synapse-features
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
org.apache.synapse
diff --git a/modules/features/org.apache.synapse.transport.nhttp.feature/pom.xml b/modules/features/org.apache.synapse.transport.nhttp.feature/pom.xml
index a444d02d4d..308127b2e3 100644
--- a/modules/features/org.apache.synapse.transport.nhttp.feature/pom.xml
+++ b/modules/features/org.apache.synapse.transport.nhttp.feature/pom.xml
@@ -19,7 +19,7 @@
synapse-features
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
org.apache.synapse
diff --git a/modules/features/org.apache.synapse.transport.vfs.feature/pom.xml b/modules/features/org.apache.synapse.transport.vfs.feature/pom.xml
index 89a448d423..3cc18abeb9 100644
--- a/modules/features/org.apache.synapse.transport.vfs.feature/pom.xml
+++ b/modules/features/org.apache.synapse.transport.vfs.feature/pom.xml
@@ -19,7 +19,7 @@
synapse-features
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
org.apache.synapse
diff --git a/modules/features/org.apache.synapse.transport.vfs.smb.feature/pom.xml b/modules/features/org.apache.synapse.transport.vfs.smb.feature/pom.xml
index 59a21db186..cdf4b9e60c 100644
--- a/modules/features/org.apache.synapse.transport.vfs.smb.feature/pom.xml
+++ b/modules/features/org.apache.synapse.transport.vfs.smb.feature/pom.xml
@@ -19,7 +19,7 @@
synapse-features
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
org.apache.synapse
diff --git a/modules/features/org.apache.synapse.transport.vfs.smb2.feature/pom.xml b/modules/features/org.apache.synapse.transport.vfs.smb2.feature/pom.xml
index 27bd89acd5..0dca2ed56c 100644
--- a/modules/features/org.apache.synapse.transport.vfs.smb2.feature/pom.xml
+++ b/modules/features/org.apache.synapse.transport.vfs.smb2.feature/pom.xml
@@ -20,7 +20,7 @@
synapse-features
org.apache.synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
4.0.0
diff --git a/modules/features/org.apache.synapse.wso2.feature/pom.xml b/modules/features/org.apache.synapse.wso2.feature/pom.xml
index 0f4d06d7fa..a2e80eda68 100644
--- a/modules/features/org.apache.synapse.wso2.feature/pom.xml
+++ b/modules/features/org.apache.synapse.wso2.feature/pom.xml
@@ -20,7 +20,7 @@
synapse-features
org.apache.synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
4.0.0
diff --git a/modules/features/pom.xml b/modules/features/pom.xml
index 7acc6b5faf..57bc3a74ee 100644
--- a/modules/features/pom.xml
+++ b/modules/features/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/handler/pom.xml b/modules/handler/pom.xml
index be1ff98b84..1ffe1d6512 100644
--- a/modules/handler/pom.xml
+++ b/modules/handler/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/pom.xml b/modules/integration/pom.xml
index 951b61bf6f..461d91801e 100644
--- a/modules/integration/pom.xml
+++ b/modules/integration/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/src/test/java/org/apache/synapse/samples/framework/tests/endpoint/Sample63.java b/modules/integration/src/test/java/org/apache/synapse/samples/framework/tests/endpoint/Sample63.java
index caede6b321..5ef71a4029 100644
--- a/modules/integration/src/test/java/org/apache/synapse/samples/framework/tests/endpoint/Sample63.java
+++ b/modules/integration/src/test/java/org/apache/synapse/samples/framework/tests/endpoint/Sample63.java
@@ -100,4 +100,27 @@ public void testOAuthConfiguredEPWithDynamicValues() throws Exception {
HttpResponse response = client.doGet("http://127.0.0.1:8280/foodapi/list/dynamicValues");
assertEquals(HttpStatus.SC_OK, response.getStatus());
}
+
+ public void testOAuthConfiguredDynamicURLEP() throws Exception {
+
+ String payload1 = "\n" +
+ "\thttp://localhost:9000/foodservice/food\n" +
+ "\thttp://localhost:9000/foodservice/token1\n" +
+ "";
+
+ String payload2 = "\n" +
+ "\thttp://localhost:9000/foodservice/apple\n" +
+ "\thttp://localhost:9000/foodservice/token2\n" +
+ "";
+
+ BasicHttpClient client = new BasicHttpClient();
+ HttpResponse response = client.doPost("http://127.0.0.1:8280/foodapi/list/dynamicURL", payload1.getBytes(),
+ "text/xml");
+ assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+ HttpResponse response2 = client.doPost("http://127.0.0.1:8280/foodapi/list/dynamicURL", payload2.getBytes(),
+ "text/xml");
+ assertEquals(HttpStatus.SC_OK, response2.getStatus());
+ assertEquals("1", response2.getBodyAsString());
+ }
}
diff --git a/modules/migrator/pom.xml b/modules/migrator/pom.xml
index 24f4d3b21c..46bda83af9 100644
--- a/modules/migrator/pom.xml
+++ b/modules/migrator/pom.xml
@@ -24,7 +24,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/packaging/package-archetype/pom.xml b/modules/packaging/package-archetype/pom.xml
index 6da7f95f06..8be2118e74 100644
--- a/modules/packaging/package-archetype/pom.xml
+++ b/modules/packaging/package-archetype/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../../pom.xml
synapse-package-archetype
diff --git a/modules/packaging/package-skeleton/pom.xml b/modules/packaging/package-skeleton/pom.xml
index 5030966654..15a17be3af 100644
--- a/modules/packaging/package-skeleton/pom.xml
+++ b/modules/packaging/package-skeleton/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../../pom.xml
synapse-package-skeleton
diff --git a/modules/patches/pom.xml b/modules/patches/pom.xml
index f6631be765..a6ebd0ace3 100644
--- a/modules/patches/pom.xml
+++ b/modules/patches/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
synapse-patches
diff --git a/modules/samples/pom.xml b/modules/samples/pom.xml
index 2af5c2a0db..68d614a5f7 100644
--- a/modules/samples/pom.xml
+++ b/modules/samples/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/Constants.java b/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/Constants.java
index cf2b5d7920..ca30a72085 100644
--- a/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/Constants.java
+++ b/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/Constants.java
@@ -22,6 +22,7 @@ public class Constants {
static final String refreshToken = "wxyz#9876";
static final String accessToken = "abcd@1234";
+ static final String accessToken2 = "jklm#6789";
static final String expiresIn = "3600";
static final String tokenType = "Bearer";
static final String clientId = "my_client_id";
diff --git a/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/FoodService.java b/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/FoodService.java
index 6a2826e6e6..e95167e85b 100644
--- a/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/FoodService.java
+++ b/modules/samples/src/main/java/org/wso2/synapse/samples/jaxrs/foodsample/FoodService.java
@@ -38,6 +38,7 @@ public class FoodService {
private int unauthorizedReqCount = 0;
private int tokenReqCount = 0;
+ private int appleServiceRequests = 0;
@POST
@Path("/token")
@@ -57,6 +58,38 @@ public Response getAccessToken(@Context HttpHeaders httpHeaders,
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Credentials").build();
}
+ @POST
+ @Path("/token1")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getAccessToken1(@Context HttpHeaders httpHeaders,
+ MultivaluedMap tokenRequestParams) {
+
+ String basicHeader = httpHeaders.getHeaderString("Authorization");
+
+ if (validateBasicAuthHeader(basicHeader)) {
+ return Response.status(Response.Status.OK).entity(new Token(Constants.accessToken, Constants.expiresIn,
+ Constants.tokenType)).build();
+ }
+ return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Credentials").build();
+ }
+
+ @POST
+ @Path("/token2")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getAccessToken2(@Context HttpHeaders httpHeaders,
+ MultivaluedMap tokenRequestParams) {
+
+ String basicHeader = httpHeaders.getHeaderString("Authorization");
+
+ if (validateBasicAuthHeader(basicHeader)) {
+ return Response.status(Response.Status.OK).entity(new Token(Constants.accessToken2, Constants.expiresIn,
+ Constants.tokenType)).build();
+ }
+ return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Credentials").build();
+ }
+
@POST
@Path("/custom-token")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@@ -105,6 +138,22 @@ public Response getFoodItem(@Context HttpHeaders httpHeaders) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
+ @GET
+ @Path("/apple")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getFoodItem2(@Context HttpHeaders httpHeaders) {
+
+ appleServiceRequests++;
+ String authorizationHeader = httpHeaders.getHeaderString("Authorization");
+ if (authorizationHeader != null) {
+ String token = authorizationHeader.split(" ")[1];
+ if (token.equals(Constants.accessToken2)) {
+ return Response.status(Response.Status.OK).entity(appleServiceRequests).build();
+ }
+ }
+ return Response.status(Response.Status.UNAUTHORIZED).build();
+ }
+
@GET
@Path("/unauthorized")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/modules/securevault/pom.xml b/modules/securevault/pom.xml
index 6c5af61d53..8d13eda926 100644
--- a/modules/securevault/pom.xml
+++ b/modules/securevault/pom.xml
@@ -24,7 +24,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
org.apache.synapse
diff --git a/modules/tasks/pom.xml b/modules/tasks/pom.xml
index 6c51e3189c..107475619f 100644
--- a/modules/tasks/pom.xml
+++ b/modules/tasks/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/transports/core/nhttp/pom.xml b/modules/transports/core/nhttp/pom.xml
index ffd57040d6..71a011389f 100644
--- a/modules/transports/core/nhttp/pom.xml
+++ b/modules/transports/core/nhttp/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
synapse-transports
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java
new file mode 100644
index 0000000000..2765ac41a1
--- /dev/null
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.synapse.transport.certificatevalidation;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.synapse.transport.certificatevalidation.cache.CertCache;
+import org.apache.synapse.transport.certificatevalidation.crl.CRLCache;
+import org.apache.synapse.transport.certificatevalidation.crl.CRLVerifier;
+import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPCache;
+import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPVerifier;
+import org.apache.synapse.transport.certificatevalidation.pathvalidation.CertificatePathValidator;
+import org.apache.synapse.transport.nhttp.config.TrustStoreHolder;
+
+import java.io.ByteArrayInputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Optional;
+
+/**
+ * Manager class responsible for verifying certificates. This class will use the available verifiers according to
+ * a predefined policy.
+ */
+public class CertificateVerificationManager {
+
+ private int cacheSize = Constants.CACHE_DEFAULT_ALLOCATED_SIZE;
+ private int cacheDelayMins = Constants.CACHE_DEFAULT_DELAY_MINS;
+ private boolean isFullCertChainValidationEnabled = true;
+ private boolean isCertExpiryValidationEnabled = false;
+ private static final Log log = LogFactory.getLog(CertificateVerificationManager.class);
+
+ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) {
+
+ if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE
+ && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) {
+ this.cacheSize = cacheAllocatedSize;
+ } else {
+ log.warn("The cache size is out of range. Hence, using the default cache size value of "
+ + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + ".");
+ }
+ if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS
+ && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) {
+ this.cacheDelayMins = cacheDelayMins;
+ } else {
+ log.warn("The cache delay is out of range. Hence, using the default cache delay value of "
+ + Constants.CACHE_DEFAULT_DELAY_MINS + ".");
+ }
+ }
+
+ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins,
+ boolean isFullCertChainValidationEnabled,
+ boolean isCertExpiryValidationEnabled) {
+
+ if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE
+ && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) {
+ this.cacheSize = cacheAllocatedSize;
+ } else {
+ log.warn("The cache size is out of range. Hence, using the default cache size value of "
+ + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + ".");
+ }
+ if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS
+ && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) {
+ this.cacheDelayMins = cacheDelayMins;
+ } else {
+ log.warn("The cache delay is out of range. Hence, using the default cache delay value of "
+ + Constants.CACHE_DEFAULT_DELAY_MINS + ".");
+ }
+
+ this.isFullCertChainValidationEnabled = isFullCertChainValidationEnabled;
+ this.isCertExpiryValidationEnabled = isCertExpiryValidationEnabled;
+ }
+
+ /**
+ * This method verifies the given certificate chain or given peer certificate for revocation based on the
+ * requirement of full certificate chain validation. If full chain validation is enabled (default),
+ * the full certificate chain will be validated before checking the chain for revocation. If full chain validation
+ * is disabled, this method expects a single peer certificate, and it is validated with the immediate issuer
+ * certificate in the truststore (The truststore must contain the immediate issuer of the peer certificate).
+ * In both cases, OCSP and CRL verifiers are used for revocation verification.
+ * It first tries to verify using OCSP since OCSP verification is faster. If that fails it tries to do the
+ * verification using CRL.
+ *
+ * @param peerCertificates javax.security.cert.X509Certificate[] array of peer certificate chain from peer/client.
+ * @throws CertificateVerificationException
+ */
+ public void verifyCertificateValidity(javax.security.cert.X509Certificate[] peerCertificates)
+ throws CertificateVerificationException {
+
+ X509Certificate[] convertedCertificates = convert(peerCertificates);
+
+ Optional peerCertOpt;
+ X509Certificate peerCert = null;
+ X509Certificate issuerCert = null;
+ String alias;
+
+ if (!isFullCertChainValidationEnabled) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Retrieving the issuer certificate from client truststore since full certificate chain " +
+ "validation is disabled");
+ }
+
+ KeyStore trustStore = TrustStoreHolder.getInstance().getClientTrustStore();
+ Enumeration aliases;
+
+ // When full chain validation is disabled, only one cert is expected
+ peerCertOpt = Arrays.stream(convertedCertificates).findFirst();
+ if (peerCertOpt.isPresent()) {
+ peerCert = peerCertOpt.get();
+ } else {
+ throw new CertificateVerificationException("Peer certificate is not provided");
+ }
+
+ // Get cert cache and initialize it
+ CertCache certCache = CertCache.getCache();
+
+ if (certCache.getCacheValue(peerCert.getSerialNumber().toString()) == null) {
+
+ try {
+ aliases = trustStore.aliases();
+ } catch (KeyStoreException e) {
+ throw new CertificateVerificationException("Error while retrieving aliases from truststore", e);
+ }
+
+ while (aliases.hasMoreElements()) {
+
+ alias = aliases.nextElement();
+ try {
+ issuerCert = (X509Certificate) trustStore.getCertificate(alias);
+ } catch (KeyStoreException e) {
+ throw new CertificateVerificationException("Unable to read the certificate from " +
+ "truststore with the alias: " + alias, e);
+ }
+
+ if (issuerCert == null) {
+ throw new CertificateVerificationException("Issuer certificate not found in truststore");
+ }
+
+ try {
+ peerCert.verify(issuerCert.getPublicKey());
+
+ log.debug("Valid issuer certificate found in the client truststore. Caching..");
+
+ // Store the valid issuer cert in cache for future use
+ certCache.setCacheValue(peerCert.getSerialNumber().toString(), issuerCert);
+ if (log.isDebugEnabled()) {
+ log.debug("Issuer certificate with serial number: " + issuerCert.getSerialNumber()
+ .toString() + " has been cached against the serial number: " + peerCert
+ .getSerialNumber().toString() + " of the peer certificate.");
+ }
+ break;
+ } catch (SignatureException | CertificateException | NoSuchAlgorithmException |
+ InvalidKeyException | NoSuchProviderException e) {
+ // Unable to verify the signature. Check with the next certificate in the next loop traversal.
+ }
+ }
+ } else {
+ X509Certificate cachedIssuerCert = certCache.getCacheValue(peerCert.getSerialNumber().toString());
+ try {
+ peerCert.verify(cachedIssuerCert.getPublicKey());
+ } catch (SignatureException | CertificateException | NoSuchAlgorithmException |
+ InvalidKeyException |
+ NoSuchProviderException e) {
+ // Unable to verify the signature.
+ throw new CertificateVerificationException("Unable to verify the signature of the certificate.");
+ }
+ }
+ }
+
+ OCSPCache ocspCache = OCSPCache.getCache(cacheSize, cacheDelayMins);
+ CRLCache crlCache = CRLCache.getCache(cacheSize, cacheDelayMins);
+
+ RevocationVerifier[] verifiers = {new OCSPVerifier(ocspCache), new CRLVerifier(crlCache)};
+
+ for (RevocationVerifier verifier : verifiers) {
+ try {
+ if (isFullCertChainValidationEnabled) {
+
+ if (isCertExpiryValidationEnabled) {
+ log.debug("Validating certificate chain for expiry");
+ if (isExpired(convertedCertificates)) {
+ throw new CertificateVerificationException("One of the provided certificates are expired");
+ }
+ }
+
+ log.debug("Doing full certificate chain validation");
+ CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates,
+ verifier);
+ pathValidator.validatePath();
+ } else {
+
+ if (isCertExpiryValidationEnabled) {
+ log.debug("Validating the client certificate for expiry");
+ if (isExpired(convertedCertificates)) {
+ throw new CertificateVerificationException("The provided certificate is expired");
+ }
+ }
+
+ log.debug("Validating client certificate with the issuer certificate retrieved from" +
+ "the trust store");
+ verifier.checkRevocationStatus(peerCert, issuerCert);
+ }
+ return;
+ } catch (Exception e) {
+ log.debug("Certificate verification with " + verifier.getClass().getSimpleName() + " failed. ", e);
+ }
+ }
+ throw new CertificateVerificationException("Path Verification Failed for both OCSP and CRL");
+ }
+
+ /**
+ * @param certs array of javax.security.cert.X509Certificate[] s.
+ * @return the converted array of java.security.cert.X509Certificate[] s.
+ * @throws CertificateVerificationException
+ */
+ private X509Certificate[] convert(javax.security.cert.X509Certificate[] certs)
+ throws CertificateVerificationException {
+ X509Certificate[] certChain = new X509Certificate[certs.length];
+ Throwable exceptionThrown;
+ for (int i = 0; i < certs.length; i++) {
+ try {
+ byte[] encoded = certs[i].getEncoded();
+ ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
+ java.security.cert.CertificateFactory cf
+ = java.security.cert.CertificateFactory.getInstance("X.509");
+ certChain[i]=((X509Certificate)cf.generateCertificate(bis));
+ continue;
+ } catch (java.security.cert.CertificateEncodingException e) {
+ exceptionThrown = e;
+ } catch (javax.security.cert.CertificateEncodingException e) {
+ exceptionThrown = e;
+ } catch (java.security.cert.CertificateException e) {
+ exceptionThrown = e;
+ }
+ throw new CertificateVerificationException("Cant Convert certificates from javax to java", exceptionThrown);
+ }
+ return certChain;
+ }
+
+ /**
+ * Checks whether a provided certificate is expired or not at the time it is validated.
+ *
+ * @param certificates certificates to be validated for expiry
+ * @return true if one of the certs are expired, false otherwise
+ */
+ public boolean isExpired(X509Certificate[] certificates) {
+
+ for (X509Certificate cert : certificates) {
+ try {
+ cert.checkValidity();
+ } catch (CertificateExpiredException e) {
+ log.error("Peer certificate is expired");
+ return true;
+ } catch (CertificateNotYetValidException e) {
+ log.error("Peer certificate is not valid yet");
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java
deleted file mode 100644
index 338b8a8a36..0000000000
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF 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 org.apache.synapse.transport.certificatevalidation;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.synapse.transport.certificatevalidation.crl.CRLCache;
-import org.apache.synapse.transport.certificatevalidation.crl.CRLVerifier;
-import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPCache;
-import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPVerifier;
-import org.apache.synapse.transport.certificatevalidation.pathvalidation.CertificatePathValidator;
-
-import java.io.ByteArrayInputStream;
-import java.security.cert.X509Certificate;
-
-/**
- * Manager class responsible for verifying certificates. This class will use the available verifiers according to
- * a predefined policy.
- */
-public class RevocationVerificationManager {
-
- private int cacheSize = Constants.CACHE_DEFAULT_ALLOCATED_SIZE;
- private int cacheDelayMins = Constants.CACHE_DEFAULT_DELAY_MINS;
- private static final Log log = LogFactory.getLog(RevocationVerificationManager.class);
-
- public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) {
-
- if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE
- && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) {
- this.cacheSize = cacheAllocatedSize;
- }
- if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS
- && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) {
- this.cacheDelayMins = cacheDelayMins;
- }
- }
-
- /**
- * This method first tries to verify the given certificate chain using OCSP since OCSP verification is
- * faster. If that fails it tries to do the verification using CRL.
- * @param peerCertificates javax.security.cert.X509Certificate[] array of peer certificate chain from peer/client.
- * @throws CertificateVerificationException
- */
- public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCertificates)
- throws CertificateVerificationException {
-
- X509Certificate[] convertedCertificates = convert(peerCertificates);
-
- long start = System.currentTimeMillis();
-
- OCSPCache ocspCache = OCSPCache.getCache();
- ocspCache.init(cacheSize, cacheDelayMins);
- CRLCache crlCache = CRLCache.getCache();
- crlCache.init(cacheSize, cacheDelayMins);
-
- RevocationVerifier[] verifiers = {new OCSPVerifier(ocspCache), new CRLVerifier(crlCache)};
-
- for (RevocationVerifier verifier : verifiers) {
- try {
- CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates, verifier);
- pathValidator.validatePath();
- log.info("Path verification Successful. Took " + (System.currentTimeMillis() - start) + " ms.");
- return;
- } catch (Exception e) {
- log.info(verifier.getClass().getSimpleName() + " failed.");
- log.debug("Certificate verification with " + verifier.getClass().getSimpleName() + " failed. ", e);
- }
- }
- throw new CertificateVerificationException("Path Verification Failed for both OCSP and CRL");
- }
-
- /**
- * @param certs array of javax.security.cert.X509Certificate[] s.
- * @return the converted array of java.security.cert.X509Certificate[] s.
- * @throws CertificateVerificationException
- */
- private X509Certificate[] convert(javax.security.cert.X509Certificate[] certs)
- throws CertificateVerificationException {
- X509Certificate[] certChain = new X509Certificate[certs.length];
- Throwable exceptionThrown;
- for (int i = 0; i < certs.length; i++) {
- try {
- byte[] encoded = certs[i].getEncoded();
- ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
- java.security.cert.CertificateFactory cf
- = java.security.cert.CertificateFactory.getInstance("X.509");
- certChain[i]=((X509Certificate)cf.generateCertificate(bis));
- continue;
- } catch (java.security.cert.CertificateEncodingException e) {
- exceptionThrown = e;
- } catch (javax.security.cert.CertificateEncodingException e) {
- exceptionThrown = e;
- } catch (java.security.cert.CertificateException e) {
- exceptionThrown = e;
- }
- throw new CertificateVerificationException("Cant Convert certificates from javax to java", exceptionThrown);
- }
- return certChain;
- }
-}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java
new file mode 100644
index 0000000000..9ada86e88d
--- /dev/null
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.synapse.transport.certificatevalidation.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.synapse.commons.jmx.MBeanRegistrar;
+import org.apache.synapse.transport.certificatevalidation.Constants;
+
+import java.security.cert.X509Certificate;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This is a cache to store a certificate against a unique string (can be a serial number). This is a singleton since
+ * more than one cache of this kind should not be allowed. This cache can be used by any place where certificate
+ * caching is needed.
+ */
+public class CertCache implements ManageableCache {
+
+ private static volatile CertCache cache;
+ private static volatile Map hashMap = new ConcurrentHashMap();
+ private static volatile Iterator> iterator = hashMap.entrySet().iterator();
+ private static volatile CacheManager cacheManager;
+ private static final Log log = LogFactory.getLog(CertCache.class);
+
+ private CertCache() {
+ }
+
+ public static CertCache getCache() {
+ //Double-checked locking
+ if (cache == null) {
+ synchronized (CertCache.class) {
+ if (cache == null) {
+ cache = new CertCache();
+ cacheManager = new CacheManager(cache, Constants.CACHE_DEFAULT_ALLOCATED_SIZE,
+ Constants.CACHE_DEFAULT_DELAY_MINS);
+ }
+ }
+ }
+ return cache;
+ }
+
+ public synchronized X509Certificate getCacheValue(String serialNumber) {
+ CertCacheValue cacheValue = hashMap.get(serialNumber);
+ if (cacheValue != null) {
+ return cacheValue.getValue();
+ } else
+ return null;
+ }
+
+ @Override
+ public ManageableCacheValue getNextCacheValue() {
+
+ if (iterator.hasNext()) {
+ return hashMap.get(iterator.next().getKey());
+ } else {
+ resetIterator();
+ return null;
+ }
+ }
+
+ @Override
+ public int getCacheSize() {
+
+ return hashMap.size();
+ }
+
+ @Override
+ public void resetIterator() {
+
+ iterator = hashMap.entrySet().iterator();
+ }
+
+ public static void resetCache() {
+
+ hashMap.clear();
+ }
+
+ public synchronized void setCacheValue(String serialNumber, X509Certificate cert) {
+ CertCacheValue cacheValue = new CertCacheValue(serialNumber, cert);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Before set - HashMap size " + hashMap.size());
+ }
+ hashMap.put(serialNumber, cacheValue);
+ if (log.isDebugEnabled()) {
+ log.debug("After set - HashMap size " + hashMap.size());
+ }
+ }
+
+ public synchronized void removeCacheValue(String serialNumber) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Before remove - HashMap size " + hashMap.size());
+ }
+ hashMap.remove(serialNumber);
+ if (log.isDebugEnabled()) {
+ log.debug("After remove - HashMap size " + hashMap.size());
+ }
+ }
+
+ /**
+ * This is the wrapper class of the actual cache value.
+ */
+ private class CertCacheValue implements ManageableCacheValue {
+
+ private final String serialNumber;
+ private final X509Certificate issuerCertificate;
+ private final long timeStamp = System.currentTimeMillis();
+
+ public CertCacheValue(String serialNumber, X509Certificate issuerCertificate) {
+
+ this.serialNumber = serialNumber;
+ this.issuerCertificate = issuerCertificate;
+ }
+
+ public X509Certificate getValue() {
+
+ return issuerCertificate;
+ }
+
+ public String getKey() {
+
+ return serialNumber;
+ }
+
+ public boolean isValid() {
+
+ // Will be always return true since we only set defined data.
+ return true;
+ }
+
+ public long getTimeStamp() {
+
+ return timeStamp;
+ }
+
+ /**
+ * Used by cacheManager to remove invalid entries.
+ */
+ public void removeThisCacheValue() {
+
+ removeCacheValue(serialNumber);
+ }
+
+ public void updateCacheWithNewValue() {
+ // No implementation needed since there are no scenarios of the cache value being invalid.
+ }
+ }
+}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java
index 11db425524..2597960102 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java
@@ -50,12 +50,13 @@ public class CRLCache implements ManageableCache {
private CRLCache() {
}
- public static CRLCache getCache() {
+ public static CRLCache getCache(int cacheSize, int cacheDelayMins) {
//Double checked locking
if (cache == null) {
synchronized (CRLCache.class) {
if (cache == null) {
cache = new CRLCache();
+ cacheManager = new CacheManager(cache, cacheSize, cacheDelayMins);
}
}
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java
index b01d509867..cf904cd3f4 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java
@@ -22,6 +22,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.commons.jmx.MBeanRegistrar;
import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException;
+import org.apache.synapse.transport.certificatevalidation.Constants;
import org.apache.synapse.transport.certificatevalidation.cache.CacheController;
import org.apache.synapse.transport.certificatevalidation.cache.CacheManager;
import org.apache.synapse.transport.certificatevalidation.cache.ManageableCache;
@@ -51,12 +52,14 @@ public class OCSPCache implements ManageableCache {
private OCSPCache() {}
- public static OCSPCache getCache() {
+ public static OCSPCache getCache(int cacheSize, int cacheDelayMins) {
//Double checked locking
if (cache == null) {
synchronized (OCSPCache.class) {
- if (cache == null)
+ if (cache == null) {
cache = new OCSPCache();
+ cacheManager = new CacheManager(cache, cacheSize, cacheDelayMins);
+ }
}
}
return cache;
@@ -116,7 +119,7 @@ private synchronized void replaceNewCacheValue(OCSPCacheValue cacheValue){
try {
String serviceUrl = cacheValue.serviceUrl;
OCSPReq request = cacheValue.request;
- OCSPResp response= ocspVerifier.getOCSPResponce(serviceUrl, request);
+ OCSPResp response= ocspVerifier.getOCSPResponse(serviceUrl, request);
if (OCSPResponseStatus.SUCCESSFUL != response.getStatus())
throw new CertificateVerificationException("OCSP response status not SUCCESSFUL");
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java
index d9a3a11039..5744365730 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java
@@ -20,20 +20,42 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.bouncycastle.asn1.*;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException;
+import org.apache.synapse.transport.certificatevalidation.Constants;
+import org.apache.synapse.transport.certificatevalidation.RevocationStatus;
+import org.apache.synapse.transport.certificatevalidation.RevocationVerifier;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
-import org.bouncycastle.asn1.x509.*;
+import org.bouncycastle.asn1.x509.AccessDescription;
+import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.ocsp.*;
-import org.apache.synapse.transport.certificatevalidation.*;
+import org.bouncycastle.cert.ocsp.BasicOCSPResp;
+import org.bouncycastle.cert.ocsp.CertificateID;
+import org.bouncycastle.cert.ocsp.CertificateStatus;
+import org.bouncycastle.cert.ocsp.OCSPReq;
+import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
+import org.bouncycastle.cert.ocsp.OCSPResp;
+import org.bouncycastle.cert.ocsp.SingleResp;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.math.BigInteger;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.security.Provider;
import java.security.Security;
import java.security.cert.X509Certificate;
@@ -52,6 +74,12 @@ public OCSPVerifier(OCSPCache cache) {
this.cache = cache;
}
+ public static final String CONTENT_TYPE = "Content-Type";
+ public static final String JSON_TYPE ="application/json";
+ public static final String ACCEPT_TYPE = "Accept";
+ public static final String OCSP_REQUEST_TYPE = "application/ocsp-request";
+ public static final String OCSP_RESPONSE_TYPE = "application/ocsp-response";
+
/**
* Gets the revocation status (Good, Revoked or Unknown) of the given peer certificate.
*
@@ -83,7 +111,7 @@ public RevocationStatus checkRevocationStatus(X509Certificate peerCert, X509Cert
SingleResp[] responses;
try {
- OCSPResp ocspResponse = getOCSPResponce(serviceUrl, request);
+ OCSPResp ocspResponse = getOCSPResponse(serviceUrl, request);
if (OCSPResponseStatus.SUCCESSFUL != ocspResponse.getStatus()) {
continue; // Server didn't give the response right.
}
@@ -128,37 +156,34 @@ private RevocationStatus getRevocationStatus(SingleResp resp) throws Certificate
* @throws CertificateVerificationException
*
*/
- protected OCSPResp getOCSPResponce(String serviceUrl, OCSPReq request) throws CertificateVerificationException {
+ protected OCSPResp getOCSPResponse(String serviceUrl, OCSPReq request) throws CertificateVerificationException {
- try {
- //Todo: Use http client.
- byte[] array = request.getEncoded();
- if (serviceUrl.startsWith("http")) {
- HttpURLConnection con;
- URL url = new URL(serviceUrl);
- con = (HttpURLConnection) url.openConnection();
- con.setRequestProperty("Content-Type", "application/ocsp-request");
- con.setRequestProperty("Accept", "application/ocsp-response");
- con.setDoOutput(true);
- OutputStream out = con.getOutputStream();
- DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(out));
- dataOut.write(array);
-
- dataOut.flush();
- dataOut.close();
-
- //Check errors in response:
- if (con.getResponseCode() / 100 != 2) {
- throw new CertificateVerificationException("Error getting ocsp response." +
- "Response code is " + con.getResponseCode());
- }
+ if (log.isDebugEnabled()) {
+ log.debug("Initiating HTTP request to URL: " + serviceUrl + " to get the OCSP response");
+ }
+
+ try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+ HttpPost httpPost = new HttpPost(serviceUrl);
+
+ // adding request timeout configurations
+ if (httpPost.getConfig() == null) {
+ httpPost.setConfig(RequestConfig.custom().build());
+ }
- //Get Response
- InputStream in = (InputStream) con.getContent();
- return new OCSPResp(in);
- } else {
- throw new CertificateVerificationException("Only http is supported for ocsp calls");
+ httpPost.addHeader(CONTENT_TYPE, OCSP_REQUEST_TYPE);
+ httpPost.addHeader(ACCEPT_TYPE, OCSP_RESPONSE_TYPE);
+ httpPost.setEntity(new ByteArrayEntity(request.getEncoded(), ContentType.create(JSON_TYPE)));
+ HttpResponse httpResponse = client.execute(httpPost);
+
+ //Check errors in response, if response status code is not 200 (success) range, throws exception
+ // eg: if response code is 200 (success) or 201 (accepted) return true,
+ // if response code is 404 (not found) or 500 throw exception
+ if (httpResponse.getStatusLine().getStatusCode() / 100 != 2) {
+ throw new CertificateVerificationException("Error getting ocsp response." +
+ "Response code is " + httpResponse.getStatusLine().getStatusCode());
}
+ InputStream in = httpResponse.getEntity().getContent();
+ return new OCSPResp(in);
} catch (IOException e) {
throw new CertificateVerificationException("Cannot get ocspResponse from url: " + serviceUrl, e);
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java
index b041a7314d..b6335f88a4 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java
@@ -22,6 +22,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.transport.certificatevalidation.*;
+import java.lang.reflect.InvocationTargetException;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.List;
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java
index 24977a7115..e5c94d91f6 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java
@@ -33,7 +33,7 @@
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.nio.reactor.ssl.SSLSetupHandler;
import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException;
-import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager;
public class ClientSSLSetupHandler implements SSLSetupHandler {
@@ -139,10 +139,10 @@ public void verify(
};
private final X509HostnameVerifier hostnameVerifier;
- private final RevocationVerificationManager verificationManager;
+ private final CertificateVerificationManager verificationManager;
public ClientSSLSetupHandler(final X509HostnameVerifier hostnameVerifier,
- final RevocationVerificationManager verificationManager) {
+ final CertificateVerificationManager verificationManager) {
this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : DEFAULT;
this.verificationManager = verificationManager;
}
@@ -184,7 +184,7 @@ public void verify(IOSession iosession, SSLSession sslsession) throws SSLExcepti
if (verificationManager!=null) {
try {
- verificationManager.verifyRevocationStatus(sslsession.getPeerCertificateChain());
+ verificationManager.verifyCertificateValidity(sslsession.getPeerCertificateChain());
} catch (CertificateVerificationException e) {
throw new SSLException("Certificate Chain Validation failed for host : " + address, e);
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java
index a4bc324ce1..bb4e7c08d6 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java
@@ -21,11 +21,12 @@
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
+import javax.security.cert.X509Certificate;
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.nio.reactor.ssl.SSLSetupHandler;
import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException;
-import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -36,12 +37,12 @@ public class ServerSSLSetupHandler implements SSLSetupHandler {
private final SSLClientAuth clientAuth;
/** Enabled SSL handshake protocols (e.g. SSLv3, TLSv1) */
private final String[] httpsProtocols;
- private RevocationVerificationManager verificationManager;
+ private CertificateVerificationManager verificationManager;
/** Ciphers enabled in axis2.xml, enabled all if null*/
private final String[] preferredCiphers;
public ServerSSLSetupHandler(final SSLClientAuth clientAuth, final String[] httpsProtocols,
- final RevocationVerificationManager verificationManager, final String[] preferredCiphers) {
+ final CertificateVerificationManager verificationManager, final String[] preferredCiphers) {
this.clientAuth = clientAuth;
this.httpsProtocols = httpsProtocols;
this.verificationManager = verificationManager;
@@ -78,7 +79,7 @@ public void verify(
if (verificationManager != null) {
try {
- verificationManager.verifyRevocationStatus(sslsession.getPeerCertificateChain());
+ verificationManager.verifyCertificateValidity(sslsession.getPeerCertificateChain());
} catch (CertificateVerificationException e) {
SocketAddress remoteAddress = iosession.getRemoteAddress();
String address;
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java
index bf504b9999..5495ae9fc2 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java
@@ -19,27 +19,6 @@
package org.apache.synapse.transport.nhttp.config;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLStreamException;
-
-import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.AxisFault;
@@ -52,8 +31,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.params.HttpParams;
-import org.apache.synapse.commons.crypto.CryptoConstants;
-import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager;
import org.apache.synapse.transport.exceptions.InvalidConfigurationException;
import org.apache.synapse.transport.http.conn.ClientConnFactory;
import org.apache.synapse.transport.http.conn.ClientSSLSetupHandler;
@@ -63,8 +41,25 @@
import org.apache.synapse.transport.nhttp.util.SecureVaultValueReader;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
-import org.wso2.securevault.SecureVaultException;
-import org.wso2.securevault.commons.MiscellaneousUtil;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
public class ClientConnFactoryBuilder {
@@ -76,6 +71,7 @@ public class ClientConnFactoryBuilder {
private SSLContextDetails ssl = null;
private Map sslByHostMap = null;
private ConfigurationContext configurationContext;
+ TrustStoreHolder trustStoreHolder = TrustStoreHolder.getInstance();
public ClientConnFactoryBuilder(final TransportOutDescription transportOut, ConfigurationContext configurationContext) {
this(transportOut);
@@ -87,7 +83,7 @@ public ClientConnFactoryBuilder(final TransportOutDescription transportOut) {
this.transportOut = transportOut;
this.name = transportOut.getName().toUpperCase(Locale.US);
}
-
+
public ClientConnFactoryBuilder parseSSL() throws AxisFault {
Parameter keyParam = transportOut.getParameter("keystore");
Parameter trustParam = transportOut.getParameter("truststore");
@@ -133,7 +129,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault {
final Parameter cvp = transportOut.getParameter("CertificateRevocationVerifier");
final String cvEnable = cvp != null ?
cvp.getParameterElement().getAttribute(new QName("enable")).getAttributeValue() : null;
- RevocationVerificationManager revocationVerifier = null;
+ CertificateVerificationManager certificateVerifier = null;
if ("true".equalsIgnoreCase(cvEnable)) {
String cacheSizeString = cvp.getParameterElement().getFirstChildWithName(new QName("CacheSize")).getText();
@@ -146,7 +142,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault {
cacheDelay = new Integer(cacheDelayString);
} catch (NumberFormatException e) {
}
- revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay);
+ certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay);
}
// Process HttpProtocols
@@ -167,7 +163,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault {
}
// Initiated separately to cater setting https protocols
- ClientSSLSetupHandler clientSSLSetupHandler = new ClientSSLSetupHandler(hostnameVerifier, revocationVerifier);
+ ClientSSLSetupHandler clientSSLSetupHandler = new ClientSSLSetupHandler(hostnameVerifier, certificateVerifier);
if (null != httpsProtocols) {
clientSSLSetupHandler.setHttpsProtocols(httpsProtocols);
@@ -353,28 +349,37 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE
log.warn(name + " Ignoring novalidatecert parameter since a truststore has been specified");
}
- String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText();
- String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText();
- OMElement passwordElement = trustStoreElt.getFirstChildWithName(new QName("Password"));
- if (passwordElement == null) {
- throw new AxisFault("Cannot proceed because Password element is missing in TrustStore");
- }
- String storePassword = SecureVaultValueReader.getSecureVaultValue(resolver, passwordElement);
-
FileInputStream fis = null;
+ String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText();;
+ KeyStore trustStore;
+
try {
- KeyStore trustStore = KeyStore.getInstance(type);
- fis = new FileInputStream(location);
- if (log.isDebugEnabled()) {
- log.debug(name + " Loading Trust Keystore from : " + location);
+ if (trustStoreHolder.getClientTrustStore() == null) {
+ String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText();
+ OMElement passwordElement = trustStoreElt.getFirstChildWithName(new QName("Password"));
+
+ if (passwordElement == null) {
+ throw new AxisFault("Cannot proceed because Password element is missing in TrustStore");
+ }
+
+ String storePassword = SecureVaultValueReader.getSecureVaultValue(resolver, passwordElement);
+ trustStore = KeyStore.getInstance(type);
+ fis = new FileInputStream(location);
+
+ if (log.isDebugEnabled()) {
+ log.debug(name + " Loading Trust Keystore from : " + location);
+ }
+
+ trustStore.load(fis, storePassword.toCharArray());
+ trustStoreHolder.setClientTrustStore(trustStore);
+ } else {
+ trustStore = trustStoreHolder.getClientTrustStore();
}
- trustStore.load(fis, storePassword.toCharArray());
TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerfactory.init(trustStore);
trustManagers = trustManagerfactory.getTrustManagers();
-
} catch (GeneralSecurityException gse) {
log.error(name + " Error loading Key store : " + location, gse);
throw new AxisFault("Error loading Key store : " + location, gse);
@@ -424,9 +429,9 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE
keyStoreElt.getFirstChildWithName(new QName("Password")));
String keyPassword = SecureVaultValueReader.getSecureVaultValue(secretResolver,
keyStoreElt.getFirstChildWithName(new QName("KeyPassword")));
-
- try (FileInputStream fis = new FileInputStream(location)) {
- KeyStore keyStore = KeyStore.getInstance(type);
+
+ try (FileInputStream fis = new FileInputStream(location)) {
+ KeyStore keyStore = KeyStore.getInstance(type);
if (log.isDebugEnabled()) {
log.debug(name + " Loading Identity Keystore from : " + location);
}
@@ -443,7 +448,7 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE
} catch (IOException ioe) {
log.error(name + " Error opening Keystore : " + location, ioe);
throw new AxisFault("Error opening Keystore : " + location, ioe);
- }
+ }
}
if (trustStoreElt != null) {
@@ -451,31 +456,35 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE
log.warn(name + " Ignoring novalidatecert parameter since a truststore has been specified");
}
+ KeyStore trustStore;
String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText();
- String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText();
- String storePassword = SecureVaultValueReader
- .getSecureVaultValue(secretResolver, trustStoreElt.getFirstChildWithName(new QName("Password")));
-
+
try (FileInputStream fis = new FileInputStream(location)) {
- KeyStore trustStore = KeyStore.getInstance(type);
-
- if (log.isDebugEnabled()) {
- log.debug(name + " Loading Trust Keystore from : " + location);
+ if (trustStoreHolder.getClientTrustStore() == null) {
+ String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText();
+ String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver,
+ trustStoreElt.getFirstChildWithName(new QName("Password")));
+ trustStore = KeyStore.getInstance(type);
+ if (log.isDebugEnabled()) {
+ log.debug(name + " Loading Trust Keystore from : " + location);
+ }
+ trustStore.load(fis, storePassword.toCharArray());
+ trustStoreHolder.setClientTrustStore(trustStore);
+ } else {
+ trustStore = trustStoreHolder.getClientTrustStore();
}
- trustStore.load(fis, storePassword.toCharArray());
TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerfactory.init(trustStore);
trustManagers = trustManagerfactory.getTrustManagers();
-
} catch (GeneralSecurityException gse) {
log.error(name + " Error loading Key store : " + location, gse);
throw new AxisFault("Error loading Key store : " + location, gse);
} catch (IOException ioe) {
log.error(name + " Error opening Key store : " + location, ioe);
throw new AxisFault("Error opening Key store : " + location, ioe);
- }
+ }
} else if (novalidatecert) {
if (log.isWarnEnabled()) {
log.warn(name + " Server certificate validation (trust) has been disabled. " +
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java
index 817c11e99b..b9b4b0018e 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java
@@ -26,11 +26,12 @@
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.transport.base.ParamUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.params.HttpParams;
-import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager;
import org.apache.synapse.transport.http.conn.SSLClientAuth;
import org.apache.synapse.transport.http.conn.SSLContextDetails;
import org.apache.synapse.transport.http.conn.ServerConnFactory;
@@ -40,6 +41,13 @@
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.xml.namespace.QName;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -54,14 +62,6 @@
import java.util.Locale;
import java.util.Map;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509KeyManager;
-import javax.xml.namespace.QName;
-
public class ServerConnFactoryBuilder {
private final Log log = LogFactory.getLog(ServerConnFactoryBuilder.class);
@@ -73,6 +73,7 @@ public class ServerConnFactoryBuilder {
protected SSLContextDetails ssl;
private Map sslByIPMap = null;
private ConfigurationContext configurationContext;
+ CertificateVerificationManager certificateVerifier = null;
public ServerConnFactoryBuilder(final TransportInDescription transportIn, final HttpHost host,
ConfigurationContext configurationContext) {
@@ -89,13 +90,13 @@ public ServerConnFactoryBuilder(final TransportInDescription transportIn, final
}
protected SSLContextDetails createSSLContext(
- final OMElement keyStoreEl,
- final OMElement trustStoreEl,
- final OMElement cientAuthEl,
- final OMElement httpsProtocolsEl,
- final OMElement preferredCiphersEl,
- final RevocationVerificationManager verificationManager,
- final String sslProtocol) throws AxisFault {
+ final OMElement keyStoreEl,
+ final OMElement trustStoreEl,
+ final OMElement cientAuthEl,
+ final OMElement httpsProtocolsEl,
+ final OMElement preferredCiphersEl,
+ final CertificateVerificationManager verificationManager,
+ final String sslProtocol) throws AxisFault {
SecretResolver secretResolver;
if (configurationContext != null && configurationContext.getAxisConfiguration() != null) {
@@ -114,7 +115,7 @@ protected SSLContextDetails createSSLContext(
final OMElement cientAuthEl,
final OMElement httpsProtocolsEl,
final OMElement preferredCiphersEl,
- final RevocationVerificationManager verificationManager,
+ final CertificateVerificationManager verificationManager,
final String sslProtocol, final SecretResolver secretResolver) throws AxisFault {
KeyManager[] keymanagers = null;
@@ -182,25 +183,38 @@ protected SSLContextDetails createSSLContext(
}
if (trustStoreEl != null) {
- String location = getValueOfElementWithLocalName(trustStoreEl, "Location");
- String type = getValueOfElementWithLocalName(trustStoreEl, "Type");
- OMElement storePasswordEl = trustStoreEl.getFirstChildWithName(new QName("Password"));
- if (storePasswordEl == null) {
- throw new AxisFault("Cannot proceed because Password element is missing in TrustStore");
- }
- String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, storePasswordEl);
+ TrustStoreHolder trustStoreHolder = TrustStoreHolder.getInstance();
FileInputStream fis = null;
+ String location = getValueOfElementWithLocalName(trustStoreEl, "Location");
+ KeyStore trustStore;
+
try {
- KeyStore trustStore = KeyStore.getInstance(type);
- fis = new FileInputStream(location);
- if (log.isDebugEnabled()) {
- log.debug(name + " Loading Trust Keystore from : " + location);
+ if (trustStoreHolder.getClientTrustStore() == null) {
+
+ String type = getValueOfElementWithLocalName(trustStoreEl, "Type");
+ OMElement storePasswordEl = trustStoreEl.getFirstChildWithName(new QName("Password"));
+
+ if (storePasswordEl == null) {
+ throw new AxisFault("Cannot proceed because Password element is missing in TrustStore");
+ }
+
+ String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, storePasswordEl);
+ trustStore = KeyStore.getInstance(type);
+ fis = new FileInputStream(location);
+
+ if (log.isDebugEnabled()) {
+ log.debug(name + " Loading Trust Keystore from : " + location);
+ }
+
+ trustStore.load(fis, storePassword.toCharArray());
+ trustStoreHolder.setClientTrustStore(trustStore);
+ } else {
+ trustStore = trustStoreHolder.getClientTrustStore();
}
- trustStore.load(fis, storePassword.toCharArray());
TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance(
- TrustManagerFactory.getDefaultAlgorithm());
+ TrustManagerFactory.getDefaultAlgorithm());
trustManagerfactory.init(trustStore);
trustManagers = trustManagerfactory.getTrustManagers();
@@ -294,7 +308,6 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault {
final Parameter cvp = transportIn.getParameter("CertificateRevocationVerifier");
final String cvEnable = cvp != null ?
cvp.getParameterElement().getAttribute(new QName("enable")).getAttributeValue() : null;
- RevocationVerificationManager revocationVerifier = null;
if ("true".equalsIgnoreCase(cvEnable)) {
String cacheSizeString = cvp.getParameterElement().getFirstChildWithName(new QName("CacheSize")).getText();
@@ -305,12 +318,33 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault {
cacheSize = new Integer(cacheSizeString);
cacheDelay = new Integer(cacheDelayString);
}
- catch (NumberFormatException e) {}
- revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay);
+ catch (NumberFormatException e) {
+ throw new AxisFault("Cache size or Cache delay values are malformed", e);
+ }
+
+ // Checking whether the full certificate chain validation is enabled or not.
+ boolean isFullCertChainValidationEnabled = true;
+ boolean isCertExpiryValidationEnabled = false;
+ OMElement fullCertChainValidationConfig = cvp.getParameterElement()
+ .getFirstChildWithName(new QName("FullChainValidation"));
+ OMElement certExpiryValidationConfig = cvp.getParameterElement()
+ .getFirstChildWithName(new QName("ExpiryValidation"));
+
+ if (fullCertChainValidationConfig != null
+ && StringUtils.equals("false", fullCertChainValidationConfig.getText())) {
+ isFullCertChainValidationEnabled = false;
+ }
+
+ if (certExpiryValidationConfig != null && StringUtils.equals("true", certExpiryValidationConfig.getText())) {
+ isCertExpiryValidationEnabled = true;
+ }
+
+ certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay,
+ isFullCertChainValidationEnabled, isCertExpiryValidationEnabled);
}
ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphersEl,
- revocationVerifier, sslProtocol);
+ certificateVerifier, sslProtocol);
return this;
}
@@ -324,6 +358,7 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault {
OMElement profilesEl = profileParam.getParameterElement();
SecretResolver secretResolver = SecretResolverFactory.create(profilesEl, true);
Iterator> profiles = profilesEl.getChildrenWithName(new QName("profile"));
+
while (profiles.hasNext()) {
OMElement profileEl = (OMElement) profiles.next();
OMElement bindAddressEl = profileEl.getFirstChildWithName(new QName("bindAddress"));
@@ -341,8 +376,63 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault {
OMElement preferredCiphersEl = profileEl.getFirstChildWithName(new QName(NhttpConstants.PREFERRED_CIPHERS));
final Parameter sslpParameter = transportIn.getParameter("SSLProtocol");
final String sslProtocol = sslpParameter != null ? sslpParameter.getValue().toString() : "TLS";
+
+ /* If multi SSL profiles are configured, checking whether the certificate revocation verifier is
+ configured and full certificate chain validation is enabled or not. */
+ if (profileEl.getFirstChildWithName(new QName("CertificateRevocationVerifier")) != null) {
+
+ Integer cacheSize = null;
+ Integer cacheDelay = null;
+
+ OMElement revocationVerifierConfig = profileEl
+ .getFirstChildWithName(new QName("CertificateRevocationVerifier"));
+ OMElement revocationEnabled = revocationVerifierConfig
+ .getFirstChildWithName(new QName("Enable"));
+
+ if (revocationEnabled != null && "true".equals(revocationEnabled.getText())) {
+ String cacheSizeString = revocationVerifierConfig
+ .getFirstChildWithName(new QName("CacheSize")).getText();
+ String cacheDelayString = revocationVerifierConfig
+ .getFirstChildWithName(new QName("CacheDelay")).getText();
+
+ try {
+ cacheSize = new Integer(cacheSizeString);
+ cacheDelay = new Integer(cacheDelayString);
+ } catch (NumberFormatException e) {
+ throw new AxisFault("Cache size or Cache delay values are malformed", e);
+ }
+ }
+
+ boolean isFullCertChainValidationEnabled = true;
+ boolean isCertExpiryValidationEnabled = false;
+
+ OMElement fullCertChainValidationConfig = revocationVerifierConfig
+ .getFirstChildWithName(new QName("FullChainValidation"));
+
+ OMElement certExpiryValidationConfig = revocationVerifierConfig
+ .getFirstChildWithName(new QName("ExpiryValidation"));
+
+ if (fullCertChainValidationConfig != null
+ && StringUtils.equals("false", fullCertChainValidationConfig.getText())) {
+ isFullCertChainValidationEnabled = false;
+ }
+
+ if (certExpiryValidationConfig != null
+ && StringUtils.equals("true", certExpiryValidationConfig.getText())) {
+ isCertExpiryValidationEnabled = true;
+ }
+
+ if (fullCertChainValidationConfig != null
+ && StringUtils.equals("false", fullCertChainValidationConfig.getText())) {
+ isFullCertChainValidationEnabled = false;
+ }
+
+ certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay,
+ isFullCertChainValidationEnabled, isCertExpiryValidationEnabled);
+ }
+
SSLContextDetails ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl,
- preferredCiphersEl, null, sslProtocol, secretResolver);
+ preferredCiphersEl, certificateVerifier, sslProtocol, secretResolver);
if (sslByIPMap == null) {
sslByIPMap = new HashMap();
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java
new file mode 100644
index 0000000000..697dd6eba6
--- /dev/null
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.synapse.transport.nhttp.config;
+
+import java.security.KeyStore;
+
+/**
+ * A data holder class to store the client trust store.
+ */
+public class TrustStoreHolder {
+
+ private static volatile TrustStoreHolder instance;
+ private KeyStore clientTrustStore;
+
+ private TrustStoreHolder() {}
+
+ public static TrustStoreHolder getInstance() {
+
+ if (instance == null) {
+ synchronized (TrustStoreHolder.class) {
+ if (instance == null) {
+ instance = new TrustStoreHolder();
+ }
+ }
+ }
+ return instance;
+ }
+
+ public KeyStore getClientTrustStore() {
+
+ return clientTrustStore;
+ }
+
+ public void setClientTrustStore(KeyStore clientTrustStore) {
+
+ this.clientTrustStore = clientTrustStore;
+ }
+
+ /**
+ * Reset the instance.
+ */
+ public static void resetInstance() {
+
+ instance = null;
+ }
+}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java
index 1d4ddf2a6a..3e7f92c6d6 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java
@@ -47,8 +47,6 @@
import org.apache.axis2.transport.TransportListener;
import org.apache.axis2.transport.base.BaseConstants;
import org.apache.axis2.transport.base.BaseUtils;
-import org.apache.axis2.transport.base.ManagementSupport;
-import org.apache.axis2.transport.base.TransportMBeanSupport;
import org.apache.axis2.transport.base.threads.NativeThreadFactory;
import org.apache.axis2.transport.base.threads.WorkerPool;
import org.apache.axis2.transport.base.tracker.AxisServiceFilter;
@@ -62,8 +60,10 @@
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.nio.reactor.IOReactorExceptionHandler;
import org.apache.http.params.HttpConnectionParams;
+import org.apache.synapse.transport.certificatevalidation.cache.CertCache;
import org.apache.synapse.transport.http.conn.Scheme;
import org.apache.synapse.transport.http.conn.ServerConnFactory;
+import org.apache.synapse.transport.nhttp.config.TrustStoreHolder;
import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder;
import org.apache.synapse.transport.passthru.config.PassThroughConfiguration;
import org.apache.synapse.transport.passthru.config.SourceConfiguration;
@@ -683,5 +683,4 @@ public void reloadDynamicSSLConfig(TransportInDescription transportInDescription
this.reloadSpecificEndPoints(transportInDescription);
}
}
-
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java
index 208b364178..406ae5a53b 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java
@@ -5,10 +5,12 @@
import org.apache.axis2.description.ParameterInclude;
import org.apache.axis2.description.TransportInDescription;
import org.apache.http.HttpHost;
+import org.apache.synapse.transport.certificatevalidation.cache.CertCache;
import org.apache.synapse.transport.http.conn.Scheme;
import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder;
import org.apache.synapse.transport.dynamicconfigurations.ListenerProfileReloader;
import org.apache.synapse.transport.dynamicconfigurations.SSLProfileLoader;
+import org.apache.synapse.transport.nhttp.config.TrustStoreHolder;
public class PassThroughHttpMultiSSLListener extends PassThroughHttpListener implements SSLProfileLoader{
@@ -39,6 +41,8 @@ protected ServerConnFactoryBuilder initConnFactoryBuilder(final TransportInDescr
* @throws AxisFault
*/
public void reloadConfig(ParameterInclude transport) throws AxisFault {
+ CertCache.resetCache();
+ TrustStoreHolder.resetInstance();
reloadDynamicSSLConfig((TransportInDescription) transport);
}
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java
index 3af961c03f..b977eb30a7 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java
@@ -47,12 +47,14 @@
import org.apache.http.nio.reactor.IOReactorExceptionHandler;
import org.apache.http.protocol.HTTP;
import org.apache.synapse.commons.CorrelationConstants;
+import org.apache.synapse.transport.certificatevalidation.cache.CertCache;
import org.apache.synapse.transport.exceptions.InvalidConfigurationException;
import org.apache.synapse.transport.http.conn.ClientConnFactory;
import org.apache.synapse.transport.http.conn.ProxyConfig;
import org.apache.synapse.transport.http.conn.Scheme;
import org.apache.synapse.transport.nhttp.NhttpConstants;
import org.apache.synapse.transport.nhttp.config.ClientConnFactoryBuilder;
+import org.apache.synapse.transport.nhttp.config.TrustStoreHolder;
import org.apache.synapse.transport.nhttp.config.ProxyConfigBuilder;
import org.apache.synapse.transport.nhttp.util.MessageFormatterDecoratorFactory;
import org.apache.synapse.transport.nhttp.util.NhttpUtil;
@@ -557,7 +559,7 @@ public void submitResponse(MessageContext msgContext)
ProtocolState state = SourceContext.getState(conn);
if (state != null && state.compareTo(ProtocolState.REQUEST_DONE) <= 0) {
// start sending the response if we
-
+
boolean noEntityBodyResponse = false;
if (noEntityBody != null && Boolean.TRUE == noEntityBody
&& pipe != null) {
@@ -567,7 +569,7 @@ public void submitResponse(MessageContext msgContext)
out.close();
noEntityBodyResponse = true;
}
-
+
if (!noEntityBodyResponse && msgContext.isPropertyTrue(PassThroughConstants.MESSAGE_BUILDER_INVOKED) && pipe != null) {
OutputStream out = pipe.getOutputStream();
/*if (msgContext.isPropertyTrue(NhttpConstants.SC_ACCEPTED)) {
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/Pipe.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/Pipe.java
index 73fe7ea168..a13403bd16 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/Pipe.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/Pipe.java
@@ -672,7 +672,6 @@ public void write(final byte[] b, int off, int len) throws IOException {
return;
} else if (isProducerError()) {
writeCondition.signalAll();
- buffer.clear();
return;
}
} else if (consumerIoControl instanceof NHttpClientConnection) {
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/SourceHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/SourceHandler.java
index 335ccb17de..bcd7242f8a 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/SourceHandler.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/SourceHandler.java
@@ -28,6 +28,7 @@
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
+import org.apache.http.MethodNotSupportedException;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.nio.ContentDecoder;
import org.apache.http.nio.ContentEncoder;
@@ -895,42 +896,12 @@ public void exception(NHttpServerConnection conn, Exception ex) {
isFault = true;
SourceContext.updateState(conn, ProtocolState.CLOSED);
sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
+ } else if (ex instanceof MethodNotSupportedException) {
+ isFault = generateHTTPErrorResponse(conn, ex, HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_IMPLEMENTED,
+ "Not Implemented");
} else if (ex instanceof HttpException) {
- log.error("HttpException occurred ", ex);
- if (PassThroughCorrelationConfigDataHolder.isEnable()) {
- logHttpRequestErrorInCorrelationLog(conn, "HTTP Exception");
- }
- try {
- if (conn.isResponseSubmitted()) {
- sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
- return;
- }
- HttpContext httpContext = conn.getContext();
-
- HttpResponse response = new BasicHttpResponse(
- HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_REQUEST, "Bad request");
- response.setParams(
- new DefaultedHttpParams(sourceConfiguration.getHttpParams(),
- response.getParams()));
- response.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
-
- // Pre-process HTTP request
- httpContext.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
- httpContext.setAttribute(ExecutionContext.HTTP_REQUEST, null);
- httpContext.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
-
- sourceConfiguration.getHttpProcessor().process(response, httpContext);
-
- conn.submitResponse(response);
- SourceContext.updateState(conn, ProtocolState.CLOSED);
- informWriterError(conn);
- conn.close();
- } catch (Exception ex1) {
- log.error(ex1.getMessage(), ex1);
- SourceContext.updateState(conn, ProtocolState.CLOSED);
- sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
- isFault = true;
- }
+ isFault = generateHTTPErrorResponse(conn, ex, HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_REQUEST,
+ "Bad request");
} else {
log.error("Unexpected error: " + ex.getMessage(), ex);
SourceContext.updateState(conn, ProtocolState.CLOSED);
@@ -943,6 +914,45 @@ public void exception(NHttpServerConnection conn, Exception ex) {
}
}
+ private boolean generateHTTPErrorResponse (NHttpServerConnection conn, Exception ex, HttpVersion version,
+ int statusCode, String reason) {
+ log.error("HttpException occurred ", ex);
+ boolean isFault = false;
+ if (PassThroughCorrelationConfigDataHolder.isEnable()) {
+ logHttpRequestErrorInCorrelationLog(conn, "HTTP Exception");
+ }
+ try {
+ if (conn.isResponseSubmitted()) {
+ sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
+ return false;
+ }
+ HttpContext httpContext = conn.getContext();
+
+ HttpResponse response = new BasicHttpResponse(version, statusCode, reason);
+ response.setParams(
+ new DefaultedHttpParams(sourceConfiguration.getHttpParams(), response.getParams()));
+ response.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
+
+ // Pre-process HTTP request
+ httpContext.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+ httpContext.setAttribute(ExecutionContext.HTTP_REQUEST, null);
+ httpContext.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
+
+ sourceConfiguration.getHttpProcessor().process(response, httpContext);
+
+ conn.submitResponse(response);
+ SourceContext.updateState(conn, ProtocolState.CLOSED);
+ informWriterError(conn);
+ conn.close();
+ } catch (Exception ex1) {
+ log.error(ex1.getMessage(), ex1);
+ SourceContext.updateState(conn, ProtocolState.CLOSED);
+ sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
+ isFault = true;
+ }
+ return isFault;
+ }
+
private Map getLoggingInfo(NHttpServerConnection conn, ProtocolState state) {
HashMap logDetails = new HashMap<>();
SourceContext sourceContext = SourceContext.get(conn);
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java
index 282900b956..8ea5433d4f 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java
@@ -19,12 +19,11 @@
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
-import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.TransportInDescription;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
-import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager;
+import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager;
import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder;
import javax.xml.namespace.QName;
@@ -46,7 +45,7 @@ public ServerConnFactoryBuilder parseSSL(OMElement keyStoreEl, OMElement trustSt
AxisFault {
final String cvEnable = cvp != null ?
cvp.getAttribute(new QName("enable")).getAttributeValue() : null;
- RevocationVerificationManager revocationVerifier = null;
+ CertificateVerificationManager revocationVerifier = null;
if ("true".equalsIgnoreCase(cvEnable)) {
Iterator iterator = cvp.getChildElements();
@@ -70,7 +69,7 @@ public ServerConnFactoryBuilder parseSSL(OMElement keyStoreEl, OMElement trustSt
} catch (NumberFormatException e) {
log.error("Please specify correct Integer numbers for CacheDelay and CacheSize");
}
- revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay);
+ revocationVerifier = new CertificateVerificationManager(cacheSize, cacheDelay);
}
ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphers,
revocationVerifier,
diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java
index f5a81c1572..406a7a2d30 100644
--- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java
+++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java
@@ -170,5 +170,4 @@ public static String getStringProperty(String name, String def, Properties props
return val == null ? def : val;
}
-
}
diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java
index 38d7964b8a..ec582f9dd7 100644
--- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java
+++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java
@@ -88,8 +88,7 @@ public void testRevokedCertificate() throws Exception {
//Create a crl with fakeRevokedCertificate marked as revoked.
X509CRL x509CRL = createCRL(fakeCACert, caKeyPair.getPrivate(), revokedSerialNumber);
- CRLCache cache = CRLCache.getCache();
- cache.init(5, 5);
+ CRLCache cache = CRLCache.getCache(5, 5);
cache.setCacheValue(crlDistributionPointUrl, x509CRL);
CRLVerifier crlVerifier = new CRLVerifier(cache);
diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java
index 9c2299bb2b..9d4f0a01bd 100644
--- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java
+++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java
@@ -107,8 +107,7 @@ public void testOCSPVerifier() throws Exception{
OCSPResp response = generateOCSPResponse(request, certificateHolder, caKeyPair.getPrivate(), caKeyPair.getPublic(), revokedID);
SingleResp singleResp = ((BasicOCSPResp)response.getResponseObject()).getResponses()[0];
- OCSPCache cache = OCSPCache.getCache();
- cache.init(5,5);
+ OCSPCache cache = OCSPCache.getCache(5, 5);
cache.setCacheValue(revokedSerialNumber,singleResp, request, null);
OCSPVerifier ocspVerifier= new OCSPVerifier(cache);
diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java
index 7f282dd86c..9adc063ea0 100644
--- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java
+++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java
@@ -116,8 +116,7 @@ public void testOCSPPathValidationWithFakeCerts() throws Exception {
private void crlPathValidation(X509Certificate[] certChain) throws Exception {
- CRLCache crlCache = CRLCache.getCache();
- crlCache.init(5, 5);
+ CRLCache crlCache = CRLCache.getCache(5, 5);
RevocationVerifier verifier = new CRLVerifier(crlCache);
CertificatePathValidator pathValidator = new CertificatePathValidator(certChain, verifier);
pathValidator.validatePath();
@@ -125,8 +124,7 @@ private void crlPathValidation(X509Certificate[] certChain) throws Exception {
private void ocspPathValidation(X509Certificate[] certChain) throws Exception {
- OCSPCache ocspCache = OCSPCache.getCache();
- ocspCache.init(5, 5);
+ OCSPCache ocspCache = OCSPCache.getCache(5, 5);
RevocationVerifier verifier = new OCSPVerifier(ocspCache);
CertificatePathValidator pathValidator = new CertificatePathValidator(certChain, verifier);
pathValidator.validatePath();
diff --git a/modules/transports/core/pipe/pom.xml b/modules/transports/core/pipe/pom.xml
index 4f399083c6..646cbd743c 100644
--- a/modules/transports/core/pipe/pom.xml
+++ b/modules/transports/core/pipe/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
synapse-transports
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/transports/core/vfs/pom.xml b/modules/transports/core/vfs/pom.xml
index 30aab7c13a..ba4e8c278c 100644
--- a/modules/transports/core/vfs/pom.xml
+++ b/modules/transports/core/vfs/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
synapse-transports
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties
new file mode 100644
index 0000000000..8f1ee4a76d
--- /dev/null
+++ b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties
@@ -0,0 +1 @@
+t-0-1705986523002.txt 23/01/2024/ 10:38:43
\ No newline at end of file
diff --git a/modules/transports/optional/fix/pom.xml b/modules/transports/optional/fix/pom.xml
index ba0d6462df..0b1ca0e531 100644
--- a/modules/transports/optional/fix/pom.xml
+++ b/modules/transports/optional/fix/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
synapse-transports
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/transports/pom.xml b/modules/transports/pom.xml
index 74939da9d1..7779daced2 100644
--- a/modules/transports/pom.xml
+++ b/modules/transports/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/war/pom.xml b/modules/war/pom.xml
index 4c3ddb51a2..3245da206a 100644
--- a/modules/war/pom.xml
+++ b/modules/war/pom.xml
@@ -23,7 +23,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
diff --git a/modules/xar-maven-plugin/pom.xml b/modules/xar-maven-plugin/pom.xml
index 041c9ea649..441411c9a6 100644
--- a/modules/xar-maven-plugin/pom.xml
+++ b/modules/xar-maven-plugin/pom.xml
@@ -22,7 +22,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
../../pom.xml
org.apache.synapse
diff --git a/pom.xml b/pom.xml
index efee8ef8b6..165a8ef696 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
org.apache.synapse
Apache-Synapse
- 4.0.0-wso2v72-SNAPSHOT
+ 4.0.0-wso2v79-SNAPSHOT
Apache Synapse
Apache Synapse
pom
@@ -1566,10 +1566,10 @@
2.0.9
3.0.0
2.2.6.wso2v9
- 2.13.4
- 2.13.4.2
- 32.1.3-jre
- 1.0.1
+ 2.16.1
+ 2.16.1
+ 33.0.0-jre
+ 1.0.2
2.9.4.wso2v1
7.4.2.wso2v1
0.8.6
@@ -1585,11 +1585,11 @@
5.9.1
1.5.2
1.17.0
- 4.1.100.Final
- 6.3.49
+ 4.1.104.Final
+ 6.3.50
1.1.1.wso2v3
5.8.0
- 1.11.0.wso2v5
+ 1.11.0.wso2v6
4.9.3.wso2v2
2.8.0.wso2v2
2.16.3
diff --git a/repository/conf/sample/synapse_sample_63.xml b/repository/conf/sample/synapse_sample_63.xml
index fbc676bfda..8e1d7d1e74 100644
--- a/repository/conf/sample/synapse_sample_63.xml
+++ b/repository/conf/sample/synapse_sample_63.xml
@@ -211,5 +211,33 @@
+
+
+
+
+
+
+
+
+
+
+ my_client_id
+ my_client_secret
+ {$ctx:token_ep}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+