Skip to content

Add cache for OAuth2 token to reduce the number of requests. #997

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

Merged
merged 1 commit into from
Mar 1, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,33 @@
package com.cloudbees.jenkins.plugins.bitbucket.impl.credentials;

import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketException;
import com.cloudbees.jenkins.plugins.bitbucket.client.Cache;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse;
import com.github.scribejava.core.model.OAuthConstants;
import com.github.scribejava.core.oauth.OAuth20Service;
import hudson.model.Descriptor.FormException;
import hudson.util.Secret;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import jenkins.util.SetContextClassLoader;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpRequest;

public class BitbucketOAuthAuthenticator implements BitbucketAuthenticator {
private static final Cache<String, OAuth2AccessToken> cacheToken = new Cache<>(5, TimeUnit.MINUTES);

private final String credentialsId;
private final String username;
private final Secret password;
private OAuth2AccessToken token;

/**
* Constructor.
Expand All @@ -60,18 +65,26 @@
}

private OAuth2AccessToken getToken() {
if (token == null) {
try (SetContextClassLoader cl = new SetContextClassLoader(this.getClass());
OAuth20Service service = new ServiceBuilder(username)
.apiSecret(Secret.toString(password))
.httpClientConfig(JDKHttpClientConfig.defaultConfig())
.build(BitbucketOAuth.instance())) {
token = service.getAccessTokenClientCredentialsGrant();
} catch (IOException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
try {
String plainSecret = Secret.toString(password);
String cacheKey = DigestUtils.md2Hex(StringUtils.join(new String[] { credentialsId, username, plainSecret }, '/'));
return cacheToken.get(cacheKey, () -> {
try (SetContextClassLoader cl = new SetContextClassLoader(this.getClass());
OAuth20Service service = new ServiceBuilder(username)
.apiSecret(plainSecret)
.httpClientConfig(JDKHttpClientConfig.defaultConfig())
.build(BitbucketOAuth.instance())) {
return service.getAccessTokenClientCredentialsGrant();
}
});
} catch (ExecutionException e) {
// unwrap exception
Throwable cause = e.getCause();
if (cause instanceof OAuth2AccessTokenErrorResponse oauthEx) {
throw new BitbucketException(oauthEx.getErrorDescription() + ". Please check configured OAuth credentials client id and secret are correct.", e);
}
throw new RuntimeException(cause);

Check warning on line 86 in src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketOAuthAuthenticator.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 69-86 are not covered by tests
}
return token;
}

/**
Expand Down