Skip to content

Commit

Permalink
Add the option to retrieve credentials in the context of a Run
Browse files Browse the repository at this point in the history
  • Loading branch information
kneirinck committed Feb 14, 2024
1 parent 9bd65d0 commit ec1a025
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 1 deletion.
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,16 @@
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-rest-java-client-core</artifactId>
<version>5.2.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down
41 changes: 40 additions & 1 deletion src/main/java/org/jfrog/hudson/CredentialsConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jfrog.hudson;

import hudson.model.Item;
import hudson.model.Run;
import hudson.util.Secret;
import hudson.util.XStream2;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -91,6 +92,16 @@ public boolean isCredentialsProvided() {
private String provideUsername(Item item) {
return isUsingCredentialsPlugin() ? PluginsUtils.usernamePasswordCredentialsLookup(credentialsId, item).getUsername() : Secret.toString(username);
}

/**
* Not like getUsername this will return the username of the current Credentials mode of the system (legacy/credentials plugin) in the context of a Run
*
* @return the username that should be applied in this configuration
*/
private String provideUsername(Run run) {
return isUsingCredentialsPlugin() ? PluginsUtils.usernamePasswordCredentialsLookup(credentialsId, run).getUsername() : Secret.toString(username);
}

/**
* Not like getPassword this will return the password of the current Credentials mode of the system (legacy/credentials plugin)
*
Expand All @@ -100,7 +111,16 @@ private String providePassword(Item item) {
return isUsingCredentialsPlugin() ? PluginsUtils.usernamePasswordCredentialsLookup(credentialsId, item).getPassword() : Secret.toString(password);
}

public String provideAccessToken(Item item) {
/**
* Not like getPassword this will return the password of the current Credentials mode of the system (legacy/credentials plugin) in the context of a Run
*
* @return the password that should be applied in this configuration
*/
private String providePassword(Run run) {
return isUsingCredentialsPlugin() ? PluginsUtils.usernamePasswordCredentialsLookup(credentialsId, run).getPassword() : Secret.toString(password);
}

private String provideAccessToken(Item item) {
if (isUsingCredentialsPlugin()) {
StringCredentials accessTokenCredentials = PluginsUtils.accessTokenCredentialsLookup(credentialsId, item);
if (accessTokenCredentials != null) {
Expand All @@ -110,6 +130,16 @@ public String provideAccessToken(Item item) {
return StringUtils.EMPTY;
}

private String provideAccessToken(Run run) {
if (isUsingCredentialsPlugin()) {
StringCredentials accessTokenCredentials = PluginsUtils.accessTokenCredentialsLookup(credentialsId, run);
if (accessTokenCredentials != null) {
return accessTokenCredentials.getSecret().getPlainText();
}
}
return StringUtils.EMPTY;
}

public Credentials provideCredentials(Item item) {
String accessToken = provideAccessToken(item);
if (StringUtils.isNotEmpty(accessToken)) {
Expand All @@ -119,6 +149,15 @@ public Credentials provideCredentials(Item item) {
return new Credentials(provideUsername(item), providePassword(item));
}

public Credentials provideCredentials(Run run) {
String accessToken = provideAccessToken(run);
if (StringUtils.isNotEmpty(accessToken)) {
return new Credentials(accessToken);
}

return new Credentials(provideUsername(run), providePassword(run));
}

// NOTE: These getters are not part of the API, but used by Jenkins Jelly for displaying values on user interface
// This should not be used in order to retrieve credentials in the configuration - Use provideUsername, providePassword instead

Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/jfrog/hudson/util/plugins/PluginsUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.model.queue.Tasks;
import hudson.security.ACL;
import hudson.util.ListBoxModel;
Expand Down Expand Up @@ -87,13 +88,28 @@ public static Credentials usernamePasswordCredentialsLookup(String credentialsId
return Credentials.EMPTY_CREDENTIALS;
}

public static Credentials usernamePasswordCredentialsLookup(String credentialsId, Run run) {
UsernamePasswordCredentials usernamePasswordCredentials = CredentialsProvider.findCredentialById(
credentialsId, StandardUsernamePasswordCredentials.class, run);

if (usernamePasswordCredentials != null) {
return new Credentials(usernamePasswordCredentials.getUsername(),
usernamePasswordCredentials.getPassword().getPlainText());
}
return Credentials.EMPTY_CREDENTIALS;
}

public static StringCredentials accessTokenCredentialsLookup(String credentialsId, Item item) {
return CredentialsMatchers.firstOrNull(
lookupCredentials(StringCredentials.class, item),
CredentialsMatchers.withId(credentialsId)
);
}

public static StringCredentials accessTokenCredentialsLookup(String credentialsId, Run run) {
return CredentialsProvider.findCredentialById(credentialsId, StringCredentials.class, run);
}

/**
* Return job and Jenkins scoped credentials.
*
Expand Down
61 changes: 61 additions & 0 deletions src/test/java/org/jfrog/hudson/CredentialsConfigTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.jfrog.hudson;

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.common.IdCredentials;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import hudson.model.*;
import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import org.acegisecurity.Authentication;
import org.jfrog.hudson.util.Credentials;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.MockQueueItemAuthenticator;

import java.util.HashMap;
import java.util.Map;

public class CredentialsConfigTest {
@Rule
public JenkinsRule j = new JenkinsRule();

@Test
public void testProvideCredentialsForRun() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
MockAuthorizationStrategy auth = new MockAuthorizationStrategy()
.grant(Jenkins.READ).everywhere().to("alice", "bob")
.grant(Computer.BUILD).everywhere().to("alice", "bob")
// Item.CONFIGURE implies Credentials.USE_ITEM, which is what CredentialsProvider.findCredentialById
// uses when determining whether to include item-scope credentials in the search.
.grant(Item.CONFIGURE).everywhere().to("alice");
j.jenkins.setAuthorizationStrategy(auth);

String globalCredentialsId = "global-creds";
IdCredentials globalCredentials = new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL,
globalCredentialsId, "test-global-creds", "global-user", "global-password");
CredentialsProvider.lookupStores(j.jenkins).iterator().next().addCredentials(Domain.global(), globalCredentials);

FreeStyleProject p1 = j.createFreeStyleProject();
FreeStyleProject p2 = j.createFreeStyleProject();

Map<String, Authentication> jobsToAuths = new HashMap<>();
jobsToAuths.put(p1.getFullName(), User.getById("alice", true).impersonate());
jobsToAuths.put(p2.getFullName(), User.getById("bob", true).impersonate());
QueueItemAuthenticatorConfiguration.get().getAuthenticators().replace(new MockQueueItemAuthenticator(jobsToAuths));

FreeStyleBuild r1 = j.buildAndAssertSuccess(p1);
Credentials credentials1 = new CredentialsConfig("", "", globalCredentialsId).provideCredentials(r1);
Assert.assertEquals("Alice has Credentials.USE_ITEM and should be able to use the credential", "global-user", credentials1.getUsername());
Assert.assertEquals("global-password", credentials1.getPassword());

FreeStyleBuild r2 = j.buildAndAssertSuccess(p2);
Credentials credentials2 = new CredentialsConfig("", "", globalCredentialsId).provideCredentials(r2);
Assert.assertEquals("Bob does not have Credentials.USE_ITEM and should not be able to use the credential", "", credentials2.getUsername());
Assert.assertEquals("", credentials2.getPassword());
}
}

0 comments on commit ec1a025

Please sign in to comment.