Hello Atlassian-Dev-Community,
we are running Confluence Data Center and are currently migrating customizations from version 8.5 to 9.2.
Specifically, this issue is about modification of the default 404 page:
When a User tries to open a page without having the appropriate Space-Permission set, we want to show additional information instead of just displaying the default 404 page.
We want to determine the Admin-Users and -Groups of the belonging Space and display them as contact persons for being able to request proper Space-Permissions.
In Confluence 8.5, we could easily modify the template 404.vm and add the additional data to it by using Velocity technology.
Due to the switch to soy-Template based technology by Atlassian, this is no longer possible on the same way:
We were able to locate the 404.soy template and do simple modifications on it, but we could not put the additional data to it, yet.
Has anyone here struggled with similar problems? In detail we have the following questions:
-
Is it possible to add additional data to the template?
- Since it is being rendered by Confluence’s core components itself, we don’t see a place, where we could determine add the data as soy-Parameters/-Variables.
-
A different approach would be, to override the whole belonging Action-Class (com.atlassian.confluence.core.actions.FourOhFourAction), and render it on our own way.
- But honestly speaking, we don’t know, if this is possible at all? Overriding the action via Plugin failed so far…
- Anyone with experience of overriding such crucial “base”-Actions of Confluence?
Any help/hint is appreciated!!
TIA
Alexander Engler
I approach this by using a servlet filter to detect the situation and redirect them to my own information page. I don’t customize anything out of the application installation and I don’t override default templates, actions, etc. I believe that overriding actions has fallen out of favor, and may simply no longer work.
A servlet filter can be registered:
<servlet-filter name="Permissions Detection Filter"
key="permissionDetectionFilter"
class="com.company.application.filter.AccessFilter"
location="before-dispatch"
weight="10">
<url-pattern>{PATH_TO_EXECUTE_ON}/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</servlet-filter>
And the implementation can look like this:
@Named
public class AccessFilter implements Filter {
private final PermissionHelperInternal permissionHelper;
@ComponentImport
private final AuthenticationContext authenticationContext;
@ComponentImport
private final ApplicationPropertiesService applicationPropertiesService;
@Inject
AccessFilter(PermissionHelperInternal permissionHelper, AuthenticationContext authenticationContext, ApplicationPropertiesService applicationPropertiesService) {
this.permissionHelper = permissionHelper;
this.authenticationContext = authenticationContext;
this.applicationPropertiesService = applicationPropertiesService;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
URI baseUrl = applicationPropertiesService.getBaseUrl();
String baseUrlString = baseUrl.toString();
ApplicationUser currentUser = authenticationContext.getCurrentUser();
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
PathPartsInternal pathParts = new PathPartsInternal(httpRequest.getPathInfo());
// We should always have a key on this URL pattern... We can bail out of our filter
// and hand it back to the app by calling FilterChain#doFilter and
// breaking (with a return)
if (pathParts.key == null) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
// If we made it this far, we have a key. The user must be trying to access a space
// and we can do a permission check with our custom class now
if (!permissionHelperInternal.hasAccess(currentUser, pathParts.key)) {
httpResponse.sendRedirect(baseUrlString + "/plugins/servlet/NoAccess/spaces/" + pathParts.key);
return;
}
// If we reached this point, the the end user must have appropriate permissions
// according to our custom PermissionHelperInternal#hasAccess method
// In this case, we can bail out of our filter and hand it back to the app
filterChain.doFilter(servletRequest, servletResponse);
}
...
}
Once you detect the situation and redirect them to your own endpoint/servlet you can display anything you want.
Anyways, this is all just my opinion and how I choose to solve these issues.
1 Like