Last updated Sep 9, 2019

How to secure your macro

A Confluence macro can be a very powerful API to add new functionality, and as a plugin developer, it's important to understand the security pitfalls a macro may introduce to the Confluence instance.

This guide outlines some best practices you should follow when writing Confluence macros.

Respect the Outbound allowlist when making HTTP queries from the server

Macros have the ability to make calls to other HTTP services on the server side. In some cases, this may be preferable over making an HTTP call from the browser; for example, when the service being used is unavailable on the browser side.

Your macro must respect the Confluence allowlist (Note: the term whitelist has been changed to allowlist in the Confluence user interface. There are no API changes, so whitelist remains in the codebase). See Configuring the allowlist for more information on how System Administrators can add specific URLs to the allowlist.

Your plugin can access the allowlist by importing the component com.atlassian.plugins.whitelist.OutboundWhitelist using an @ComponentImport annotation on the field. See the spring-scanner documentation for more information on how to use the annotation.

In your pom.xml for the plugin, add the following dependency:

1
2
<dependency>
    <groupId>com.atlassian.plugins</groupId>
    <artifactId>atlassian-whitelist-api-plugin</artifactId>
    <version>6.0.3</version>
    <scope>provided</scope>
</dependency>

In your macro class:

1
2
//...other fields
private final OutboundWhitelist outboundWhitelist;

public YourMacro(@ComponentImport OutboundWhitelist outboundWhitelist) {
   this.outboundWhitelist = outboundWhitelist;
}

public String execute(Map<String, String> map, String s, ConversionContext conversionContext) throws MacroExecutionException {
    String url = map.get("url");
    if (outboundWhitelist.isAllowed(new URI(url)) {
        //make your HTTP outbound calls here
        return "URI:" + HtmlUtil.htmlEncode(url) + " is allowed";
    } else {
        return "URI:" + HtmlUtil.htmlEncode(url) + " is not allowed";
    }
}

//...other macro methods omitted

The component OutboundWhitelist has two methods:

  • isAllowed(URI) that returns true if the given URI matches any of the allowlist patterns added by the administrator, or it matches a configured application link URL.

  • isAllowed(URI uri, UserKey userKey) extends the previous method and also also checks if the user has access to the product. For example, anonymous users can be excluded.

For a more detailed example, see the Confluence HTML Include Macro.

Ensure permission is checked when querying content/data in a macro

A macro may also query and render Confluence content from another page, as in the Include Page macro.

When a macro is performing such a query/render, it's essential that the permission is checked against the current user using the permission manager as follows:

com.atlassian.confluence.security.PermissionManager.hasPermission(com.atlassian.user.User, com.atlassian.confluence.security.Permission, java.lang.Object)

where the permission is one of the permissions in Permission.ALL_PERMISSIONS (usually VIEW), and the object is the target content entity (Page, Blogpost, Comment, or your own CustomContentEntity etc).

The currently logged in user may be obtained via:

This permission check will be cached behind the scenes by Confluence's internal permission cache system, so you should not need to do any bespoke caching in your macro class.

For more information on Confluence's permission model, see Confluence permissions architecture.

Rate this page: