I created an Atlassian connect add-on using the Atlassian Spring Boot Starter. I created the following descriptor (atlassian-connect.json):
{
<span>"key"</span>: <span>"${addon.key}"</span>,
<span>"baseUrl"</span>: <span>"${addon.base-url}"</span>,
<span>"name"</span>: <span>"Mahesh Hello World"</span>,
<span>"description"</span>: <span>"Mahesh Hello World"</span>,
<span>"authentication"</span>: {
<span>"type"</span>: <span>"jwt"</span>
},
<span>"lifecycle"</span>: {
<span>"installed"</span>: <span>"/installed"</span>,
<span>"uninstalled"</span>: <span>"/uninstalled"</span>
},
<span>"modules"</span>: {
<span>"webhooks"</span>: [
{
<span>"event"</span>: <span>"pullrequest:created"</span>,
<span>"url"</span>: <span>"/bitbucket-hook"</span>
}
],
<span>"webPanel"</span>: [
{
<span>"url"</span>: <span>"/connect-example?repoPath={repo_path}"</span>,
<span>"name"</span>: {
<span>"value"</span>: <span>"Example Web Panel"</span>
},
<span>"location"</span>: <span>"org.bitbucket.repository.overview.informationPanel"</span>,
<span>"key"</span>: <span>"example-web-panel"</span>
}
]
},
<span>"scopes"</span>: [<span>"account"</span>, <span>"repository:admin"</span>, <span>"pullrequest"</span>]
}As seen, there is one webhook registered for the pullrequest:created event. The Spring Rest Controller webhook listener is based on this link
As per the above link, docs for atlassian-connect-spring-boot states the following :
"Provides a Spring Boot starter for building Atlassian Connect add-ons for JIRA (Software, Service Desk and Core) and Confluence."
Apparently this means Bitbucket Cloud is not supported out of the box. So the link provides a solution to create your own JWT tokens based on another link
In addition to classes mentioned in this link, I created my Rest Controller (webhook listener) as follows:
<span>@PostMapping("bitbucket-hook")</span>
<span>public</span> <span>void</span> <span>webhook</span><span>(@AuthenticationPrincipal AtlassianHostUser hostUser, @RequestBody String repository, HttpServletResponse httpServletResponse)</span>
<span>throws</span> ClientProtocolException, IOException, URISyntaxException, InterruptedException {
log.info(repository);
<span>AccessTokenResponse</span> <span>accessToken</span> <span>=</span> <span>new</span> <span>AccessToken</span>(hostUser.getHost().getSharedSecret(), hostUser.getHost().getClientKey(), <span>"mahesh-hello-world-9"</span>).getAccessToken();
<span>RestTemplate</span> <span>restTemplate</span> <span>=</span> <span>new</span> <span>RestTemplate</span>();
<span>HttpHeaders</span> <span>headers</span> <span>=</span> <span>new</span> <span>HttpHeaders</span>();
headers.add(<span>"Authorization"</span>, <span>"Bearer "</span> + accessToken.getAccess_token());
HttpEntity<String> branchRequest = <span>new</span> <span>HttpEntity</span><String>(headers);
ResponseEntity<String> response = restTemplate.exchange(<span>"https://api.bitbucket.org/2.0/repositories/maheshr-sacumen-ws/bitbucket-test-code/refs/branches/master"</span>, HttpMethod.GET, branchRequest, String.class);
<span>String</span> <span>branchObject</span> <span>=</span> response.getBody();
<span>JsonObject</span> <span>targetJsonObject</span> <span>=</span> JsonParser.parseString(branchObject).getAsJsonObject().get(<span>"target"</span>).getAsJsonObject();
<span>String</span> <span>hash</span> <span>=</span> targetJsonObject.get(<span>"hash"</span>).getAsString();
log.info(hash);
headers = <span>new</span> <span>HttpHeaders</span>();
accessToken = <span>new</span> <span>AccessToken</span>(hostUser.getHost().getSharedSecret(), hostUser.getHost().getClientKey(), <span>"mahesh-hello-world-9"</span>).getAccessToken();
headers.add(<span>"Authorization"</span>, <span>"Bearer "</span> + accessToken.getAccess_token());
headers.add(<span>"user-agent"</span>, <span>"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"</span>);
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> map= <span>new</span> <span>LinkedMultiValueMap</span><>();
map.add(<span>"message"</span>, <span>"This is a test commit"</span>);
map.add(<span>"author"</span>, <span>"Mahesh Chandran <mahesh.kr@sacumen.com>"</span>);
map.add(<span>"parents"</span>, hash);
map.add(<span>"branch"</span>, <span>"master"</span>);
map.add(<span>"test.yml"</span>, <span>new</span> <span>FileSystemResource</span>(<span>"/home/sacumen/Code/atlassian/bitbucket-test-code/test.yml"</span>));
HttpEntity<MultiValueMap<String, Object>> pushRequest
= <span>new</span> <span>HttpEntity</span><>(map, headers);
response = restTemplate.exchange(<span>"https://api.bitbucket.org/2.0/repositories/maheshr-sacumen-ws/bitbucket-test-code/src"</span>, HttpMethod.POST, pushRequest, String.class);
log.info(response.getStatusCode().toString());
}But I get the following error:
org.springframework.web.client.HttpClientErrorException: 403 Forbidden
I have given repo read/write/admin rights for the OAuth consumer which I created in Bitbucket.
The same endpoints work well and pushes the files successfully from Postman. The only difference I can make out is that in Postman, I use client_credentials with the Client ID and Client Secret corresponding to the OAuth consumer. I don't see this used as far as I can think.
Can someone look into the code and let me know if there is a solution, given this approach.