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

JENKINS-58753: Jenkins proxy settings support. #4

Merged
merged 1 commit into from Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/main/java/io/jenkins/plugins/zoom/ZoomNotifier.java
Expand Up @@ -27,6 +27,8 @@ public class ZoomNotifier extends Notifier {
@DataBoundSetter
private String authToken;
@DataBoundSetter
private boolean jenkinsProxyUsed;
@DataBoundSetter
private boolean notifyStart;
@DataBoundSetter
private boolean notifySuccess;
Expand Down Expand Up @@ -67,7 +69,7 @@ public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener){
listener.getLogger().println("---------------------- Prebuild ----------------------");
if(notifyStart){
MessageBuilder messageBuilder = new MessageBuilder(this, build, listener);
ZoomNotifyClient.notify(this.webhookUrl, this.authToken, messageBuilder.prebuild());
ZoomNotifyClient.notify(this.webhookUrl, this.authToken, this.jenkinsProxyUsed, messageBuilder.prebuild());
}
return super.prebuild(build, listener);
}
Expand All @@ -79,7 +81,7 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
listener.getLogger().println("---------------------- Perform ----------------------");
if(notifyPerform(build)){
MessageBuilder messageBuilder = new MessageBuilder(this, build, listener);
ZoomNotifyClient.notify(this.webhookUrl, this.authToken, messageBuilder.build());
ZoomNotifyClient.notify(this.webhookUrl, this.authToken, this.jenkinsProxyUsed, messageBuilder.build());
}
return true;
}
Expand Down Expand Up @@ -139,9 +141,10 @@ public String getDisplayName() {

@POST
public FormValidation doTestConnection(@QueryParameter("webhookUrl") final String webhookUrl,
@QueryParameter("authToken") final String authToken){
@QueryParameter("authToken") final String authToken,
@QueryParameter("jenkinsProxyUsed") final boolean jenkinsProxyUsed){
Jenkins.get().checkPermission(Permission.CONFIGURE);
if(ZoomNotifyClient.notify(webhookUrl, authToken, null)){
if(ZoomNotifyClient.notify(webhookUrl, authToken, jenkinsProxyUsed, null)){
return FormValidation.ok("Connection is ok");
}
return FormValidation.error("Connect failed");
Expand Down
123 changes: 106 additions & 17 deletions src/main/java/io/jenkins/plugins/zoom/ZoomNotifyClient.java
@@ -1,43 +1,46 @@
package io.jenkins.plugins.zoom;

import hudson.ProxyConfiguration;
import lombok.extern.slf4j.Slf4j;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.regex.Pattern;

@Slf4j
public class ZoomNotifyClient{

private static CloseableHttpClient httpclient = HttpClients.createDefault();
private static CloseableHttpClient defaultHttpClient = HttpClients.createDefault();

public static boolean notify(String url, String authToken, String message) {
public static boolean notify(String url, String authToken, boolean jenkinsProxyUsed, String message) {
boolean success = false;
log.info("Send notification to {}, message: {}", url, message);
if(url == null || url.isEmpty()){
log.error("Invalid URL: {}", url);
return success;
}
HttpPost httpPost = null;
try {
httpPost = new HttpPost(url);
httpPost.setHeader("content-type", "application/json;charset=UTF-8");
if(authToken != null && !authToken.isEmpty()){
httpPost.setHeader("Authorization", authToken);
}
if(message != null && !message.isEmpty()){
StringEntity stringEntity = new StringEntity(message, "UTF-8");
stringEntity.setContentEncoding("UTF-8");
httpPost.setEntity(stringEntity);
}
CloseableHttpResponse response = httpclient.execute(httpPost);
CloseableHttpResponse response = jenkinsProxyUsed
? notifyWithProxy(url, authToken, message)
: notifyNoProxy(url, authToken, message);
int responseCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
log.info("Response code: {}", responseCode);
Expand All @@ -51,12 +54,98 @@ public static boolean notify(String url, String authToken, String message) {
log.error("Invalid URL: {}", url);
} catch (IOException e2) {
log.error("Error posting to Zoom, url: {}, message: {}", url, message);
}
log.info("Notify success? {}", success);
return success;
}

private static CloseableHttpResponse notifyWithProxy(String url, String authToken, String message) throws IOException {
CloseableHttpResponse response = null;
ProxyConfiguration proxyConfig = null;
try {
proxyConfig = ProxyConfiguration.load();
} catch (IOException e) {
log.error("Error while loading the proxy configuration");
}
if(proxyConfig != null
&& proxyConfig.name != null && !proxyConfig.name.isEmpty()
&& proxyConfig.port > 0
&& !isNoProxyHost(url, proxyConfig.getNoProxyHostPatterns())
)
{
HttpClientBuilder builder = HttpClients.custom();
HttpHost proxyHost = new HttpHost(proxyConfig.name, proxyConfig.port);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxyHost);
builder.setRoutePlanner(routePlanner);
String username = proxyConfig.getUserName();
if(username != null && !username.isEmpty()) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxyConfig.name, proxyConfig.port),
new UsernamePasswordCredentials(username, proxyConfig.getPassword()));
builder.setDefaultCredentialsProvider(credsProvider);
}
CloseableHttpClient customHttpClient = builder.build();
try {
response = doPost(customHttpClient, url, authToken, message);
}
finally {
customHttpClient.close();
}
}
else {
response = notifyNoProxy(url, authToken, message);
}
return response;
}

private static CloseableHttpResponse notifyNoProxy(String url, String authToken, String message) throws IOException {
CloseableHttpResponse response = doPost(defaultHttpClient, url, authToken, message);
return response;
}

private static CloseableHttpResponse doPost(CloseableHttpClient httpClient, String url, String authToken, String message) throws IOException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
httpPost = decoratePost(new HttpPost(url), authToken, message);
response = httpClient.execute(httpPost);
} finally {
if(httpPost != null){
httpPost.releaseConnection();
}
}
log.info("Notify success? {}", success);
return success;
return response;
}

private static HttpPost decoratePost(HttpPost httpPost, String authToken, String message) {
httpPost.setHeader("content-type", "application/json;charset=UTF-8");
if(authToken != null && !authToken.isEmpty()){
httpPost.setHeader("Authorization", authToken);
}
if(message != null && !message.isEmpty()){
StringEntity stringEntity = new StringEntity(message, "UTF-8");
stringEntity.setContentEncoding("UTF-8");
httpPost.setEntity(stringEntity);
}
return httpPost;
}

private static boolean isNoProxyHost(String url, List<Pattern> noProxyHostPatterns) {
boolean result = false;
try {
String host = new URL(url).getHost();
for(Pattern pattern : noProxyHostPatterns) {
if(pattern.matcher(host).matches()) {
result = true;
break;
}
}
}
catch(MalformedURLException e) {
log.error("Invalid URL: {}", url);
}
return result;
}

}
Expand Up @@ -28,6 +28,8 @@ public class ZoomSendStep extends Step {
@DataBoundSetter
private String authToken;
@DataBoundSetter
private boolean jenkinsProxyUsed;
@DataBoundSetter
private String message;

@DataBoundConstructor
Expand Down Expand Up @@ -58,7 +60,7 @@ protected Object run() throws Exception {
TaskListener listener = getContext().get(TaskListener.class);
MessageBuilder messageBuilder = new MessageBuilder(null, run, listener);
String msg = messageBuilder.buildPipeMsg(this.step.getMessage());
ZoomNotifyClient.notify(this.step.getWebhookUrl(), this.step.getAuthToken(), msg);
ZoomNotifyClient.notify(this.step.getWebhookUrl(), this.step.getAuthToken(), this.step.isJenkinsProxyUsed(), msg);
return null;
}
}
Expand All @@ -83,9 +85,10 @@ public String getDisplayName() {

@POST
public FormValidation doTestConnection(@QueryParameter("webhookUrl") final String webhookUrl,
@QueryParameter("authToken") final String authToken){
@QueryParameter("authToken") final String authToken,
@QueryParameter("jenkinsProxyUsed") final boolean jenkinsProxyUsed){
Jenkins.get().checkPermission(Permission.CONFIGURE);
if(ZoomNotifyClient.notify(webhookUrl, authToken, null)){
if(ZoomNotifyClient.notify(webhookUrl, authToken, jenkinsProxyUsed, null)){
return FormValidation.ok("Connection is ok");
}
return FormValidation.error("Connect failed");
Expand Down
Expand Up @@ -6,10 +6,13 @@
<f:entry title="Token" help="/plugin/zoom/token.html">
<f:textbox field="authToken" />
</f:entry>
<f:entry field="jenkinsProxyUsed" title="Use Jenkins proxy settings" help="/plugin/zoom/jenkinsProxy.html">
<f:checkbox default="true" />
</f:entry>

<f:validateButton
title="${%Test Connection}" progress="${%Testing...}"
method="testConnection" with="webhookUrl,authToken"/>
method="testConnection" with="webhookUrl,authToken,jenkinsProxyUsed"/>

<f:advanced>
<f:entry field="notifyStart" title="Notify Build Start" help="/plugin/zoom/notify-start.html">
Expand Down
Expand Up @@ -7,13 +7,16 @@
<f:entry title="Token" help="/plugin/zoom/token.html">
<f:textbox field="authToken" />
</f:entry>
<f:entry field="jenkinsProxyUsed" title="Use Jenkins proxy settings" help="/plugin/zoom/jenkinsProxy.html">
<f:checkbox default="true" />
</f:entry>
<f:entry title="Message">
<f:textbox field="message" />
</f:entry>

<f:validateButton
title="${%Test Connection}" progress="${%Testing...}"
method="testConnection" with="webhookUrl,authToken"/>
method="testConnection" with="webhookUrl,authToken,jenkinsProxyUsed"/>


</j:jelly>
3 changes: 3 additions & 0 deletions src/main/webapp/jenkinsProxy.html
@@ -0,0 +1,3 @@
<div>
<p>Whether to use Jenkins proxy settings.</p>
</div>