Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [COR-916] Use proxy config to make outbound connections through internet #517

Merged
merged 10 commits into from
May 23, 2024
16 changes: 16 additions & 0 deletions store/conf/web.xml.production
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,17 @@
<load-on-startup>7</load-on-startup>
</servlet>

<servlet>
<servlet-name>ProxyServlet</servlet-name>
<servlet-class>com.zimbra.cs.service.servlet.proxy.ProxyServlet</servlet-class>
<async-supported>true</async-supported>
<init-param>
<param-name>allowed.ports</param-name>
<param-value>%%zimbraMailPort%%, %%zimbraMailSSLPort%%, 7070</param-value>
</init-param>
<load-on-startup>8</load-on-startup>
</servlet>

<servlet>
<servlet-name>DavServlet</servlet-name>
<servlet-class>com.zimbra.cs.dav.service.DavServlet</servlet-class>
Expand Down Expand Up @@ -555,6 +566,11 @@
<url-pattern>/collectldapconfig/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>ProxyServlet</servlet-name>
<url-pattern>/proxy/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>DavServlet</servlet-name>
<url-pattern>/dav/*</url-pattern>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.zextras.mailbox.tracking;

import com.zimbra.cs.httpclient.HttpProxyUtil;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import org.apache.http.client.methods.HttpPost;
Expand All @@ -18,7 +19,10 @@ public PostHogTracking(String endPoint) {

@Override
public void sendEventIgnoringFailure(Event event) {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
var clientBuilder = HttpClientBuilder.create();
HttpProxyUtil.configureProxy(clientBuilder);

try (CloseableHttpClient client = clientBuilder.build()) {
keshavbhatt marked this conversation as resolved.
Show resolved Hide resolved
client.execute(generateRequest(event));
} catch (Exception ignored) {
}
Expand Down
93 changes: 50 additions & 43 deletions store/src/main/java/com/zimbra/cs/httpclient/HttpProxyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

package com.zimbra.cs.httpclient;

import com.zimbra.common.account.ZAttrProvisioning;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.cs.account.Provisioning;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
Expand All @@ -16,53 +19,57 @@
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;

import com.zimbra.common.service.ServiceException;
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.cs.account.Provisioning;

public class HttpProxyUtil {

private static String sProxyUrl = null;
private static URI sProxyUri = null;
private static AuthScope sProxyAuthScope = null;
private static UsernamePasswordCredentials sProxyCreds = null;
private HttpProxyUtil() {
throw new IllegalStateException("Utility class");
}

public static synchronized void configureProxy(HttpClientBuilder clientBuilder) {
try {
String url = Provisioning.getInstance().getLocalServer().getAttr(Provisioning.A_zimbraHttpProxyURL, null);
if (url == null) return;
public static synchronized void configureProxy(HttpClientBuilder clientBuilder) {
try {
final var httpProxyUrl = Provisioning.getInstance().getLocalServer()
.getAttr(ZAttrProvisioning.A_zimbraHttpProxyURL, null);
if (httpProxyUrl == null || httpProxyUrl.isEmpty()) {
ZimbraLog.misc.info("HttpProxyUtil.configureProxy 'zimbraHttpProxyURL' is null or empty, not using proxy.");
return;
}

// need to initializae all the statics
if (!url.equals(sProxyUrl)) {
sProxyUrl = url;
sProxyUri = new URI(url);
sProxyAuthScope = null;
sProxyCreds = null;
String userInfo = sProxyUri.getUserInfo();
if (userInfo != null) {
int i = userInfo.indexOf(':');
if (i != -1) {
sProxyAuthScope = new AuthScope(sProxyUri.getHost(), sProxyUri.getPort(), null);
sProxyCreds = new UsernamePasswordCredentials(userInfo.substring(0, i), userInfo.substring(i+1));
}
}
}
if (ZimbraLog.misc.isDebugEnabled()) {
ZimbraLog.misc.debug("setting proxy: "+url);
}
var uri = new URI(httpProxyUrl);
var proxyHost = uri.getHost();
var proxyPort = uri.getPort();

HttpHost proxy = new HttpHost(sProxyUri.getHost(), sProxyUri.getPort());
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
clientBuilder.setDefaultRequestConfig(config);
if (sProxyAuthScope != null && sProxyCreds != null) {
CredentialsProvider cred = new BasicCredentialsProvider();
cred.setCredentials(sProxyAuthScope, sProxyCreds);
clientBuilder.setDefaultCredentialsProvider(cred);
}
} catch (ServiceException | URISyntaxException e) {
ZimbraLog.misc.warn("Unable to configureProxy: "+e.getMessage(), e);
var userInfo = uri.getUserInfo();
String username = null;
String password = null;
if (userInfo != null) {
var credentials = userInfo.split(":");
if (credentials.length == 2) {
username = credentials[0];
password = credentials[1];
}
}

if (username != null && password != null) {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(proxyHost, proxyPort),
new UsernamePasswordCredentials(username, password)
);
clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}

var proxy = new HttpHost(proxyHost, proxyPort);
var config = RequestConfig.custom()
.setProxy(proxy)
.build();
clientBuilder.setDefaultRequestConfig(config);

if (ZimbraLog.misc.isDebugEnabled()) {
ZimbraLog.misc.debug("setting proxy: " + httpProxyUrl);
}

} catch (ServiceException | URISyntaxException | IllegalArgumentException e) {
ZimbraLog.misc.warn("Unable to configureProxy: " + e.getMessage(), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.cs.account.Account;
import com.zimbra.cs.account.AuthToken;
import com.zimbra.cs.httpclient.HttpProxyUtil;
import com.zimbra.cs.servlet.ZimbraServlet;
import com.zimbra.cs.util.AccountUtil;
import io.vavr.control.Try;
Expand Down Expand Up @@ -259,7 +258,6 @@ private Try<BlobResponseStore> getAttachment(AuthToken authToken, String message
() -> {
HttpClientBuilder clientBuilder =
ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
HttpProxyUtil.configureProxy(clientBuilder);
HttpGet getRequest =
new HttpGet(getContentServletResourceUrl(authToken, messageId, part));
HttpClient client =
Expand Down
Loading