-
Notifications
You must be signed in to change notification settings - Fork 414
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
Fix folder credential usage #541
Changes from all commits
d35f206
8d05af3
1c8d88e
7d3c7e9
a01335b
94811cd
4e071dc
8217e7c
2edbd9d
c63a66c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package jenkins.plugins.slack; | ||
|
||
import com.cloudbees.plugins.credentials.CredentialsMatcher; | ||
import com.cloudbees.plugins.credentials.CredentialsMatchers; | ||
import com.cloudbees.plugins.credentials.CredentialsProvider; | ||
import hudson.model.Item; | ||
import hudson.security.ACL; | ||
import jenkins.model.Jenkins; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.jenkinsci.plugins.plaincredentials.StringCredentials; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.NoSuchElementException; | ||
|
||
public class CredentialsObtainer { | ||
|
||
public static StringCredentials lookupCredentials(String credentialId) { | ||
List<StringCredentials> credentials = CredentialsProvider.lookupCredentials(StringCredentials.class, Jenkins.get(), ACL.SYSTEM, Collections.emptyList()); | ||
return getCredentialWithId(credentialId, credentials); | ||
} | ||
|
||
public static StringCredentials lookupCredentials(String credentialId, Item item) { | ||
List<StringCredentials> credentials = CredentialsProvider.lookupCredentials(StringCredentials.class, item, ACL.SYSTEM, Collections.emptyList()); | ||
return getCredentialWithId(credentialId, credentials); | ||
} | ||
|
||
/** | ||
* Attempts to obtain the credential with the providedId from the item's credential context, otherwise returns token | ||
* @param credentialId the id from the credential to be used | ||
* @param item the item with the context to obtain the credential from. | ||
* @param token the fallback token | ||
* @return the obtained token | ||
*/ | ||
public static String getTokenToUse(String credentialId, Item item, String token) { | ||
String response; | ||
if (StringUtils.isEmpty(credentialId)) { | ||
response = token; | ||
} else { | ||
StringCredentials credentials = lookupCredentials(StringUtils.trim(credentialId), item); | ||
if (credentials != null) { | ||
response = credentials.getSecret().getPlainText(); | ||
} else { | ||
response = token; | ||
} | ||
} | ||
if (StringUtils.isEmpty(response)) { | ||
throw new IllegalArgumentException("the token with the provided ID could not be found and no token was specified"); | ||
} | ||
return response; | ||
} | ||
|
||
private static StringCredentials getCredentialWithId(String credentialId, List<StringCredentials> credentials) { | ||
CredentialsMatcher matcher = CredentialsMatchers.withId(credentialId); | ||
return CredentialsMatchers.firstOrNull(credentials, matcher); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import com.cloudbees.plugins.credentials.CredentialsMatcher; | ||
import com.cloudbees.plugins.credentials.CredentialsMatchers; | ||
import hudson.ProxyConfiguration; | ||
import hudson.model.Item; | ||
import hudson.security.ACL; | ||
import jenkins.model.Jenkins; | ||
import jenkins.plugins.slack.logging.BuildKey; | ||
|
@@ -44,31 +45,67 @@ public class StandardSlackService implements SlackService { | |
private String host = "slack.com"; | ||
private String baseUrl; | ||
private String teamDomain; | ||
private String token; | ||
private String authTokenCredentialId; | ||
private boolean botUser; | ||
private String[] roomIds; | ||
private boolean replyBroadcast; | ||
private String responseString = null; | ||
private String responseString; | ||
private String populatedToken; | ||
|
||
/** | ||
* @deprecated use {@link #StandardSlackService(String, String, boolean, String, boolean, String)} instead} | ||
*/ | ||
@Deprecated | ||
public StandardSlackService(String baseUrl, String teamDomain, String authTokenCredentialId, boolean botUser, String roomId) { | ||
this(baseUrl, teamDomain, null, authTokenCredentialId, botUser, roomId, false); | ||
} | ||
|
||
/** | ||
* @deprecated use {@link #StandardSlackService(String, String, boolean, String, boolean, String)} instead} | ||
*/ | ||
@Deprecated | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll check this when I test the code out, but can you make sure that none of these constructors are called anymore internally to the codebase? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just had a look, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They're only used from tests. I'll adapt them. |
||
public StandardSlackService(String baseUrl, String teamDomain, String token, String authTokenCredentialId, boolean botUser, String roomId) { | ||
this(baseUrl, teamDomain, token, authTokenCredentialId, botUser, roomId, false); | ||
} | ||
|
||
/** | ||
* @deprecated use {@link #StandardSlackService(String, String, boolean, String, boolean, String)} instead} | ||
*/ | ||
@Deprecated | ||
public StandardSlackService(String baseUrl, String teamDomain, String token, String authTokenCredentialId, boolean botUser, String roomId, boolean replyBroadcast) { | ||
this(baseUrl, teamDomain, botUser, roomId, replyBroadcast); | ||
this.populatedToken = getTokenToUse(authTokenCredentialId, token); | ||
if (this.populatedToken == null) { | ||
throw new IllegalArgumentException("No slack token found, setup a secret text credential and configure it to be used"); | ||
} | ||
} | ||
|
||
/** | ||
* @param baseUrl the full url to use, this is an alternative to specifying teamDomain | ||
* @param teamDomain the teamDomain inside slack.com to use | ||
* @param botUser | ||
* @param roomId a semicolon separated list of rooms to notify | ||
* @param replyBroadcast | ||
* @param populatedToken a non-null token to use for authentication | ||
*/ | ||
public StandardSlackService(String baseUrl, String teamDomain, boolean botUser, String roomId, boolean replyBroadcast, String populatedToken) { | ||
this(baseUrl, teamDomain, botUser, roomId, replyBroadcast); | ||
if (populatedToken == null) { | ||
throw new IllegalArgumentException("No slack token found, setup a secret text credential and configure it to be used"); | ||
} | ||
this.populatedToken = populatedToken; | ||
} | ||
|
||
private StandardSlackService(String baseUrl, String teamDomain, boolean botUser, String roomId, boolean replyBroadcast) { | ||
super(); | ||
this.baseUrl = baseUrl; | ||
if(this.baseUrl != null && !this.baseUrl.isEmpty() && !this.baseUrl.endsWith("/")) { | ||
this.baseUrl += "/"; | ||
} | ||
this.teamDomain = teamDomain; | ||
this.token = token; | ||
this.authTokenCredentialId = StringUtils.trim(authTokenCredentialId); | ||
this.botUser = botUser; | ||
if (roomId == null) { | ||
throw new IllegalArgumentException("Project Channel or Slack User ID must be specified."); | ||
} | ||
this.roomIds = roomId.split("[,; ]+"); | ||
this.replyBroadcast = replyBroadcast; | ||
} | ||
|
@@ -120,12 +157,11 @@ public boolean publish(String message, JSONArray attachments, String color) { | |
roomId = splitThread[0]; | ||
threadTs = splitThread[1]; | ||
} | ||
|
||
//prepare post methods for both requests types | ||
if (!botUser || !StringUtils.isEmpty(baseUrl)) { | ||
url = "https://" + teamDomain + "." + host + "/services/hooks/jenkins-ci?token=" + getTokenToUse(); | ||
url = "https://" + teamDomain + "." + host + "/services/hooks/jenkins-ci?token=" + populatedToken; | ||
if (!StringUtils.isEmpty(baseUrl)) { | ||
url = baseUrl + getTokenToUse(); | ||
url = baseUrl + populatedToken; | ||
} | ||
post = new HttpPost(url); | ||
JSONObject json = new JSONObject(); | ||
|
@@ -139,7 +175,7 @@ public boolean publish(String message, JSONArray attachments, String color) { | |
|
||
nvps.add(new BasicNameValuePair("payload", json.toString())); | ||
} else { | ||
url = "https://slack.com/api/chat.postMessage?token=" + getTokenToUse() + | ||
url = "https://slack.com/api/chat.postMessage?token=" + populatedToken + | ||
"&channel=" + roomId.replace("#", "") + | ||
"&link_names=1" + | ||
"&as_user=true"; | ||
|
@@ -185,26 +221,19 @@ public boolean publish(String message, JSONArray attachments, String color) { | |
return result; | ||
} | ||
|
||
private String getTokenToUse() { | ||
if (authTokenCredentialId != null && !authTokenCredentialId.isEmpty()) { | ||
StringCredentials credentials = lookupCredentials(authTokenCredentialId); | ||
private String getTokenToUse(String authTokenCredentialId, String token) { | ||
if (!StringUtils.isEmpty(authTokenCredentialId)) { | ||
StringCredentials credentials = CredentialsObtainer.lookupCredentials(authTokenCredentialId); | ||
if (credentials != null) { | ||
logger.fine("Using Integration Token Credential ID."); | ||
return credentials.getSecret().getPlainText(); | ||
} | ||
} | ||
|
||
logger.fine("Using Integration Token."); | ||
|
||
return token; | ||
} | ||
|
||
private StringCredentials lookupCredentials(String credentialId) { | ||
List<StringCredentials> credentials = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(StringCredentials.class, Jenkins.get(), ACL.SYSTEM, Collections.emptyList()); | ||
CredentialsMatcher matcher = CredentialsMatchers.withId(credentialId); | ||
return CredentialsMatchers.firstOrNull(credentials, matcher); | ||
} | ||
|
||
protected CloseableHttpClient getHttpClient() { | ||
final HttpClientBuilder clientBuilder = HttpClients.custom(); | ||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this throw an exception if token is null please?
We get lots of issues falling through to the bottom because token and credential are both null
same on line 29
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All code paths on StandardSlackService should now throw an IllegalArgumentException if token is null.