Skip to content

Commit 458c083

Browse files
committed
[JENKINS-75477] Frequent 401 errors from Bitbucket Data Center when there are high concurrent builds
Use CredentialsMatcher boxed in a timeout execution only when gathering the list of credentials for a web UI page, to exclude credentials that make remote calls to retrieve the password. In all other cases, when the plugin needs to look up stored credentials, it does not set the timebox on the secret.getPassword call, which causes an unpredictable
1 parent 3371543 commit 458c083

19 files changed

+314
-270
lines changed

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3535
import com.cloudbees.jenkins.plugins.bitbucket.impl.extension.FallbackToOtherRepositoryGitSCMExtension;
3636
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
37-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
37+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3838
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.SCMUtils;
3939
import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey;
4040
import com.cloudbees.plugins.credentials.Credentials;
@@ -172,9 +172,9 @@ public BitbucketSCMSource scmSource() {
172172
@NonNull
173173
public BitbucketGitSCMBuilder withCredentials(String credentialsId, BitbucketRepositoryProtocol protocol) {
174174
if (StringUtils.isNotBlank(credentialsId)) {
175-
StandardCredentials credentials = BitbucketCredentials.lookupCredentials(
176-
scmSource.getServerUrl(),
175+
StandardCredentials credentials = BitbucketCredentialsUtils.lookupCredentials(
177176
scmSource.getOwner(),
177+
scmSource.getServerUrl(),
178178
credentialsId,
179179
StandardCredentials.class
180180
);

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketCloudEndpoint;
3636
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3737
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
38-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
38+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3939
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
4040
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
4141
import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation;
@@ -248,9 +248,9 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
248248
listener.getLogger().format("Must specify a repository owner%n");
249249
return;
250250
}
251-
StandardCredentials credentials = BitbucketCredentials.lookupCredentials(
252-
serverUrl,
251+
StandardCredentials credentials = BitbucketCredentialsUtils.lookupCredentials(
253252
observer.getContext(),
253+
serverUrl,
254254
credentialsId,
255255
StandardCredentials.class
256256
);
@@ -301,9 +301,9 @@ public List<Action> retrieveActions(@NonNull SCMNavigatorOwner owner,
301301
// TODO when we have support for trusted events, use the details from event if event was from trusted source
302302
listener.getLogger().printf("Looking up team details of %s...%n", getRepoOwner());
303303
List<Action> result = new ArrayList<>();
304-
StandardCredentials credentials = BitbucketCredentials.lookupCredentials(
305-
serverUrl,
304+
StandardCredentials credentials = BitbucketCredentialsUtils.lookupCredentials(
306305
owner,
306+
serverUrl,
307307
credentialsId,
308308
StandardCredentials.class
309309
);
@@ -392,6 +392,7 @@ public boolean isServerUrlSelectable() {
392392
return !BitbucketEndpointProvider.all().isEmpty();
393393
}
394394

395+
@RequirePOST
395396
public ListBoxModel doFillServerUrlItems(@AncestorInPath SCMSourceOwner context) {
396397
AccessControlled contextToCheck = context == null ? Jenkins.get() : context;
397398
if (!contextToCheck.hasPermission(Item.CONFIGURE)) {
@@ -402,9 +403,9 @@ public ListBoxModel doFillServerUrlItems(@AncestorInPath SCMSourceOwner context)
402403

403404
@RequirePOST
404405
public static FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner context,
405-
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL,
406+
@QueryParameter(fixEmpty = true, value = "serverUrl", required = true) String serverURL,
406407
@QueryParameter String value) {
407-
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
408+
return BitbucketCredentialsUtils.checkCredentialsId(context, value, serverURL);
408409
}
409410

410411
@RequirePOST
@@ -420,16 +421,17 @@ public static FormValidation doCheckMirrorId(@QueryParameter String value,
420421
return FormValidation.ok();
421422
}
422423

424+
@RequirePOST
423425
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context,
424-
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
425-
return BitbucketCredentials.fillCredentialsIdItems(context, serverURL);
426+
@QueryParameter(fixEmpty = true, value = "serverUrl", required = true) String serverURL) {
427+
return BitbucketCredentialsUtils.listCredentials(context, serverURL, null);
426428
}
427429

430+
@RequirePOST
428431
public ListBoxModel doFillMirrorIdItems(@AncestorInPath SCMSourceOwner context,
429-
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverUrl,
432+
@QueryParameter(fixEmpty = true, value = "serverUrl", required = true) String serverUrl,
430433
@QueryParameter String credentialsId,
431-
@QueryParameter String repoOwner)
432-
throws FormFillFailure {
434+
@QueryParameter String repoOwner) throws FormFillFailure {
433435
return getFromBitbucket(context, serverUrl, credentialsId, repoOwner, null, MirrorListSupplier.INSTANCE);
434436
}
435437

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
import com.cloudbees.jenkins.plugins.bitbucket.impl.extension.GitClientAuthenticatorExtension;
5050
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
5151
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils.BitbucketSupplier;
52-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
52+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
5353
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.DateUtils;
5454
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
5555
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
@@ -797,9 +797,9 @@ public DescriptorImpl getDescriptor() {
797797

798798
@CheckForNull
799799
/* package */ StandardCredentials credentials() {
800-
return BitbucketCredentials.lookupCredentials(
801-
getServerUrl(),
800+
return BitbucketCredentialsUtils.lookupCredentials(
802801
getOwner(),
802+
getServerUrl(),
803803
getCredentialsId(),
804804
StandardCredentials.class
805805
);
@@ -1054,7 +1054,7 @@ public String getDisplayName() {
10541054
public FormValidation doCheckCredentialsId(@CheckForNull @AncestorInPath SCMSourceOwner context,
10551055
@QueryParameter String value,
10561056
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
1057-
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
1057+
return BitbucketCredentialsUtils.checkCredentialsId(context, value, serverURL);
10581058
}
10591059

10601060
public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner context, @QueryParameter String value) {
@@ -1095,7 +1095,7 @@ public ListBoxModel doFillServerUrlItems(@AncestorInPath SCMSourceOwner context)
10951095
}
10961096

10971097
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context, @QueryParameter String serverUrl) {
1098-
return BitbucketCredentials.fillCredentialsIdItems(context, serverUrl);
1098+
return BitbucketCredentialsUtils.listCredentials(context, serverUrl, null);
10991099
}
11001100

11011101
@RequirePOST

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApiFactory.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ protected BitbucketApi create(@Nullable String serverUrl,
7979
* Creates a {@link BitbucketApi} for the specified URL with the supplied credentials, owner and (optional)
8080
* repository.
8181
*
82-
* @param serverUrl the server URL.
82+
* @param serverURL the server URL.
8383
* @param authenticator the (optional) authenticator.
8484
* @param owner the owner name.
8585
* @param projectKey the (optional) project key.
@@ -88,17 +88,17 @@ protected BitbucketApi create(@Nullable String serverUrl,
8888
* @throws IllegalArgumentException if the supplied URL is not supported.
8989
*/
9090
@NonNull
91-
public static BitbucketApi newInstance(@Nullable String serverUrl,
91+
public static BitbucketApi newInstance(@Nullable String serverURL,
9292
@Nullable BitbucketAuthenticator authenticator,
9393
@NonNull String owner,
9494
@CheckForNull String projectKey,
9595
@CheckForNull String repository) {
9696
for (BitbucketApiFactory factory : ExtensionList.lookup(BitbucketApiFactory.class)) {
97-
if (factory.isMatch(serverUrl)) {
98-
return factory.create(serverUrl, authenticator, owner, projectKey, repository);
97+
if (factory.isMatch(serverURL)) {
98+
return factory.create(serverURL, authenticator, owner, projectKey, repository);
9999
}
100100
}
101-
throw new IllegalArgumentException("Unsupported Bitbucket server URL: " + serverUrl);
101+
throw new IllegalArgumentException("Unsupported Bitbucket server URL: " + serverURL);
102102
}
103103

104104
@NonNull

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpoint.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
package com.cloudbees.jenkins.plugins.bitbucket.api.endpoint;
2525

2626
import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource;
27-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
27+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
2828
import com.cloudbees.plugins.credentials.common.StandardCredentials;
2929
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
3030
import edu.umd.cs.findbugs.annotations.CheckForNull;
@@ -128,7 +128,7 @@ default StandardCredentials credentials() {
128128
if (credentialsId == null) {
129129
return null;
130130
} else {
131-
return BitbucketCredentials.lookupCredentials(getServerURL(), Jenkins.get(), credentialsId, StandardCredentials.class);
131+
return BitbucketCredentialsUtils.lookupCredentials(Jenkins.get(), getServerURL(), credentialsId, StandardCredentials.class);
132132
}
133133
}
134134

@@ -143,7 +143,7 @@ default StringCredentials hookSignatureCredentials() {
143143
if (credentialsId == null) {
144144
return null;
145145
} else {
146-
return BitbucketCredentials.lookupCredentials(getServerURL(), Jenkins.get(), credentialsId, StringCredentials.class);
146+
return BitbucketCredentialsUtils.lookupCredentials(Jenkins.get(), getServerURL(), credentialsId, StringCredentials.class);
147147
}
148148
}
149149

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointDescriptor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@
2323
*/
2424
package com.cloudbees.jenkins.plugins.bitbucket.api.endpoint;
2525

26-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
26+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
2727
import com.cloudbees.plugins.credentials.CredentialsMatchers;
28-
import com.cloudbees.plugins.credentials.common.StandardCredentials;
2928
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
3029
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
3130
import hudson.Util;
@@ -59,7 +58,7 @@ public class BitbucketEndpointDescriptor extends Descriptor<BitbucketEndpoint> {
5958
public ListBoxModel doFillCredentialsIdItems(@QueryParameter(fixEmpty = true) String credentialsId,
6059
@QueryParameter(value = "serverUrl", fixEmpty = true) String serverURL) {
6160
Jenkins jenkins = checkPermission();
62-
return BitbucketCredentials.fillCredentialsIdItems(serverURL, jenkins, StandardCredentials.class, credentialsId);
61+
return BitbucketCredentialsUtils.listCredentials(jenkins, serverURL, credentialsId);
6362
}
6463

6564
private static Jenkins checkPermission() {

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/ServerPushEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
3535
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit;
3636
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequest;
37-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
37+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3838
import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient;
3939
import com.cloudbees.jenkins.plugins.bitbucket.server.client.branch.BitbucketServerCommit;
4040
import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequest;
@@ -197,9 +197,9 @@ private void addBranchesAndTags(BitbucketSCMSource src, Map<SCMHead, SCMRevision
197197
protected BitbucketApi getClient(BitbucketSCMSource src) {
198198
String serverURL = src.getServerUrl();
199199

200-
StandardCredentials credentials = BitbucketCredentials.lookupCredentials(
201-
serverURL,
200+
StandardCredentials credentials = BitbucketCredentialsUtils.lookupCredentials(
202201
src.getOwner(),
202+
serverURL,
203203
src.getCredentialsId(),
204204
StandardCredentials.class
205205
);

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/avatars/BitbucketAvatarImageSource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi;
2727
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApiFactory;
2828
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
29-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentials;
29+
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3030
import com.cloudbees.plugins.credentials.common.StandardCredentials;
3131
import edu.umd.cs.findbugs.annotations.NonNull;
3232
import edu.umd.cs.findbugs.annotations.Nullable;
@@ -68,7 +68,7 @@ public AvatarImage fetch() {
6868
owner = Jenkins.get().getItemByFullName(scmOwner, SCMNavigatorOwner.class);
6969
}
7070
if (owner != null) {
71-
StandardCredentials credentials = BitbucketCredentials.lookupCredentials(serverURL, owner, credentialsId, StandardCredentials.class);
71+
StandardCredentials credentials = BitbucketCredentialsUtils.lookupCredentials(owner, serverURL, credentialsId, StandardCredentials.class);
7272
BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverURL), credentials);
7373
// projectKey and repository are not used to fetch the project avatar
7474
// owner can not be null but is not used from the client to retrieve avatar image, we just need authentication

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketClientCertificateAuthenticatorSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public BitbucketClientCertificateAuthenticator convert(@NonNull StandardCertific
5757
}
5858

5959
/**
60-
* Whether this source works in the given context. For client certs, only HTTPS BitbucketServer instances make sense
60+
* Whether this source works in the given context. For client certs, only HTTPS Bitbucket Data Center instances make sense
6161
*
6262
* @param ctx the context
6363
* @return whether this can authenticate given the context

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketOAuthAuthenticatorSource.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
2828
import com.cloudbees.plugins.credentials.CredentialsMatcher;
29+
import com.cloudbees.plugins.credentials.CredentialsMatchers;
2930
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
3031
import edu.umd.cs.findbugs.annotations.NonNull;
3132
import hudson.Extension;
@@ -61,8 +62,7 @@ public BitbucketOAuthAuthenticator convert(@NonNull StandardUsernamePasswordCred
6162
}
6263

6364
/**
64-
* Whether this source works in the given context. For client certs, only HTTPS
65-
* BitbucketServer instances make sense
65+
* Whether this source works in the given context.
6666
*
6767
* @param ctx the context
6868
* @return whether this can authenticate given the context
@@ -78,7 +78,7 @@ protected boolean isFit(AuthenticationTokenContext<? super BitbucketOAuthAuthent
7878
*/
7979
@Override
8080
public CredentialsMatcher matcher() {
81-
return new BitbucketOAuthCredentialMatcher();
81+
return CredentialsMatchers.allOf(super.matcher(), new BitbucketOAuthCredentialMatcher());
8282
}
8383

8484
}

0 commit comments

Comments
 (0)