I am trying to use project and repository services inside of my integration tests. For example, creating a new project:
@RunWith(AtlassianPluginsTestRunner.class)
public class MyComponentTest {
private final ApplicationProperties applicationProperties;
private final RepositoryService repositoryService;
private final ProjectService projectService;
public MyComponentTest(ApplicationProperties applicationProperties, RepositoryService repositoryService, ProjectService projectService){
this.applicationProperties = applicationProperties;
this.repositoryService = repositoryService;
this.projectService = projectService;
}
@Test
public void testSomething(){
// Error:
// com.atlassian.bitbucket.AuthorisationException:
// You are not permitted to access this resource
Project project = projectService.create(
new ProjectCreateRequest.Builder()
.name("Project1")
.key("proj_1")
.build()
);
// Then create repository
// Finally, do something with the repository and my custom plugin
}
}
The problem is that I get “com.atlassian.bitbucket.AuthorisationException: You are not permitted to access this resource” exception when creating the project.
If this was Jira, I would be able to solve this by importing JiraAuthenticationContext and calling setLoggedInUser(user). But I am unable to find anything similar for a Bitbucket plugin.
How do I ensure that the user is logged in?
I have found a workaround for this.
It works without a problem if the test is run through the Dev Toolbox test console (e.g. http://localhost:7990/bitbucket/plugins/servlet/it-test-console
)
Or when run through curl (e.g. http://localhost:7990/bitbucket/rest/atlassiantestrunner/1.0/runtestfromconsole/it.<path to class>
)
But will fail if run through the atlas-integration-test command.
Why?
In Bitbucket, you can authorise resource requests by using the com.atlassian.bitbucket.user.SecurityService component.
Wrap your request with SecurityService.withPermission().call(). This way you also don’t have to impersonate a specific user like you are describing with the JiraAuthenticationContext. Alternatively If you did want to authorise against a specific user then you could use SecurityContext.impersonating().
Example:
securityService.withPermission(Permission.ADMIN, "Useful message").call(() -> projectService.create(....));
Thank you! You have saved my day!
The securityService.withPermission(...).call(() -> ...);
did not work, because many services need the current authenticated user. (Consider AuthenticationContext.getCurrentUser()
). For example when creating a project, the ProjectService needs the current user to assign them as a project admin.
But, SecurityContext.impersonating()
does work. I have ended up doing the following:
import com.atlassian.bitbucket.user.UserService;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.user.SecurityService;
...
final ApplicationUser user = userService.findUserByNameOrEmail("admin");
if (user == null) throw new RuntimeException("User not found");
securityService.impersonating(user, "Useful message").call(() -> {
[... your tests here ...]
return true;
});
Ah, I didn’t know about some methods requiring a user, good to know.