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.
Macros have the ability to make calls to other HTTP services on the server-side. This may be preferable in some cases, over making the HTTP call from the browser (for example when the service being used is unavailable on the browser-side).
Your macro must respect the Confluence whitelist (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 whitelist 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>4.0.7</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 a single method, isAllowed(URI)
, which returns true
if the given URI
matches any of the whitelist patterns added by the administrator, or it matches a configured application link URL.
For a more detailed example, see the Confluence HTML Include 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:
com.atlassian.sal.api.user.UserManager.getRemoteUser()
(see sal-services), orcom.atlassian.confluence.user.AuthenticatedUserThreadLocal.get()
method (see How do I find the logged in user).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: