cancel
Showing results for 
Search instead for 
Did you mean: 

CMIS ACL problem/question [SOLVED]

nickdegraeve
Champ in-the-making
Champ in-the-making
Hi

I'm trying to figure out how to use the CMIS Java API, in particular ACLs, but I run into a "CmisPermissionDeniedException: Forbidden" when I try to manipulate a document as a non-Administrator user.

I have an Alfresco Community v4.2.0 (4428) schema 6019 running with an extra user called "user". I'm using version 0.8.0 of Chemistry.

In the JUnit test below I create, as administrator, a text file in the rootfolder and add a write permission to it for the normal user. When I try to check out the document as a normal user I get CmisPermissionDeniedException: Forbidden.

Over at the Chemistry mailing list they suggested using
permissions.add("{http://www.alfresco.org/model/content/1.0}cmobject.Collaborator");
instead of
permissions.add(BasicPermissions.WRITE);
And indeed the test completes without errors.

But using the Alfresco specific permission instead of the CMIS basic permission, defeats the purpose of using CMIS to become vendor agnostic.

At this moment I'm just testing against Alfresco but the goal is the replace the Documentum Foundation Classes with CMIS in our applications. Eventually we'll want to replace Documentum, probably with Alfresco, but we also want to do automated testing with the OpenCMIS InMemory repository. And by using CMIS we thought we could do that easily without further code changes.

So is there a way to use CMIS permissions with Alfresco?
       
Yours,
Nick

CmisTests.java:
public class CmisTests {

    @Test
    public void test() throws IOException {
        SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(SessionParameter.USER, "admin");
        parameters.put(SessionParameter.PASSWORD, "admin");
        parameters.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        parameters.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/alfresco/cmisatom");
        Session session = sessionFactory.getRepositories(parameters).get(0).createSession();

        Document document = FileUtils.createTextDocument("/", "test.txt", "Some text", BaseTypeId.CMIS_DOCUMENT.value(), VersioningState.MAJOR, session);
        String id = document.getId();

        OperationContext operationContext = new OperationContextImpl();
        operationContext.setIncludeAcls(true);
        document = (Document) session.getObject(id, operationContext);

        System.out.println("Acl:");
        Acl acl = document.getAcl();
        for (Ace ace : acl.getAces()) {
            System.out.println(ace);
        }

        parameters.put(SessionParameter.USER, "user");
        parameters.put(SessionParameter.PASSWORD, "user");
        session = sessionFactory.getRepositories(parameters).get(0).createSession();

        document = (Document) session.getObject(id);
        String content = IOUtils.toString(document.getContentStream().getStream());
        System.out.println("Content: " + content);

        ObjectId checkedOutDocumentObjectId = null;
        try {
            checkedOutDocumentObjectId = document.checkOut();
        } catch (CmisPermissionDeniedException e) {
            System.out.println("No permission to check out");
        }

        parameters.put(SessionParameter.USER, "admin");
        parameters.put(SessionParameter.PASSWORD, "admin");
        session = sessionFactory.getRepositories(parameters).get(0).createSession();

        document = (Document) session.getObject(id, operationContext);
        String principal = "user";
        List<String> permissions = new LinkedList<String>();
        permissions.add(BasicPermissions.WRITE);
        Ace addAce = session.getObjectFactory().createAce(principal, permissions);
        List<Ace> addAces = new LinkedList<Ace>();
        addAces.add(addAce);
        document.addAcl(addAces, AclPropagation.REPOSITORYDETERMINED);

        System.out.println("Acl:");
        acl = document.getAcl();
        for (Ace ace : acl.getAces()) {
            System.out.println(ace);
        }

        parameters.put(SessionParameter.USER, "user");
        parameters.put(SessionParameter.PASSWORD, "user");
        session = sessionFactory.getRepositories(parameters).get(0).createSession();

        document = (Document) session.getObject(id);
        // CmisPermissionDeniedException: Forbidden below
        checkedOutDocumentObjectId = document.checkOut();

        Document checkedOutDocument = (Document) session.getObject(checkedOutDocumentObjectId);
        String newContent = "New text.";
        boolean major = false;
        Map<String, String> properties = null;
        String filename = document.getName();
        BigInteger length = BigInteger.valueOf(newContent.length());
        String mimeType = document.getContentStreamMimeType();
        InputStream stream = IOUtils.toInputStream(newContent);
        ContentStream updatedContentStream = new ContentStreamImpl(filename, length, mimeType, stream);
        String checkinComment = "Text is updated";
        checkedOutDocument.checkIn(major, properties, updatedContentStream, checkinComment);

        document = document.getObjectOfLatestVersion(false);
        content = IOUtils.toString(document.getContentStream().getStream());
        System.out.println("Content: " + content);
    }

    @Test
    public void t() {
        SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(SessionParameter.USER, "admin");
        parameters.put(SessionParameter.PASSWORD, "admin");
        parameters.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        parameters.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/alfresco/cmisatom");
        Session session = sessionFactory.getRepositories(parameters).get(0).createSession();
        Document document = (Document) session.getObjectByPath("/test.txt");
        OperationContext operationContext = new OperationContextImpl();
        operationContext.setIncludeAcls(true);
        document = (Document) session.getObject(document, operationContext);
        Acl acl = document.getAcl();
        for (Ace ace : acl.getAces()) {
            System.out.println(ace);
        }
    }

    @Before
    public void init() {
        SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(SessionParameter.USER, "admin");
        parameters.put(SessionParameter.PASSWORD, "admin");
        parameters.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        parameters.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/alfresco/cmisatom");
        Session session = sessionFactory.getRepositories(parameters).get(0).createSession();
        session.delete(session.getObjectByPath("/test.txt"));
    }

}
3 REPLIES 3

jpotts
World-Class Innovator
World-Class Innovator
If you look at the permission mapping in the result of calling getRepositoryInfo, you'll see something like this:
<cmis:mapping>
  <cmis:key>canCheckout.Document</cmis:key>
  <cmis:permission>cmis:all</cmis:permission>
  <cmis:permission>{http://www.alfresco.org/model/content/1.0}lockable.CheckOut</cmis:permission>
</cmis:mapping>

This tells you that if you want your test user to be able to check out a document, you need to assign the "cmis:all" permission. If you do that, your user will be able to successfully perform a checkout.

So if you are writing an interoperable client, before setting the ACL, check the permission mapping, then set the ACL to the correct CMIS permission.

Jeff

nickdegraeve
Champ in-the-making
Champ in-the-making
Thanks for the help.

I was able to do it like this:
RepositoryInfo repositoryInfo = session.getRepositoryInfo();
AclCapabilities aclCapabilities = repositoryInfo.getAclCapabilities();
Map<String, PermissionMapping> permissionMappings = aclCapabilities.getPermissionMapping();
PermissionMapping permissionMapping = permissionMappings.get(PermissionMapping.CAN_CHECKOUT_DOCUMENT);
List<String> permissions = permissionMapping.getPermissions();
Ace addAce = session.getObjectFactory().createAce(principal, permissions);
List<Ace> addAces = new LinkedList<Ace>();
addAces.add(addAce);
document.addAcl(addAces, AclPropagation.REPOSITORYDETERMINED);

Is possible to set a role (administrator or contributor) to a Group via CMIS?