Skip to content

Commit

Permalink
Add UI to configure short lived token expiry
Browse files Browse the repository at this point in the history
  • Loading branch information
alextu committed Apr 10, 2024
1 parent e1b12b3 commit 3cc404b
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ public void buildEnvironmentFor(@Nonnull Run run, @Nonnull EnvVars envs, @Nonnul
Secret shortLivedToken = null;
DevelocityLogger logger = new DevelocityLogger(listener);
if (secretKey != null && DevelocityAccessKey.isValid(secretKey.getPlainText())) {
shortLivedToken = tokenClient.get(InjectionConfig.get().getServer(), DevelocityAccessKey.parse(secretKey.getPlainText()))
shortLivedToken = tokenClient.get(InjectionConfig.get().getServer(),
DevelocityAccessKey.parse(secretKey.getPlainText()),
InjectionConfig.get().getShortLivedTokenExpiry())
.map(k -> Secret.fromString(k.getRawAccessKey()))
.orElse(null);
} else {
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import hudson.util.VersionNumber;
import jenkins.model.GlobalConfiguration;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundSetter;
Expand Down Expand Up @@ -54,6 +55,7 @@ public class InjectionConfig extends GlobalConfiguration {
private String server;
private boolean allowUntrusted;
private Secret accessKey;
private Integer shortLivedTokenExpiry;

private String gradlePluginVersion;
private String ccudPluginVersion;
Expand Down Expand Up @@ -154,6 +156,16 @@ public void setAccessKey(Secret accessKey) {
}
}

@CheckForNull
public Integer getShortLivedTokenExpiry() {
return shortLivedTokenExpiry;
}

@DataBoundSetter
public void setShortLivedTokenExpiry(Integer shortLivedTokenExpiry) {
this.shortLivedTokenExpiry = shortLivedTokenExpiry;
}

@CheckForNull
public String getGradlePluginRepositoryUsername() {
return gradlePluginRepositoryUsername;
Expand Down Expand Up @@ -401,6 +413,19 @@ public FormValidation doCheckAccessKey(@QueryParameter String value) {
: FormValidation.error(Messages.InjectionConfig_InvalidAccessKey());
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckShortLivedTokenExpiry(@QueryParameter String value) {
String shortLivedTokenExpiry = Util.fixEmptyAndTrim(value);
if (shortLivedTokenExpiry == null) {
return FormValidation.ok();
}

return StringUtils.isNumeric(shortLivedTokenExpiry) && new Integer(shortLivedTokenExpiry) <= 24
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidShortLivedTokenExpiry());
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckMavenExtensionCustomCoordinates(@QueryParameter String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ public ShortLivedTokenClient() {
}

@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
public Optional<DevelocityAccessKey> get(String server, DevelocityAccessKey accessKey) {
public Optional<DevelocityAccessKey> get(String server, DevelocityAccessKey accessKey, Integer expiry) {
String url = normalize(server) + "api/auth/token";
if (expiry != null) {
url = url + "?expiry=" + expiry;
}

Request request = new Request.Builder()
.url(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ InjectionConfig.Required=Required.
InjectionConfig.InvalidUrl=Not a valid URL.
InjectionConfig.InvalidVersion=Not a valid version.
InjectionConfig.InvalidAccessKey=Not a valid access key.
InjectionConfig.InvalidShortLivedTokenExpiry=Should be a integer between 1 and 24.

InjectionConfig.InvalidMavenExtensionCustomCoordinates=Not a valid Maven groupId:artifactId(:version).
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
</div>
<f:password/>
</f:entry>
<f:entry title="${%Develocity short-lived access tokens expiry}" field="shortLivedTokenExpiry">
<f:textbox checkMethod="post"/>
</f:entry>
</f:section>

<f:section title="${%General settings}">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
The short-lived token expiry in hours. Default is 2 hours.
See <a href="https://docs.gradle.com/enterprise/api-manual/#short_lived_access_tokens">docs</a>.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class BuildScanEnvironmentContributorTest extends BaseJenkinsIntegrationTest {
config.setAccessKey(Secret.fromString(accessKey))
config.save()

shortLivedTokenClient.get(config.getServer(), DevelocityAccessKey.parse(accessKey)) >> Optional.of(DevelocityAccessKey.of('localhost', 'xyz'))
shortLivedTokenClient.get(config.getServer(), DevelocityAccessKey.parse(accessKey), null) >> Optional.of(DevelocityAccessKey.of('localhost', 'xyz'))

when:
buildScanEnvironmentContributor.buildEnvironmentFor(run, new EnvVars(), TaskListener.NULL)
Expand Down Expand Up @@ -126,7 +126,7 @@ class BuildScanEnvironmentContributorTest extends BaseJenkinsIntegrationTest {
config.setGradlePluginRepositoryPassword(Secret.fromString("foo"))
config.save()

shortLivedTokenClient.get(config.getServer(), DevelocityAccessKey.parse(accessKey)) >> Optional.of(DevelocityAccessKey.of('localhost', 'xyz'))
shortLivedTokenClient.get(config.getServer(), DevelocityAccessKey.parse(accessKey), null) >> Optional.of(DevelocityAccessKey.of('localhost', 'xyz'))


when:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,36 @@ class ShortLivedTokenClientTest extends Specification {
given:
def mockDevelocity = GroovyEmbeddedApp.of {
handlers {
post("/api/auth/token") {
post("api/auth/token") {
response.status(200)
response.send('some-token')
}
}
}

when:
def token = new ShortLivedTokenClient().get(mockDevelocity.address.toString(), DevelocityAccessKey.parse('localhost=xyz'))
def token = new ShortLivedTokenClient().get(mockDevelocity.address.toString(), DevelocityAccessKey.parse('localhost=xyz'), null)

then:
token.get().key == 'some-token'
token.get().hostname == mockDevelocity.address.host
}

def "get token with expiry"() {
given:
def mockDevelocity = GroovyEmbeddedApp.of {
handlers {
post("api/auth/token") {
if (request.queryParams.get('expiry') == '3') {
response.status(200)
response.send('some-token')
}
}
}
}

when:
def token = new ShortLivedTokenClient().get(mockDevelocity.address.toString(), DevelocityAccessKey.parse('localhost=xyz'), 3)

then:
token.get().key == 'some-token'
Expand All @@ -29,23 +50,23 @@ class ShortLivedTokenClientTest extends Specification {
given:
def mockDevelocity = GroovyEmbeddedApp.of {
handlers {
post("/api/auth/token") {
post("api/auth/token") {
response.status(401)
response.send('{"status":401,"type":"urn:gradle:develocity:api:problems:client-error","title":"Something was wrong with the request."}')
}
}
}

when:
def token = new ShortLivedTokenClient().get(mockDevelocity.address.toString(), DevelocityAccessKey.parse('localhost=xyz'))
def token = new ShortLivedTokenClient().get(mockDevelocity.address.toString(), DevelocityAccessKey.parse('localhost=xyz'), null)

then:
!token.isPresent()
}

def "get token sever fails with exception"() {
when:
def token = new ShortLivedTokenClient().get('http://localhost:8888', DevelocityAccessKey.parse('localhost=xyz'))
def token = new ShortLivedTokenClient().get('http://localhost:8888', DevelocityAccessKey.parse('localhost=xyz'), null)

then:
!token.isPresent()
Expand Down

0 comments on commit 3cc404b

Please sign in to comment.