Skip to content

Commit 18560a9

Browse files
committed
Add nonProxyHosts/targetProxyHosts support to OAuth token endpoint proxy
1 parent a35d826 commit 18560a9

5 files changed

Lines changed: 395 additions & 1 deletion

File tree

modules/core/src/main/java/org/apache/synapse/endpoints/ProxyConfigs.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public class ProxyConfigs {
2929
private String proxyPassword;
3030
private String proxyProtocol;
3131
private boolean proxyEnabled;
32+
private String nonProxyHosts;
33+
private String targetProxyHosts;
3234
private SecretResolver proxyPasswordSecretResolver;
3335

3436
public void setProxyEnabled(boolean proxyEnabled) {
@@ -79,6 +81,22 @@ public String getProxyProtocol() {
7981
return proxyProtocol;
8082
}
8183

84+
public void setNonProxyHosts(String nonProxyHosts) {
85+
this.nonProxyHosts = nonProxyHosts;
86+
}
87+
88+
public String getNonProxyHosts() {
89+
return nonProxyHosts;
90+
}
91+
92+
public void setTargetProxyHosts(String targetProxyHosts) {
93+
this.targetProxyHosts = targetProxyHosts;
94+
}
95+
96+
public String getTargetProxyHosts() {
97+
return targetProxyHosts;
98+
}
99+
82100
public void setProxyPasswordSecretResolver(SecretResolver proxyPasswordSecretResolver) {
83101
this.proxyPasswordSecretResolver = proxyPasswordSecretResolver;
84102
}

modules/core/src/main/java/org/apache/synapse/endpoints/auth/AuthConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,16 @@ public class AuthConstants {
9797
public static final String PROXY_USERNAME = "proxyUsername";
9898
public static final String PROXY_PASSWORD = "proxyPassword";
9999
public static final String OAUTH_PROXY_PROTOCOL = "proxyProtocol";
100+
public static final String PROXY_NON_PROXY_HOSTS = "nonProxyHosts";
101+
public static final String PROXY_TARGET_PROXY_HOSTS = "targetProxyHosts";
100102
public static final String OAUTH_GLOBAL_PROXY_ENABLED = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.enabled";
101103
public static final String OAUTH_GLOBAL_PROXY_HOST = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.host";
102104
public static final String OAUTH_GLOBAL_PROXY_PORT = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.port";
103105
public static final String OAUTH_GLOBAL_PROXY_USERNAME = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.username";
104106
public static final String OAUTH_GLOBAL_PROXY_PASSWORD = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.password";
105107
public static final String OAUTH_GLOBAL_PROXY_PROTOCOL = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.protocol";
108+
public static final String OAUTH_GLOBAL_PROXY_NON_PROXY_HOSTS = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.nonProxyHosts";
109+
public static final String OAUTH_GLOBAL_PROXY_TARGET_PROXY_HOSTS = "synapse.endpoint.http.oauth.token.endpoint.global.proxy.targetProxyHosts";
106110

107111
// OAuth token endpoint truststore property names for synapse.properties
108112
public static final String OAUTH_TOKEN_ENDPOINT_TRUST_STORE_LOCATION = "synapse.endpoint.http.oauth.token.endpoint.trust.store.location";

modules/core/src/main/java/org/apache/synapse/endpoints/auth/oauth/OAuthUtils.java

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import org.apache.commons.lang.StringUtils;
2929
import org.apache.commons.logging.Log;
3030
import org.apache.commons.logging.LogFactory;
31+
import org.apache.http.HttpException;
3132
import org.apache.http.HttpHost;
33+
import org.apache.http.HttpRequest;
3234
import org.apache.http.auth.AuthScope;
3335
import org.apache.http.auth.UsernamePasswordCredentials;
3436
import org.apache.http.client.CredentialsProvider;
@@ -46,6 +48,7 @@
4648
import org.apache.http.impl.client.HttpClients;
4749
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
4850
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
51+
import org.apache.http.protocol.HttpContext;
4952
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
5053
import org.apache.synapse.MessageContext;
5154
import org.apache.synapse.SynapseConstants;
@@ -343,6 +346,8 @@ private static ProxyConfigs getProxyConfigs(OMElement grantTypeOMElement) {
343346
proxyConfigs.setProxyProtocol(getChildValue(proxyConfigsOM, AuthConstants.OAUTH_PROXY_PROTOCOL));
344347
proxyConfigs.setProxyUsername(getChildValue(proxyConfigsOM, AuthConstants.PROXY_USERNAME));
345348
proxyConfigs.setProxyPassword(getChildValue(proxyConfigsOM, AuthConstants.PROXY_PASSWORD));
349+
proxyConfigs.setNonProxyHosts(getChildValue(proxyConfigsOM, AuthConstants.PROXY_NON_PROXY_HOSTS));
350+
proxyConfigs.setTargetProxyHosts(getChildValue(proxyConfigsOM, AuthConstants.PROXY_TARGET_PROXY_HOSTS));
346351
} else {
347352
Properties synapseProperties = SynapsePropertiesLoader.loadSynapseProperties();
348353
if (Boolean.parseBoolean(getChildValue(grantTypeOMElement, AuthConstants.USE_GLOBAL_PROXY_CONFIGS))
@@ -352,6 +357,8 @@ private static ProxyConfigs getProxyConfigs(OMElement grantTypeOMElement) {
352357
proxyConfigs.setProxyHost(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_HOST));
353358
proxyConfigs.setProxyPort(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_PORT));
354359
proxyConfigs.setProxyProtocol(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_PROTOCOL));
360+
proxyConfigs.setNonProxyHosts(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_NON_PROXY_HOSTS));
361+
proxyConfigs.setTargetProxyHosts(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_TARGET_PROXY_HOSTS));
355362
if (StringUtils.isNotBlank(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_USERNAME)) &&
356363
StringUtils.isNotBlank(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_PASSWORD))) {
357364
proxyConfigs.setProxyUsername(synapseProperties.getProperty(AuthConstants.OAUTH_GLOBAL_PROXY_USERNAME));
@@ -812,6 +819,18 @@ public static OMElement createOMProxyConfigs(OMFactory omFactory, ProxyConfigs p
812819
proxyConfigs.getProxyProtocol());
813820
proxyConfigsOM.addChild(proxyProtocolOM);
814821

822+
if (StringUtils.isNotBlank(proxyConfigs.getNonProxyHosts())) {
823+
OMElement nonProxyHostsOM = OAuthUtils.createOMElementWithValue(omFactory,
824+
AuthConstants.PROXY_NON_PROXY_HOSTS, proxyConfigs.getNonProxyHosts());
825+
proxyConfigsOM.addChild(nonProxyHostsOM);
826+
}
827+
828+
if (StringUtils.isNotBlank(proxyConfigs.getTargetProxyHosts())) {
829+
OMElement targetProxyHostsOM = OAuthUtils.createOMElementWithValue(omFactory,
830+
AuthConstants.PROXY_TARGET_PROXY_HOSTS, proxyConfigs.getTargetProxyHosts());
831+
proxyConfigsOM.addChild(targetProxyHostsOM);
832+
}
833+
815834
return proxyConfigsOM;
816835
}
817836

