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/Support for local plugin proxy #277

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .README/globalconfig.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Plugin is used to send actionable messages in [Outlook](http://outlook.com), [Of

#### Global configuration values used as default in jobs

![GlobalConfigurationDefault](.README/globalconfigdefault.png?raw=true)
![GlobalConfiguratio![img.png](.README/globalconfig.png)nDefault](.README/globalconfigdefault.png?raw=true)

### Microsoft Teams

Expand Down
16 changes: 13 additions & 3 deletions src/main/java/jenkins/plugins/office365connector/HttpWorker.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
*/
package jenkins.plugins.office365connector;

import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -43,17 +42,20 @@ public class HttpWorker implements Runnable {

private final PrintStream logger;

private final Proxy pluginProxy;

private final String url;
private final String data;
private final int timeout;

private static final int RETRIES = 3;

public HttpWorker(String url, String data, int timeout, PrintStream logger) {
public HttpWorker(String url, String data, int timeout, PrintStream logger, Proxy pluginProxy) {
this.url = url;
this.data = data;
this.timeout = timeout;
this.logger = logger;
this.pluginProxy = pluginProxy;
}

/**
Expand Down Expand Up @@ -92,7 +94,7 @@ public void run() {
} else {
success = true;
}
} catch (IOException e) {
} catch (Exception e) {
rockleez marked this conversation as resolved.
Show resolved Hide resolved
log("Failed to post data to webhook - %s", url);
e.printStackTrace(logger);
} finally {
Expand All @@ -105,8 +107,16 @@ public void run() {
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
Jenkins jenkins = Jenkins.get();
if (pluginProxy.proxyConfigured()) {
client.getHostConfiguration().setProxy(pluginProxy.getIp(), pluginProxy.getPort());
if (StringUtils.isNotBlank(pluginProxy.getUsername())) {
client.getState().setProxyCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(pluginProxy.getUsername(), pluginProxy.getPassword()));
}
}
if (jenkins != null) {
ProxyConfiguration proxy = jenkins.proxy;
// Check job proxy first
if (proxy != null) {
List<Pattern> noHostProxyPatterns = proxy.getNoProxyHostPatterns();
if (!isNoProxyHost(this.url, noHostProxyPatterns)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private void executeWorker(Webhook webhook, Card card) {
try {
String url = run.getEnvironment(taskListener).expand(webhook.getUrl());
String data = gson.toJson(card);
HttpWorker worker = new HttpWorker(url, data, webhook.getTimeout(), taskListener.getLogger());
HttpWorker worker = new HttpWorker(url, data, webhook.getTimeout(), taskListener.getLogger(), webhook.getPluginProxy());
worker.submit();
} catch (IOException | InterruptedException | RejectedExecutionException e) {
log(String.format("Failed to notify webhook: %s", webhook.getName()));
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/jenkins/plugins/office365connector/Proxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package jenkins.plugins.office365connector;

import org.apache.commons.lang.StringUtils;

public class Proxy {

private String ip;
private Integer port;
private String username;
private String password;


public Proxy(String ip, Integer port, String username, String password) {
this.ip = ip;
this.port = port;
this.username = username;
this.password = password;
}

public String getIp() {
return ip;
}

public void setIp(String ip) {
this.ip = ip;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Boolean proxyConfigured() {
return (!StringUtils.isEmpty(this.ip) && !StringUtils.isEmpty(String.valueOf(this.port)));
rockleez marked this conversation as resolved.
Show resolved Hide resolved
}
}
55 changes: 55 additions & 0 deletions src/main/java/jenkins/plugins/office365connector/Webhook.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public class Webhook extends AbstractDescribableImpl<Webhook> {

private int timeout;

private Proxy pluginProxy;

private List<Macro> macros = Collections.emptyList();

private List<FactDefinition> factDefinitions = Collections.emptyList();
Expand All @@ -62,6 +64,9 @@ public DescriptorImpl getDescriptor() {
@DataBoundConstructor
public Webhook(String url) {
this.url = StringUtils.isEmpty(url) ? getDescriptor().getGlobalUrl() : url;

DescriptorImpl globalConfig = getDescriptor();
this.setProxyPluginConfiguration(globalConfig.getIp(), globalConfig.getPort(), globalConfig.getUsername(), globalConfig.getPassword());
}

public String getUrl() {
Expand All @@ -72,6 +77,14 @@ public String getName() {
return Util.fixEmptyAndTrim(StringUtils.isEmpty(name) ? getDescriptor().getGlobalName() : name);
}

public Proxy getPluginProxy() {
return this.pluginProxy;
}

public void setProxyPluginConfiguration(String proxyIp, Integer proxyPort, String proxyUsername, String proxyPassword) {
this.pluginProxy = new Proxy(proxyIp, proxyPort, proxyUsername, proxyPassword);
}

@DataBoundSetter
public void setName(String name) {
this.name = Util.fixEmptyAndTrim(name);
Expand Down Expand Up @@ -183,6 +196,12 @@ public static class DescriptorImpl extends Descriptor<Webhook> {
private String globalUrl;
private String globalName;

private String ip;
private String username;
rockleez marked this conversation as resolved.
Show resolved Hide resolved
private String password;

private Integer port;

public DescriptorImpl() {
load();
}
Expand All @@ -193,6 +212,42 @@ public String getDisplayName() {
return "Webhook";
}

public String getIp() {
return ip;
}

@DataBoundSetter
public void setIp(String ip) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IP or address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settled on using the term host

this.ip = ip;
rockleez marked this conversation as resolved.
Show resolved Hide resolved
}

public String getUsername() {
return username;
}

@DataBoundSetter
public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

@DataBoundSetter
public void setPassword(String password) {
this.password = password;
}

public Integer getPort() {
return port;
}

@DataBoundSetter
public void setPort(Integer port) {
this.port = port;
}

public int getDefaultTimeout() {
return Webhook.DEFAULT_TIMEOUT;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
This section defines for which build statuses the notification is sent.
</f:description>

<f:entry title="Notify Build Start" field="startNotification">
<f:entry title="Notify Build Start" field="startNotification" >
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<f:checkbox/>
</f:entry>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,25 @@
<f:entry title="Name" field="globalName">
<f:textbox/>
</f:entry>
<f:advanced>
<f:section title="Proxy Config">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<f:description>
This section defines the Office365Connector proxy settings that will apply to all webhook notifications. This
proxy configuration will be prioritized over the Jenkins global proxy config
rockleez marked this conversation as resolved.
Show resolved Hide resolved
</f:description>
<f:entry title="IP" field="ip">
<f:textbox/>
</f:entry>
<f:entry title="Port" field="port">
<f:textbox/>
</f:entry>
<f:entry title="Username" field="username">
<f:textbox/>
</f:entry>
<f:entry title="Password" field="password">
<f:password/>
</f:entry>
</f:section>
</f:advanced>
</f:section>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">The IP address of the proxy server</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the proxy.local.dev be valid value It does not look like IP address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the description

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">This field works in conjunction with the ip field to specify the HTTP proxy port.</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">This field works in conjunction with the proxy server field to specify the username used to authenticate with the proxy.</div>
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ public void setUp() {
}

@Test
public void HttpWorker_getHttpClient_NoProxy() throws NoSuchMethodException {
public void HttpWorker_getHttpClient_NoJenkinsProxy() throws NoSuchMethodException {

// given
// from @Before
HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out);
Proxy thisPluginProxy = new Proxy(null, null, null, null);
HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy);
Method method = HttpWorker.class.getDeclaredMethod("getHttpClient");
method.setAccessible(true);

Expand All @@ -50,15 +51,16 @@ public void HttpWorker_getHttpClient_NoProxy() throws NoSuchMethodException {
}

@Test
public void HttpWorker_getHttpClient_Proxy() throws NoSuchMethodException {
public void HttpWorker_getHttpClient_JenkinsProxy() throws NoSuchMethodException {

// given
// from @Before
Proxy thisPluginProxy = new Proxy(null, null, null, null);
Jenkins jenkins = Jenkins.get();
ProxyConfiguration proxyConfiguration = new ProxyConfiguration("name", 123, null, null, "*mockwebsite.com*");
jenkins.proxy = proxyConfiguration;

HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out);
HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy);
Method method = HttpWorker.class.getDeclaredMethod("getHttpClient");
method.setAccessible(true);

Expand All @@ -71,15 +73,16 @@ public void HttpWorker_getHttpClient_Proxy() throws NoSuchMethodException {
}

@Test
public void HttpWorker_getHttpClient_Proxy_Ignored() throws NoSuchMethodException {
public void HttpWorker_getHttpClient_JenkinsProxy_Ignored() throws NoSuchMethodException {

// given
// from @Before
Proxy thisPluginProxy = new Proxy(null, null, null, null);
Jenkins jenkins = Jenkins.get();
ProxyConfiguration proxyConfiguration = new ProxyConfiguration("name", 123, null, null, "*mockwebsite.com*");
jenkins.proxy = proxyConfiguration;

HttpWorker httpWorker = new HttpWorker("http://mockwebsite.com", "{}", 30, System.out);
HttpWorker httpWorker = new HttpWorker("http://mockwebsite.com", "{}", 30, System.out, thisPluginProxy);
Method method = HttpWorker.class.getDeclaredMethod("getHttpClient");
method.setAccessible(true);

Expand All @@ -90,4 +93,22 @@ public void HttpWorker_getHttpClient_Proxy_Ignored() throws NoSuchMethodExceptio
assertThat(httpClient.getHostConfiguration().getProxyHost()).isNull();
assertThat(httpClient.getHostConfiguration().getProxyPort()).isEqualTo(-1);
}
}

@Test
public void HttpWorker_getHttpClient_PluginProxy() throws NoSuchMethodException {

// given
// from @Before
Proxy thisPluginProxy = new Proxy("10.0.0.1", 12345, null, null);
HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy);
Method method = HttpWorker.class.getDeclaredMethod("getHttpClient");
method.setAccessible(true);

// when
HttpClient httpClient = (HttpClient) ReflectionUtils.invokeMethod(method, httpWorker);

// then
assertThat(httpClient.getHostConfiguration().getProxyHost()).isEqualTo(thisPluginProxy.getIp());
assertThat(httpClient.getHostConfiguration().getProxyPort()).isEqualTo(thisPluginProxy.getPort());
}
}
49 changes: 49 additions & 0 deletions src/test/java/jenkins/plugins/office365connector/ProxyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package jenkins.plugins.office365connector;

import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class ProxyTest {

private Proxy proxyTest;
private Proxy proxyTestNoCredentials;

@Before
public void setUp() {
proxyTest = new Proxy("10.0.0.1", 65654, "myUsername", "myPassword");
proxyTestNoCredentials = new Proxy("10.0.0.1", 65654, null, null);
}

@Test
public void getIp() {
assertThat("10.0.0.1").isEqualTo(proxyTest.getIp());
}

@Test
public void getPort() {
assertThat(65654).isEqualTo(proxyTest.getPort());
}

@Test
public void getUsername() {
assertThat("myUsername").isEqualTo(proxyTest.getUsername());
}

@Test
public void getPassword() {
assertThat("myPassword").isEqualTo(proxyTest.getPassword());
}

@Test
public void proxyConfigured_True() {
assertThat(proxyTest.proxyConfigured().equals(true));
}

@Test
public void proxyConfigured_False() {
assertThat(proxyTest.proxyConfigured().equals(false));
}
}
Loading