Skip to content

Commit 48fd590

Browse files
authored
Merge pull request jenkinsci#30 from rchougule/proxy_from_env_vars
Proxy from multiple sources with priority. Custom Local Identifier fix
2 parents d7f9772 + 9631d9a commit 48fd590

17 files changed

+338
-103
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ hs_err_pid*
2222
.project
2323
.settings/
2424
/bin/
25+
.vscode/

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<p align="center">
2+
<a href="https://browserstack.com"><img alt="BrowserStack Logo" src="https://d98b8t1nnulk5.cloudfront.net/production/images/layout/logo-invoice.svg"></a>
3+
</p>
4+
15
# Overview
26
[BrowserStack](https://browserstack.com) gives instant access to 2000+ real mobile devices and browsers that enables developers to test their websites and mobile applications without requiring to install or maintain an internal lab of virtual machines, devices, or emulators.
37

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<artifactId>browserstack-integration</artifactId>
13-
<version>1.1.10-SNAPSHOT</version>
13+
<version>1.2.0</version>
1414
<packaging>hpi</packaging>
1515

1616
<name>BrowserStack</name>
@@ -150,13 +150,13 @@
150150
<dependency>
151151
<groupId>com.browserstack</groupId>
152152
<artifactId>automate-client-java</artifactId>
153-
<version>0.6</version>
153+
<version>0.7</version>
154154
</dependency>
155155

156156
<dependency>
157157
<groupId>com.browserstack</groupId>
158158
<artifactId>browserstack-local-java</artifactId>
159-
<version>1.0.3</version>
159+
<version>1.0.6</version>
160160
</dependency>
161161

162162
<dependency>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.browserstack.automate.ci.common.clienthandler;
2+
3+
import com.browserstack.appautomate.AppAutomateClient;
4+
import com.browserstack.automate.AutomateClient;
5+
import com.browserstack.automate.ci.common.enums.ProjectType;
6+
import com.browserstack.automate.ci.common.proxysettings.JenkinsProxySettings;
7+
import com.browserstack.client.BrowserStackClient;
8+
9+
import javax.annotation.Nonnull;
10+
import javax.annotation.Nullable;
11+
import java.io.PrintStream;
12+
13+
public class ClientHandler {
14+
15+
/**
16+
* Returns BrowserStackClient based on Project, i.e Automate or App Automate.
17+
* Also decides and sets the proxy for the client
18+
* @param project ProjectType
19+
* @param username Username of BrowserStack
20+
* @param accessKey Access Key of BrowserStack
21+
* @param customProxy Custom Proxy String
22+
* @param logger Logger
23+
* @return BrowserStackClient
24+
*/
25+
public static BrowserStackClient getBrowserStackClient(@Nonnull final ProjectType project, @Nonnull final String username,
26+
@Nonnull final String accessKey, @Nullable final String customProxy,
27+
@Nullable final PrintStream logger) {
28+
BrowserStackClient client = decideAndGetClient(project, username, accessKey);
29+
30+
JenkinsProxySettings proxy;
31+
if (customProxy != null) {
32+
proxy = new JenkinsProxySettings(customProxy, logger);
33+
} else {
34+
proxy = new JenkinsProxySettings(logger);
35+
}
36+
37+
if (proxy.hasProxy()) {
38+
client.setProxy(proxy.getHost(), proxy.getPort(), proxy.getUsername(), proxy.getPassword());
39+
}
40+
41+
return client;
42+
}
43+
44+
/**
45+
* Initializes BrowserStack client based on project type
46+
* @param project ProjectType
47+
* @param username Username of BrowserStack
48+
* @param accessKey Access Key of BrowserStack
49+
* @return BrowserStackClient
50+
*/
51+
private static BrowserStackClient decideAndGetClient(@Nonnull final ProjectType project, @Nonnull final String username, @Nonnull final String accessKey) {
52+
if (project == ProjectType.APP_AUTOMATE) {
53+
return new AppAutomateClient(username, accessKey);
54+
}
55+
56+
return new AutomateClient(username, accessKey);
57+
}
58+
}
Lines changed: 184 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,219 @@
11
package com.browserstack.automate.ci.common.proxysettings;
22

3+
import com.browserstack.automate.ci.common.Tools;
34
import hudson.ProxyConfiguration;
5+
import hudson.Util;
46
import jenkins.model.Jenkins;
57

8+
import javax.annotation.Nonnull;
9+
import javax.annotation.Nullable;
10+
import java.io.PrintStream;
611
import java.net.InetSocketAddress;
712
import java.net.Proxy;
13+
import java.net.URL;
14+
15+
import static com.browserstack.automate.ci.common.logger.PluginLogger.log;
16+
import static com.browserstack.automate.ci.common.logger.PluginLogger.logDebug;
817

918
public class JenkinsProxySettings {
1019

1120
private static final ProxyConfiguration jenkinsProxy = Jenkins.getInstanceOrNull() != null ? Jenkins.getInstanceOrNull().proxy : null;
12-
private static final String protocol = "https";
13-
private static final String systemProxyHost = System.getProperty(protocol + ".proxyHost");
14-
private static final int systemProxyPort = Integer.parseInt(System.getProperty(protocol + ".proxyPort", "0"));
15-
private static final String systemProxyUser = System.getProperty(protocol + ".proxyUser");
16-
private static final String systemProxyPassword = System.getProperty(protocol + ".proxyPassword");
17-
18-
public static Proxy getJenkinsProxy() {
19-
if (hasSystemProxy()) {
20-
return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(systemProxyHost, systemProxyPort));
21-
}
2221

23-
if (jenkinsProxy == null) return null;
24-
final String proxyHost = jenkinsProxy.name;
25-
final int proxyPort = jenkinsProxy.port;
26-
return (proxyHost != null && proxyPort != 0) ? new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)) : null;
22+
private static final String jarProxyHost = System.getProperty("https.proxyHost");
23+
private static final int jarProxyPort = Integer.parseInt(System.getProperty("https.proxyPort", "443"));
24+
private static final String jarProxyUser = System.getProperty("https.proxyUser");
25+
private static final String jarProxyPassword = System.getProperty("https.proxyPassword");
26+
27+
private static final String systemHttpProxyEnv = System.getenv("http_proxy");
28+
private static final String systemHttpsProxyEnv = System.getenv("https_proxy");
29+
30+
private String finalProxyHost;
31+
private int finalProxyPort;
32+
private String finalProxyUsername;
33+
private String finalProxyPassword;
34+
35+
private boolean hasProxy;
36+
37+
private transient PrintStream logger;
38+
39+
/**
40+
* Constructor for JenkinsProxySettings with Priority for Custom Proxy
41+
*
42+
* @param customProxy Custom Proxy String
43+
* @param logger Logger
44+
*/
45+
public JenkinsProxySettings(@Nonnull final String customProxy, @Nullable PrintStream logger) {
46+
this.logger = logger;
47+
decideJenkinsProxy(customProxy);
2748
}
2849