@@ -888,7 +907,8 @@ public boolean verify(String urlHostName, SSLSession session) {
888907
HttpHost host = new HttpHost(proxyConfigs.getProxyHost(), Integer.parseInt(proxyConfigs.getProxyPort()),
889908
proxyConfigs.getProxyProtocol());
890909

891-
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(host);
910+
NonProxyAwareProxyRoutePlanner routePlanner = new NonProxyAwareProxyRoutePlanner(host,
911+
proxyConfigs.getNonProxyHosts(), proxyConfigs.getTargetProxyHosts());
892912

893913
clientBuilder = HttpClients.custom().setConnectionManager(pool).setRoutePlanner(routePlanner)
894914
.setDefaultRequestConfig(config).setSSLSocketFactory(sslConnectionFactory);
@@ -948,4 +968,84 @@ public static String resolveProxyPassword(ProxyConfigs proxyConfigs, MessageCont
948968
return OAuthUtils.resolveExpression(proxyConfigs.getProxyPassword(), messageContext);
949969
}
950970
}
971+
972+
private static class NonProxyAwareProxyRoutePlanner extends DefaultProxyRoutePlanner {
973+
974+
private final String[] nonProxyPatterns;
975+
private final String[] targetProxyPatterns;
976+
977+
NonProxyAwareProxyRoutePlanner(HttpHost proxy, String nonProxyHosts, String targetProxyHosts) {
978+
super(proxy);
979+
if (org.apache.commons.lang3.StringUtils.isNotBlank(nonProxyHosts)) {
980+
this.nonProxyPatterns = nonProxyHosts.split("\\|");
981+
} else {
982+
this.nonProxyPatterns = new String[0];
983+
}
984+
if (org.apache.commons.lang3.StringUtils.isNotBlank(targetProxyHosts)) {
985+
this.targetProxyPatterns = targetProxyHosts.split("\\|");
986+
} else {
987+
this.targetProxyPatterns = new String[0];
988+
}
989+
}
990+
991+
@Override
992+
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context)
993+
throws HttpException {
994+
995+
String targetHost = target.getHostName();
996+
997+
for (String pattern : nonProxyPatterns) {
998+
String trimmedPattern = pattern.trim();
999+
if (!trimmedPattern.isEmpty()) {
1000+
if ("*".equals(trimmedPattern)) {
1001+
if (log.isDebugEnabled()) {
1002+
log.debug("Host [" + targetHost + "] matches wildcard non-proxy pattern [*]. "
1003+
+ "Bypassing proxy.");
1004+
}
1005+
return null;
1006+
}
1007+
if (matchesPattern(targetHost, trimmedPattern)) {
1008+
if (log.isDebugEnabled()) {
1009+
log.debug("Host [" + targetHost + "] matches non-proxy pattern [" + trimmedPattern
1010+
+ "]. Bypassing proxy.");
1011+
}
1012+
return null;
1013+
}
1014+
}
1015+
}
1016+
1017+
if (targetProxyPatterns.length > 0) {
1018+
for (String pattern : targetProxyPatterns) {
1019+
String trimmedPattern = pattern.trim();
1020+
if (!trimmedPattern.isEmpty()) {
1021+
if ("*".equals(trimmedPattern)) {
1022+
if (log.isDebugEnabled()) {
1023+
log.debug("Host [" + targetHost + "] matches wildcard target-proxy pattern [*]. "
1024+
+ "Using proxy.");
1025+
}
1026+
return super.determineProxy(target, request, context);
1027+
}
1028+
if (matchesPattern(targetHost, trimmedPattern)) {
1029+
if (log.isDebugEnabled()) {
1030+
log.debug("Host [" + targetHost + "] matches target-proxy pattern [" + trimmedPattern
1031+
+ "]. Using proxy.");
1032+
}
1033+
return super.determineProxy(target, request, context);
1034+
}
1035+
}
1036+
}
1037+
if (log.isDebugEnabled()) {
1038+
log.debug("Host [" + targetHost + "] does not match any target-proxy pattern. Bypassing proxy.");
1039+
}
1040+
return null;
1041+
}
1042+
1043+
return super.determineProxy(target, request, context);
1044+
}
1045+
1046+
private boolean matchesPattern(String hostname, String pattern) {
1047+
String regex = pattern.replace(".", "\\.").replace("*", ".*");
1048+
return hostname.matches(regex);
1049+
}
1050+
}
9511051
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com/).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
package org.apache.synapse.endpoints;
20+
21+
import org.junit.Test;
22+
23+
import static org.junit.Assert.assertEquals;
24+
import static org.junit.Assert.assertNull;
25+
26+
public class ProxyConfigsTest {
27+
28+
@Test
29+
public void testNonProxyHostsGetterSetter() {
30+
ProxyConfigs proxyConfigs = new ProxyConfigs();
31+
assertNull(proxyConfigs.getNonProxyHosts());
32+
33+
proxyConfigs.setNonProxyHosts("localhost|*.internal.com");
34+
assertEquals("localhost|*.internal.com", proxyConfigs.getNonProxyHosts());
35+
}
36+
37+
@Test
38+
public void testTargetProxyHostsGetterSetter() {
39+
ProxyConfigs proxyConfigs = new ProxyConfigs();
40+
assertNull(proxyConfigs.getTargetProxyHosts());
41+
42+
proxyConfigs.setTargetProxyHosts("*.external.com|api.example.com");
43+
assertEquals("*.external.com|api.example.com", proxyConfigs.getTargetProxyHosts());
44+
}
45+
46+
@Test
47+
public void testNonProxyHostsWithEmptyString() {
48+
ProxyConfigs proxyConfigs = new ProxyConfigs();
49+
proxyConfigs.setNonProxyHosts("");
50+
assertEquals("", proxyConfigs.getNonProxyHosts());
51+
}
52+
53+
@Test
54+
public void testTargetProxyHostsWithNull() {
55+
ProxyConfigs proxyConfigs = new ProxyConfigs();
56+
proxyConfigs.setTargetProxyHosts(null);
57+
assertNull(proxyConfigs.getTargetProxyHosts());
58+
}
59+
60+
@Test
61+
public void testExistingFieldsUnaffected() {
62+
ProxyConfigs proxyConfigs = new ProxyConfigs();
63+
proxyConfigs.setProxyHost("proxy.example.com");
64+
proxyConfigs.setProxyPort("8080");
65+
proxyConfigs.setProxyProtocol("HTTP");
66+
proxyConfigs.setProxyEnabled(true);
67+
proxyConfigs.setNonProxyHosts("localhost");
68+
proxyConfigs.setTargetProxyHosts("*.external.com");
69+
70+
assertEquals("proxy.example.com", proxyConfigs.getProxyHost());
71+
assertEquals("8080", proxyConfigs.getProxyPort());
72+
assertEquals("HTTP", proxyConfigs.getProxyProtocol());
73+
assertEquals(true, proxyConfigs.isProxyEnabled());
74+
assertEquals("localhost", proxyConfigs.getNonProxyHosts());
75+
assertEquals("*.external.com", proxyConfigs.getTargetProxyHosts());
76+
}
77+
}

0 commit comments

Comments
 (0)