Hi,
I’m trying to access an authenticated Bitbucket Server URL from within a Bitbucket server hook/servlet. I have it working but I feel like I’m going round the houses to do things like parse/split URLs. I’ve searched to see if this is built-in functionality but couldn’t find anything. Does anyone know a better way of doing this?
I want users to be able to configure my hook by pasting a URL into its settings screen that contains rules the plugin will use. The URL could be one referencing a file hosted inside a bitbucket repo or on the Internet. If anyone knows an easy way to cache this that would be really helpful too.
Eg:
http://bitbucket:7990/bitbucket/projects/RUL/repos/rules/raw/test.json
→ grab the URL inside the hook as the logged on userhttp://github.com/foo/bar/test.json
→ grab the URL inside the hook, no authentication (unless specified inside the URL)
I wasn’t able to get this to pass on the user’s current credentials. The closest thing I saw were questions about using SAL TrustedRequestFactory with Jira and Bamboo:
I tried injecting TrustedRequestFactory
in Bitbucket with @ComponentImport
but I get missing class errors. I defined sal-trust-api
in my pom.xml
with variants of:
<dependency>
<groupId>com.atlassian.sal</groupId>
<artifactId>sal-trust-api</artifactId>
<scope>provided</scope> <!-- on and off -->
<version>3.2.0-abbce37</version>
</dependency>
… But nothing seemed to help. Looks like its just not supported in Bitbucket (5.16.0)?
The closest thing I could find that did work was based on another forum post which shows how to use the Java API to request files based on project keys and repository slugs:
I couldn’t see an easy way to extract these strings from a URL so I ended up writing my own[1] - surely this already exists somewhere? Anyone know what it called?
After a day of hacking around my working code looks like this (constructor injection used for contentService
, applicationProperties
and requestFactory
):
...
String baseUrl = applicationProperties.getBaseUrl(UrlMode.ABSOLUTE);
BitbucketUrl bitbucketUrl = new BitbucketUrl(baseUrl, customRuleUrl);
InputStream in;
if (bitbucketUrl.isBitbucketUrl()) {
// grab a file from local bitbucket instance using Java API
Repository repository = repositoryService.getBySlug(
bitbucketUrl.getProject(),
bitbucketUrl.getSlug()
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
contentService.streamFile(
repository,
bitbucketUrl.getRevision(),
bitbucketUrl.getFilePath(),
(s) -> out
);
in = new ByteArrayInputStream(out.toByteArray());
} else {
// non-local URL - just make a regular request using RequestFactory
in = (InputStream) requestFactory.createRequest(Request.MethodType.GET, customRuleUrl)
...
}
...
Can anyone help me simplify this?
Thanks,
Geoff
[1] Bitbucket URL component extractor
package com.declarativesystems.bitbucket.commitscanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BitbucketUrl {
private String project;
private String slug;
private String filePath;
private String revision;
private boolean bitbucketUrl;
private Matcher matcher;
public String getProject() {
return project;
}
public String getSlug() {
return slug;
}
public String getFilePath() {
return filePath;
}
public String getRevision() {
return revision;
}
/**
* /projects/RUL/repos/rules/raw/test.json
* URLs must match this regex which we also use for field capture:
* $1 - project key
* $2 - slug/repository name
* $3 - path
* $4 - at parameter (all)
* $5 - commit/branch
*/
private static final Pattern regex = Pattern.compile(
"^/projects/([^/]+)/repos/([^/]+)/raw/([^\\?]+)(\\?at=(.*))?$"
);
public BitbucketUrl(String baseUrl, String targetUrl) {
bitbucketUrl = targetUrl.startsWith(baseUrl);
if (bitbucketUrl) {
parseBitbucketUrl(targetUrl.replace(baseUrl, ""));
}
}
/**
* should be left with something like
* /projects/RUL/repos/rules/raw/test.json
*/
private void parseBitbucketUrl(String path) {
// only allow paths matching regex we expect
matcher = regex.matcher(path);
if (matcher.matches()) {
project = matcher.group(1);
slug = matcher.group(2);
filePath = matcher.group(3);
revision = matcher.group(5);
} else {
throw new RuntimeException(
"Access denied: only files from bitbucket repositories can be accessed"
);
}
}
public boolean isBitbucketUrl() {
return bitbucketUrl && matcher.matches();
}
}