29-
public static String getHost() {
30-
if (hasSystemProxy()) {
31-
return systemProxyHost;
32-
}
50+
/**
51+
* Constructor for JenkinsProxySettings
52+
*
53+
* @param logger Logger
54+
*/
55+
public JenkinsProxySettings(@Nullable PrintStream logger) {
56+
this.logger = logger;
57+
decideJenkinsProxy(null);
58+
}
3359

34-
if (jenkinsProxy == null) return null;
35-
return jenkinsProxy.name;
60+
/**
61+
* Verifies the format of the Proxy String
62+
*
63+
* @param proxyString String
64+
* @param proxyType Type/Source of Proxy
65+
* @return
66+
*/
67+
private URL verifyAndGetProxyURL(final String proxyString, final String proxyType) {
68+
try {
69+
final URL proxyUrl = new URL(proxyString);
70+
if (proxyUrl.getHost() != null && proxyUrl.getHost().length() == 0)
71+
throw new Error("Empty host in proxy");
72+
73+
String userInfo = proxyUrl.getUserInfo();
74+
if (userInfo != null) {
75+
if (userInfo.split(":").length != 2) {
76+
throw new Error("Invalid authentication params in proxy");
77+
}
78+
}
79+
80+
return proxyUrl;
81+
} catch (Exception e) {
82+
if (logger != null)
83+
logDebug(logger, String.format("Invalid Proxy String: %s, Proxy Type: %s. Error: %s", proxyString, proxyType, e.toString()));
84+
return null;
85+
}
3686
}
3787

38-
public static int getPort() {
39-
if (hasSystemProxy()) {
40-
return systemProxyPort;
88+
/**
89+
* Decides Proxy for the Plugin. Priority:
90+
* 0. Custom Proxy passed as input
91+
* 1. `https_proxy` Environment Variable
92+
* 2. `http_proxy` Environment Variable
93+
* 3. Jenkins Proxy Configuration
94+
* 4. JAR Proxy arguments, i.e. `https.proxyHost` etc.
95+
*
96+
* @param customProxyString Custom Proxy String
97+
*/
98+
private void decideJenkinsProxy(final String customProxyString) {
99+
URL proxyUrl = null;
100+
101+
// Verifies the custom proxy string
102+
if (customProxyString != null) {
103+
proxyUrl = verifyAndGetProxyURL(customProxyString, "ENV_VAR");
41104
}
42105

43-
if (jenkinsProxy == null) return 0;
44-
return jenkinsProxy.port;
45-
}
106+
// Looks for System level `https_proxy`. If not, looks for `http_proxy`
107+
if (proxyUrl == null && getSystemProxyString() != null) {
108+
proxyUrl = verifyAndGetProxyURL(getSystemProxyString(), "SYSTEM_ENV_VAR");
109+
}
110+
111+
// Looks for Jenkins Proxy
112+
if (proxyUrl == null && jenkinsProxy != null) {
113+
this.finalProxyHost = jenkinsProxy.name;
114+
this.finalProxyPort = jenkinsProxy.port;
115+
116+
if (Util.fixEmpty(jenkinsProxy.getUserName()) != null && Util.fixEmpty(jenkinsProxy.getPassword()) != null) {
117+
this.finalProxyUsername = jenkinsProxy.getUserName();
118+
this.finalProxyPassword = jenkinsProxy.getPassword();
119+
}
120+
}
121+
122+
// Looks for JAR Proxy Arguments
123+
if (proxyUrl == null && this.finalProxyHost == null && jarProxyHost != null) {
124+
this.finalProxyHost = jarProxyHost;
125+
this.finalProxyPort = jarProxyPort;
126+
127+
if (Util.fixEmpty(jarProxyUser) != null && Util.fixEmpty(jarProxyPassword) != null) {
128+
this.finalProxyUsername = jarProxyUser;
129+
this.finalProxyPassword = jarProxyPassword;
130+
}
131+
}
132+
133+
// Utilises the proxyUrl set by Env Vars if Jenkins & Jar Proxy are absent
134+
if (proxyUrl != null) {
135+
this.finalProxyHost = proxyUrl.getHost();
136+
this.finalProxyPort = proxyUrl.getPort() == -1 ? proxyUrl.getDefaultPort() : proxyUrl.getPort();
137+
138+
final String userInfo = proxyUrl.getUserInfo();
46139

47-
public static String getUsername() {
48-
if (hasSystemProxy() && systemProxyUser != null && systemProxyPassword != null) {
49-
return systemProxyUser;
140+
if (userInfo != null) {
141+
String[] userInfoArray = userInfo.split(":");
142+
this.finalProxyUsername = userInfoArray[0];
143+
this.finalProxyPassword = userInfoArray[1];
144+
}
50145
}
51146

52-
if (jenkinsProxy == null) return null;
53-
return jenkinsProxy.getUserName();
147+
// Logging and final boolean set
148+
if (this.finalProxyHost != null && this.finalProxyPort != 0) {
149+
this.hasProxy = true;
150+
151+
String proxyDataToLog = "Host: " + this.getHost() + ", Port: " + this.getPort();
152+
if (this.hasAuth()) {
153+
proxyDataToLog += ", Username: " + this.getUsername() + ", Password: " + Tools.maskString(this.getPassword());
154+
}
155+
156+
if (logger != null) log(logger, "Proxy Selected for BrowserStack Plugin: " + proxyDataToLog);
157+
} else {
158+
this.hasProxy = false;
159+
160+
if (logger != null) log(logger, "No Proxy Selected for BrowserStack Plugin");
161+
}
54162
}
55163

56-
public static String getPassword() {
57-
if (hasSystemProxy() && systemProxyUser != null && systemProxyPassword != null) {
58-
return systemProxyPassword;
164+
165+
/**
166+
* Returns the proxy string from System level env vars. Priority:
167+
* 1. `https_proxy`
168+
* 2. `http_proxy`
169+
* If no value exists, returns null
170+
*
171+
* @return String/null
172+
*/
173+
private String getSystemProxyString() {
174+
return systemHttpsProxyEnv == null ? systemHttpProxyEnv : systemHttpsProxyEnv;
175+
}
176+
177+
/**
178+
* Returns Jenkins proxy configuration in Proxy object
179+
*
180+
* @return Proxy object
181+
*/
182+
public Proxy getJenkinsProxy() {
183+
if (this.hasProxy()) {
184+
return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.finalProxyHost, this.finalProxyPort));
59185
}
60186

61-
if (jenkinsProxy == null) return null;
62-
return jenkinsProxy.getPassword();
187+
return Proxy.NO_PROXY;
188+
}
189+
190+
public String getHost() {
191+
return this.finalProxyHost;
192+
}
193+
194+
public int getPort() {
195+
return this.finalProxyPort;
63196
}
64197

65-
public static ProxyConfiguration getProxyConfig() {
66-
return jenkinsProxy;
198+
public String getUsername() {
199+
if (this.finalProxyUsername != null && this.finalProxyUsername.length() != 0)
200+
return this.finalProxyUsername;
201+
202+
return null;
67203
}
68204

69-
public static boolean hasProxy() {
70-
return getHost() != null && getPort() != 0;
205+
public String getPassword() {
206+
if (this.finalProxyPassword != null && this.finalProxyPassword.length() != 0)
207+
return this.finalProxyPassword;
208+
209+
return null;
71210
}
72211

73-
public static boolean hasSystemProxy() {
74-
return systemProxyHost != null && systemProxyPort != 0;
212+
public boolean hasAuth() {
213+
return ((this.getUsername() != null) && (this.getPassword() != null));
75214
}
76215

216+
public boolean hasProxy() {
217+
return this.hasProxy;
218+
}
77219
}

0 commit comments

Comments
 (0)