From edf430cb448189872c7b218f2357084009914258 Mon Sep 17 00:00:00 2001 From: Nikolas Falco Date: Tue, 5 Nov 2024 17:09:48 +0100 Subject: [PATCH] Update OAuth2 scribe dependency to the new scribejava (#900) --- pom.xml | 12 ++--- ...tbucketAccessTokenAuthenticatorSource.java | 2 +- ...tClientCertificateAuthenticatorSource.java | 2 +- .../api/credentials/BitbucketOAuth.java | 32 +++++------- .../BitbucketOAuthAuthenticator.java | 37 +++++++++---- .../BitbucketOAuthAuthenticatorSource.java | 6 ++- .../credentials/BitbucketOAuthService.java | 52 ------------------- 7 files changed, 47 insertions(+), 96 deletions(-) delete mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthService.java diff --git a/pom.xml b/pom.xml index 872dec277..519723f56 100644 --- a/pom.xml +++ b/pom.xml @@ -145,15 +145,9 @@ plain-credentials - org.scribe - scribe - 1.3.3 - - - commons-codec - commons-codec - - + com.github.scribejava + scribejava-httpclient-apache + 8.3.3 diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketAccessTokenAuthenticatorSource.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketAccessTokenAuthenticatorSource.java index 688f9f37f..750d36fee 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketAccessTokenAuthenticatorSource.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketAccessTokenAuthenticatorSource.java @@ -39,7 +39,7 @@ public BitbucketAccessTokenAuthenticator convert(@NonNull StringCredentials cred * @return whether this can authenticate given the context */ @Override - public boolean isFit(AuthenticationTokenContext ctx) { + protected boolean isFit(AuthenticationTokenContext ctx) { return ctx.mustHave(BitbucketAuthenticator.SCHEME, "https") && (ctx.mustHave(BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE, BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE_SERVER) || ctx.mustHave(BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE, BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE_CLOUD)); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketClientCertificateAuthenticatorSource.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketClientCertificateAuthenticatorSource.java index e95f54c69..b94ea013c 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketClientCertificateAuthenticatorSource.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketClientCertificateAuthenticatorSource.java @@ -63,7 +63,7 @@ public BitbucketClientCertificateAuthenticator convert(@NonNull StandardCertific * @return whether this can authenticate given the context */ @Override - public boolean isFit(AuthenticationTokenContext ctx) { + protected boolean isFit(AuthenticationTokenContext ctx) { return ctx.mustHave(BitbucketAuthenticator.SCHEME, "https") && ctx.mustHave(BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE, BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE_SERVER); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuth.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuth.java index c81c5eb9e..ebbc2a472 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuth.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuth.java @@ -1,37 +1,29 @@ package com.cloudbees.jenkins.plugins.bitbucket.api.credentials; -import org.scribe.builder.api.DefaultApi20; -import org.scribe.extractors.AccessTokenExtractor; -import org.scribe.extractors.JsonTokenExtractor; -import org.scribe.model.OAuthConfig; -import org.scribe.model.Verb; -import org.scribe.oauth.OAuthService; +import com.github.scribejava.core.builder.api.DefaultApi20; public class BitbucketOAuth extends DefaultApi20 { - public static final String OAUTH_ENDPOINT = "https://bitbucket.org/site/oauth2/"; + private static final String OAUTH_ENDPOINT = "https://bitbucket.org/site/oauth2/"; - @Override - public String getAccessTokenEndpoint() { - return OAUTH_ENDPOINT + "access_token"; + protected BitbucketOAuth() { } - @Override - public String getAuthorizationUrl(OAuthConfig config) { - return OAUTH_ENDPOINT + "authorize"; + private static class InstanceHolder { + private static final BitbucketOAuth INSTANCE = new BitbucketOAuth(); } - @Override - public Verb getAccessTokenVerb() { - return Verb.POST; + public static BitbucketOAuth instance() { + return InstanceHolder.INSTANCE; } @Override - public AccessTokenExtractor getAccessTokenExtractor() { - return new JsonTokenExtractor(); + public String getAccessTokenEndpoint() { + return OAUTH_ENDPOINT + "access_token"; } @Override - public OAuthService createService(OAuthConfig config) { - return new BitbucketOAuthService(this, config); + protected String getAuthorizationBaseUrl() { + return OAUTH_ENDPOINT + "authorize"; } + } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticator.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticator.java index d122139d6..0c0283c7d 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticator.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticator.java @@ -5,30 +5,45 @@ 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.HttpClient; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.oauth.OAuth20Service; +import com.github.scribejava.httpclient.apache.ApacheHttpClientConfig; +import com.github.scribejava.httpclient.apache.ApacheProvider; import hudson.model.Descriptor.FormException; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import jenkins.authentication.tokens.api.AuthenticationTokenException; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpRequest; -import org.scribe.model.OAuthConfig; -import org.scribe.model.OAuthConstants; -import org.scribe.model.Token; public class BitbucketOAuthAuthenticator extends BitbucketAuthenticator { - private Token token; + private OAuth2AccessToken token; /** * Constructor. * * @param credentials the key/pass that will be used + * @throws AuthenticationTokenException */ - public BitbucketOAuthAuthenticator(StandardUsernamePasswordCredentials credentials) { + public BitbucketOAuthAuthenticator(StandardUsernamePasswordCredentials credentials) throws AuthenticationTokenException { super(credentials); - OAuthConfig config = new OAuthConfig(credentials.getUsername(), credentials.getPassword().getPlainText()); + HttpClient httpClient = new ApacheProvider().createClient(ApacheHttpClientConfig.defaultConfig()); + OAuth20Service service = new ServiceBuilder(credentials.getUsername()) + .apiSecret(credentials.getPassword().getPlainText()) + .httpClient(httpClient) + // .httpClientConfig(ApacheHttpClientConfig.defaultConfig()) the ServiceLoader does not work well with Jenkins plugin classloader + .build(BitbucketOAuth.instance()); - BitbucketOAuthService OAuthService = (BitbucketOAuthService) new BitbucketOAuth().createService(config); - - token = OAuthService.getAccessToken(OAuthConstants.EMPTY_TOKEN, null); + try { + token = service.getAccessTokenClientCredentialsGrant(); + } catch (IOException | InterruptedException | ExecutionException e) { + throw new AuthenticationTokenException(e); + } } /** @@ -36,14 +51,14 @@ public BitbucketOAuthAuthenticator(StandardUsernamePasswordCredentials credentia */ @Override public void configureRequest(HttpRequest request) { - request.addHeader(OAuthConstants.HEADER, "Bearer " + this.token.getToken()); + request.addHeader(OAuthConstants.HEADER, "Bearer " + this.token.getAccessToken()); } @Override public StandardUsernameCredentials getCredentialsForSCM() { try { return new UsernamePasswordCredentialsImpl( - CredentialsScope.GLOBAL, getId(), null, StringUtils.EMPTY, token.getToken()); + CredentialsScope.GLOBAL, getId(), null, StringUtils.EMPTY, token.getAccessToken()); } catch (FormException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticatorSource.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticatorSource.java index 1ed1edff6..d41a3eaee 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticatorSource.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthAuthenticatorSource.java @@ -6,6 +6,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import jenkins.authentication.tokens.api.AuthenticationTokenContext; +import jenkins.authentication.tokens.api.AuthenticationTokenException; import jenkins.authentication.tokens.api.AuthenticationTokenSource; @@ -27,11 +28,12 @@ public BitbucketOAuthAuthenticatorSource() { * * @param standardUsernamePasswordCredentials the username/password combo * @return an authenticator that will use them. + * @throws AuthenticationTokenException if the specific credentials could not be converted. */ @NonNull @Override public BitbucketOAuthAuthenticator convert( - @NonNull StandardUsernamePasswordCredentials standardUsernamePasswordCredentials) { + @NonNull StandardUsernamePasswordCredentials standardUsernamePasswordCredentials) throws AuthenticationTokenException { return new BitbucketOAuthAuthenticator(standardUsernamePasswordCredentials); } @@ -43,7 +45,7 @@ public BitbucketOAuthAuthenticator convert( * @return whether this can authenticate given the context */ @Override - public boolean isFit(AuthenticationTokenContext ctx) { + protected boolean isFit(AuthenticationTokenContext ctx) { return ctx.mustHave(BitbucketAuthenticator.SCHEME, "https") && ctx.mustHave( BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE, BitbucketAuthenticator.BITBUCKET_INSTANCE_TYPE_CLOUD); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthService.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthService.java deleted file mode 100644 index aa267c2db..000000000 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/credentials/BitbucketOAuthService.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.cloudbees.jenkins.plugins.bitbucket.api.credentials; - - -import java.nio.charset.StandardCharsets; -import org.eclipse.jgit.util.Base64; -import org.scribe.builder.api.DefaultApi20; -import org.scribe.model.OAuthConfig; -import org.scribe.model.OAuthConstants; -import org.scribe.model.OAuthRequest; -import org.scribe.model.Response; -import org.scribe.model.Token; -import org.scribe.model.Verifier; -import org.scribe.oauth.OAuth20ServiceImpl; - -public class BitbucketOAuthService extends OAuth20ServiceImpl { - private static final String GRANT_TYPE_KEY = "grant_type"; - private static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"; - - private DefaultApi20 api; - private OAuthConfig config; - - public BitbucketOAuthService(DefaultApi20 api, OAuthConfig config) { - super(api, config); - this.api = api; - this.config = config; - } - - @Override - public Token getAccessToken(Token requestToken, Verifier verifier) { - OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); - request.addHeader(OAuthConstants.HEADER, this.getHttpBasicAuthHeaderValue()); - request.addBodyParameter(GRANT_TYPE_KEY, GRANT_TYPE_CLIENT_CREDENTIALS); - Response response = request.send(); - - return api.getAccessTokenExtractor().extract(response.getBody()); - } - - @Override - public void signRequest(Token accessToken, OAuthRequest request) { - request.addHeader(OAuthConstants.HEADER, this.getBearerAuthHeaderValue(accessToken)); - } - - private String getHttpBasicAuthHeaderValue() { - String authStr = config.getApiKey() + ":" + config.getApiSecret(); - - return "Basic " + Base64.encodeBytes(authStr.getBytes(StandardCharsets.UTF_8)); - } - - private String getBearerAuthHeaderValue(Token token) { - return "Bearer " + token.getToken(); - } -}