PermissionManager.hasPermission(...) throws IllegalArgumentException for non-admin user

Hi there,

I am trying to check if a user has a View-permission on a page and it isn’t working as documented.

Here is an example code with the issue:

Optional<Content> page = contentService.find()
                .withId(ContentId.of(pageId))
                .fetch();

if (page.isPresent()) {
   try {
      ConfluenceUser user = AuthenticatedUserThreadLocal.get();
      boolean hasPerm = permissionManager.hasPermission(getSessionUser(), 
                                            Permission.VIEW, page.get());
        //....other code here continues with admin-user, no problem...
        } catch (Exception e) {
           // but with non-admin user we always end up here?!??
            e.printStackTrace();
        }
}
// etc

I have two users in my local Confluence test server, admin and tester. With admin this works fine, and hasPerm gets value “true” when this is tested on a page that the admin has created on his space. I guess admin has always VIEW permission everywhere so that’s to be expected I guess.

However, when I log in as the “tester”-user and I create a space and a new page, then this code always fails, the hasPermission-call always throws this exception (that is btw NOT documented in the API doc…):

java.lang.IllegalArgumentException: Could not check permissions for
Content{id='ContentId{id=7471109}', type=page, title='Test Page', 
status=current, space=CollapsedReference{idProperties={key=TST}, 
referentClass=class com.atlassian.confluence.api.model.content.Space}, 
history=CollapsedReference{idProperties={contentParent=CollapsedReference
{idProperties={id=ContentId{id=7471109}, version=CollapsedReference
{idProperties={number=2}, referentClass=class com.atlassian.confluence.api
.model.content.Version}, status=current}, referentClass=class 
com.atlassian.confluence.api.model.content.Content}}, referentClass=class 
com.atlassian.confluence.api.model.content.History}, version=
CollapsedReference{idProperties={number=2}, referentClass=class com.atlassian.confluence.api.model.content.Version}, 
ancestors=null (CollapsedList), container=CollapsedReference
{idProperties={key=TST}, referentClass=class com.atlassian.confluence.api
.model.content.Space}} no suitable delegate found.

I’ve checked that user and page both are what I expect them to be, correct logged in user and correct page. However, this error always happens for non-admin user.

This is what I try to follow: How do I tell if a user has permission to...?

and permissionManager is an injected component of type:
com.atlassian.confluence.security.PermissionManager

What might the problem be and how do I fix it? Or should I use some other way to check for View-permission on a page for admin/non-admin users?

In my Atlassian-plugin.xml I’m importing the permissionManager like this:

<component-import name="component-import" key="permissionManager"
 interface="com.atlassian.confluence.security.PermissionManager"/>

And that gets injected to my permissionManager, otherwise I would get null pointer exception from that code snippet even with the admin user.

Ok, I just noticed that one should get the current user like this:

Optional<ConfluenceUser> confluenceUser = AuthenticatedUserAccessor.get();

However, I’m, using Confluence 7.13.1 as my local Server and I don’t see this AuthenticatedUserAccessor-class there at all, there is only the AuthenticatedUserThreadLocal inside the com.gliffy.atlassian.user-package.

So not really sure where would I get the AuthenticatedUserAccessor-class…

  • Petri
1 Like

Our QA tested this issue with various Confluence Server versions and determined that the issue appeared on version 7.9 as this problem didn’t yet occur with 7.8 but appeared when he tried this with Confluence Server 7.9. On both cases our plugin version was exactly the same.

Any ideas what might have happened there between 7.8 and 7.9 that caused this?

Hello @PetriJuhaniRiipinen

The article you mentioned How do I tell if a user has permission to...? is correct, however PermissionManager is traditionally used with PageManager , SpaceManager, CommentManager … and not with our Java API models and services.
We recommend to use the Java API services instead and not go through PageManager/PermissionManager , you’ll see that a lot of the methods in PageManager are deprecated anyway.

Since you are using ContentService#find from our Java API, you can omit the explicit permission check on your side , because ContentService ensures permission checks are handled by default under the hood , so if the Optional is not empty , it means that the user has VIEW permission on the content.

The reason your code works fine for admin-users, it is because they are exempt from permission checks in some cases … which means permission checks for them follows a different code path that doesn’t blow up in that exception .

So you should be able to trust ContentService#find on its own.

Now what if you want to check for EDIT permission … ?
You should use OperationService in combination with ContentService in this case
for example OperationService#getAvailableOperations will resolve all the available ops for the logged in user for a given content item.

@Path("/operation")
public class OperationResource {

    private final ContentService contentService;
    private final OperationService operationService;

    @Autowired
    public OperationResource(
            @ComponentImport final ContentService contentService,
            @ComponentImport final OperationService operationService
    ) {
        this.contentService = contentService;
        this.operationService = operationService;
    }

    @GET
    @Path("/content/{id}")
    @Produces("application/json")
    public Response contentWithId(@PathParam("id") long id) {
        List<OperationCheckResult> operationCheckResults = contentService.find(ExpansionsParser.parse("container")).withId(ContentId.of(id))
                .fetch()
                .map(content -> operationService.getAvailableOperations(Target.forModelObject(content)))
                .orElse(Collections.emptyList());
        return Response.ok(operationCheckResults).build();
    }
}

code snippet available here welcome operation resource example · viqueen/atlassian-devbox@4118e3c · GitHub

Hope this helps
Hasnae R.

4 Likes