Skip to content

Commit 483d4a2

Browse files
[JENKINS-74970] Log user name and repository on auth error
If Bitbucket Server responds with HTTP status 401 (Unauthorized) or 403 (Forbidden), and the HTTP response includes an "X-AUSERNAME" header field that shows Bitbucket Server authenticated the user, then add more information in the message of the BitbucketRequestException: * The Bitbucket user name from the "X-AUSERNAME" response header field. * The repository to which the request was sent. * The project or user that owns the repository. The behaviour on Bitbucket Cloud is unchanged.
1 parent 843d62a commit 483d4a2

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@
8787
import jenkins.scm.api.SCMFile;
8888
import org.apache.commons.io.IOUtils;
8989
import org.apache.commons.lang.StringUtils;
90+
import org.apache.http.Header;
9091
import org.apache.http.HttpHost;
9192
import org.apache.http.HttpStatus;
93+
import org.apache.http.client.methods.CloseableHttpResponse;
9294
import org.apache.http.client.methods.HttpGet;
9395
import org.apache.http.conn.HttpClientConnectionManager;
9496
import org.apache.http.impl.client.CloseableHttpClient;
@@ -1051,4 +1053,49 @@ private Map<String,Object> collectLines(String response, final List<String> line
10511053
return content;
10521054
}
10531055

1056+
@Override
1057+
protected BitbucketRequestException buildResponseException(CloseableHttpResponse response, String errorMessage) {
1058+
// If the HTTP request failed because of an authorization
1059+
// problem, then make the exception message also show the
1060+
// Bitbucket user name with which Jenkins authenticated,
1061+
// the project name, and the repository name.
1062+
//
1063+
// Such an authorization problem can occur especially in a
1064+
// pull request from a personal fork: if Jenkins has been
1065+
// granted READ access on the target repository of the PR but
1066+
// not on the fork, then it can read the PR information from
1067+
// the target repository and check out the files, but cannot
1068+
// post a build status to the fork.
1069+
//
1070+
// If the HTTP request already includes valid credentials,
1071+
// but the Bitbucket user has not been granted access on the
1072+
// repository, then Bitbucket Server responds with HTTP status
1073+
// 401 (Unauthorized) and a WWW-Authenticate header field that
1074+
// requests OAuth, even though RFC 7235 section 2.1 recommends
1075+
// 403 (Forbidden). Let's recognize both 401 and 403.
1076+
int httpStatus = response.getStatusLine().getStatusCode();
1077+
if (httpStatus == HttpStatus.SC_UNAUTHORIZED || httpStatus == HttpStatus.SC_FORBIDDEN) {
1078+
Header userNameHeader = response.getFirstHeader("X-AUSERNAME");
1079+
if (userNameHeader != null
1080+
&& !userNameHeader.getValue().equals("anonymous")) {
1081+
String headers = StringUtils.join(response.getAllHeaders(), "\n");
1082+
1083+
// The message says "sufficient access" because it is
1084+
// too difficult for this method to know which level
1085+
// of access is actually needed.
1086+
// Posting a build status requires READ access, but
1087+
// deleting a build status requires ADMIN access.
1088+
String message = String.format("HTTP request error.%nPlease verify that the Bitbucket user \"%s\" is granted sufficient access on the repository \"%s/%s\".%nStatus: %s%nResponse: %s%n%s",
1089+
userNameHeader.getValue(),
1090+
getUserCentricOwner(),
1091+
getRepositoryName(),
1092+
response.getStatusLine(),
1093+
errorMessage,
1094+
headers);
1095+
return new BitbucketRequestException(httpStatus, message);
1096+
}
1097+
}
1098+
1099+
return super.buildResponseException(response, errorMessage);
1100+
}
10541101
}

0 commit comments

Comments
 (0)