Jared Ottley

Technology | Fatherhood | Insanity

Alfresco: Permissions Web Scripts

with 14 comments

A couple of months back I was asked to write a couple of web scripts to help one of our customers to be able to check and modify permissions for content/spaces in the Alfresco repository.  I’ve finally had the chance to spend sometime testing and now writing about them.

The core of the web scripts was quick to write.  The fun (more time consuming) part was working with exception handling in javascipt.  I know tons of fun right!  There are few different ways to use exception handling based on which version of Alfresco you are using.  The customer is on Enterprise 3.1 and I wanted to make sure that the web scripts also worked on the more current releases of Alfresco as well.  A change (re: addition) was made in Enterprise 3.2.1 and Community 3.3 to help simplify exception handeling.  I’ll talk about exception handling and these differences in a follow up post.  For now let’s talk about these new web scripts.

permissions GET

The first web script returns all of the permissions for a specified node.

The URL used is /alfresco/service/permissions/{store_type}/{store_id}/{id}

Where

store_type: The type of store you want to query, ex: workspace

store_id: The ID of the store you want to query, ex: SpacesStore

id: The UUID of the node, ex: aed218e8-df44-4865-84cd-0105252f4993

The above values are joined together to form the nodeRef.

If the node is not found a 404 error will be returned, any missing URI parameters will result in a 400 error and if you don’t have permission to view the node you will get a 401 error.

The web script will return a JSON object that looks like the following:

 { "permissions": [
"ALLOWED;user1;Coordinator",
"ALLOWED;user2;Coordinator"
] ,
"inherit": false }

The return object lists the permissions in a triplet for that node. The permissions triplet follow this format:

[ALLOWED|DENIED];[USERNAME|GROUPNAME];PERMISSION

It also returns a boolean value indicating if some permissions are inherited from the parent node.

The above example shows two permissions are assigned to the node: the Coordinator permission is given to user1 and user2 on this node. Permissions are not inherited from the parent node.

permissions POST

This web script enables you to modify the permissions for a given node

It is called through the same URL as the above web script but as a POST instead of a get: /alfresco/service/permissions/{store_type}/{store_id}/{id}

Again, if the node is not found a 404 error will be returned, any missing URI parameters will result in a 400 error and if you don’t have permission to modify the node, you will get a 401 error.

You must also pass a JSON object containing the permissions that are being changed, deleted or added.

{ permissions: [
"REMOVE;user3;All",
"REMOVE;user2;All",
"ADD;user4;Coordinator",
"ADD;GROUP_usergroup1;Consumer"
] ,
"inherit": false }

The above example uses the following triplet to define a permission

[ADD|REMOVE];[USERNAME|GROUPNAME];PERMISSION

Where the values are defined as:

ADD | REMOVE: Do you want to add or remove the permission for this user/group? Any other value passed will result in a 400 error.

USERNAME | GROUPNAME: The user or group you want the permission to be added or removed for. Group names must be prefixed by GROUP_. Unknown users or groups will result in a 400 error.

PERMISSION: The supported permissions options are defined in
org.alfresco.service.cmr.security.PermissionService or through custom extension to the permission model. Unknown permissions will result in a 400 error.

The object can also contain an optional inherit permission value to specifying if the permissions for this node should be inherited from the parent node. Without the inherit option, the current value for the node is maintained. Inherited permissions can not be removed from a node.

The return format is the same as the return format of the permissions GET web script above.

This web script is also transactional: any errors will result in the node being returned to the state before the call was made. (The exception handling in the controller was added for these conditions.)

These scripts can be installed as an AMP.  The code and AMPs are hosted in the alfresco-permissions-webscripts project on Google Code.  The code is available for either pre-3.2.1 (starting with 3.1) or 3.2.1 to 3.3.1.  These are all Enterprise releases numbers.  The web scripts have been tested against these releases.  There may not be any need to modify the web scripts for Community releases (except for the min and max version numbers in the module.properties file).  Pre community 3.3 should use the pre 3.2.1 release.  No community releases have been tested. (If you try these on a community releases, please comment either here or in the Google Code Project.)

In a follow up post, I’ll cover exception handling with JavaScript.

Written by jared

August 26th, 2010 at 1:05 pm

Posted in Alfresco

Tagged with , ,

14 Responses to 'Alfresco: Permissions Web Scripts'

Subscribe to comments with RSS or TrackBack to 'Alfresco: Permissions Web Scripts'.

  1. I made a similar webscript some months ago for a customer using enterprise 3.0.

    The main problem I found is that during the permission assigment or removal you might lost permission to act on the node and as a result the transaction will fail. That became quite a pain in the ass. Finally I solved it by temporaly getting owernship of the node and setting it back to the original owner as the last action in the script.

    As far as I can see your code does not deal with this situation. Hadn’t you have such issues ?

    Igor Blanco

    2 Sep 10 at 12:52 am

  2. @Igor I have not run into this issue. I am using new versions of Alfresco as well, so if there was an underlying bug it may have been fixed.

    I believe the issue that you may be running into would be removing the owner as one of the users. It is a good test case. I’ll throw together some additional tests to see what happens.

    jared

    3 Sep 10 at 12:02 pm

  3. I’m trying to handle errors in javascript but I can’t seem to actually get a hold of the java Exception object in javascript.

    I’ve added a BaseScopeableProcessorExtension to handle some complex property manipulation. It throws a custom java Exception if it fails. The custom java exception has a custom method called: getFileName().

    I call it it using javascript in a webscript:
    try{
    var result = customExtension.doSomething();
    }
    catch(error){
    logger.log(error.getFileName();
    }

    However this throws an error saying the method doesn’t exist. I do actually catch the error, but it appears that Alfresco’s js wrapper seems to alter the java exception in a way that means I no longer have control of it. Is there any way around this? Or should I be using a declarative webscript rather than adding a js extension?

    Leander

    29 Sep 10 at 4:08 am

  4. Once a Java Exception is thrown, you’ve lost control…everything is now being rolled back in the transaction. You can catch the exception to wrap the return: specifying the FTL template to use/http return code and error message.

    All Java exceptions are going to be wrapped by the JS engine (Rhino). If you want to access the wrapped java exception you have to dig a bit deeper in to the wrapped exception.

    For example:

    catch (e if e.javaException instanceof java.lang.UnsupportedOperationException) {
    // This case will catch permissions that are unknown. Rollback is
    // handled by the framework
    status.code = 400;
    status.message = e.message+". "+work[2]+" is not a known permission.";
    status.redirect = true;
    }

    Will test to see if the exception is a javaException if a specific type. Make sure you are catching your javaException. From there you should be able start to work on it. Use the JavaScript debugger to play with the throw exception to learn what is there and what is available. One trick to remember if you are doing this is to set the caught exception (in the example above ‘e’) as a locally defined variable within the catch block (var error = e;) or you will naught be able to reference it in the debugger.

    jared

    6 Oct 10 at 9:04 am

  5. HI,

    these are exactly what I was looking for ;)

    Have your tried these Web Scripts with Alfresco 3.4(b)?

    Jusa

    12 Nov 10 at 11:09 pm

  6. I haven’t, but I can’t think of anything that has changed that might break them. If you run into any issues let me know and we can work to update them.

    jared

    13 Nov 10 at 12:58 pm

  7. Hi,

    I’m trying to use your webscripts on Alfresco 3.4

    I use AJAX:
    xhr.open(“POST”, “http://localhost/alfresco/service/permissions/workspace/SpacesStore/” + nodeid, true);
    xhr.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
    xhr.send(mypermissions);

    ( mypermissions = {“permissions”:["REMOVE;yselbonne;Coordinator","ADD;aboursin;Coordinator"]} )

    I always get this error trace :(

    ERROR [extensions.webscripts.AbstractRuntime] Exception from executeScript – redirecting to status template error: 05170002 Wrapped Exception (with status template): 05170002 Erreur lors
    du traitement du modèle ‘Expression permissions is undefined on line 3, column 24 in org/alfresco/extension/permissions/permissions.post.json.ftl.’. Veuillez contacter votre administrateur système.
    org.springframework.extensions.webscripts.WebScriptException: 05170002 Wrapped Exception (with status template): 05170002 Erreur lors du traitement du modÞle ‘Expression permissions is undefined on li
    ne 3, column 24 in org/alfresco/extension/permissions/permissions.post.json.ftl.’. Veuillez contacter votre administrateur système.
    at org.springframework.extensions.webscripts.AbstractWebScript.createStatusException(AbstractWebScript.java:758)
    at org.springframework.extensions.webscripts.DeclarativeWebScript.execute(DeclarativeWebScript.java:171)
    at org.alfresco.repo.web.scripts.RepositoryContainer$2.execute(RepositoryContainer.java:383)
    at org.alfresco.repo.transaction.RetryingTransactionHelper.doInTransaction(RetryingTransactionHelper.java:381)
    at org.alfresco.repo.web.scripts.RepositoryContainer.transactionedExecute(RepositoryContainer.java:436)
    at org.alfresco.repo.web.scripts.RepositoryContainer.transactionedExecuteAs(RepositoryContainer.java:466)
    at org.alfresco.repo.web.scripts.RepositoryContainer.executeScript(RepositoryContainer.java:304)
    at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:351)
    at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:188)
    at org.springframework.extensions.webscripts.servlet.WebScriptServlet.service(WebScriptServlet.java:118)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.alfresco.web.app.servlet.GlobalLocalizationFilter.doFilter(GlobalLocalizationFilter.java:58)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:306)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:322)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1732)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    Caused by: org.alfresco.service.cmr.repository.TemplateException: 05170002 Erreur lors du traitement du modÞle ‘Expression permissions is undefined on line 3, column 24 in org/alfresco/extension/permi
    ssions/permissions.post.json.ftl.’. Veuillez contacter votre administrateur systÞme.
    at org.alfresco.repo.template.FreeMarkerProcessor.process(FreeMarkerProcessor.java:201)
    at org.springframework.extensions.webscripts.AbstractWebScript.renderTemplate(AbstractWebScript.java:589)
    at org.springframework.extensions.webscripts.DeclarativeWebScript.renderFormatTemplate(DeclarativeWebScript.java:267)
    at org.springframework.extensions.webscripts.DeclarativeWebScript.execute(DeclarativeWebScript.java:147)
    … 28 more

    Hope you can help me :)
    Regards

    aboursin

    17 Jun 11 at 9:51 am

  8. Content-Type is incorrect. It needs to be application/json.

    jared

    17 Jun 11 at 10:00 am

  9. That’s better now but I still get an error:

    “code” : 407,
    “name” : “Proxy Authentication Required”,
    “description” : “The client MUST first authenticate itself with the proxy.”

    How can I authenticate the script (I can get a ticket using http://localhost/alfresco/service/api/login?u=admin&pw=admin but I don’t know how to give it to the permission script) ?

    Thank you for you support

    aboursin

    20 Jun 11 at 1:36 am

  10. You can add a ticket to any web script call by appending the ticket from the above call to the url being called. alf_ticket={ticket}.

    jared

    21 Jun 11 at 7:27 am

  11. Hi again :)

    I tried to authenticate in a first ajax call.
    I get a ticket and then I call the set permission webscript with ?alf_ticket.

    xhr.open(“POST”, “http://localhost/alfresco/service/permissions/workspace/SpacesStore/” + nodeid + “?alf_ticket=” + ticket, true);
    xhr.setRequestHeader(“Content-Type”, “application/json”);
    xhr.send(JSON.stringify(jsonperms));

    I still have the 407 error
    “code” : 407,
    “name” : “Proxy Authentication Required”,
    “description” : “The client MUST first authenticate itself with the proxy.”

    Do you have any idea about what I’m doing wrong?

    aboursin

    24 Jun 11 at 7:03 am

  12. The error is probably coming from the spring surf web script framework. Test making the call directly to the web script (Use curl or REST client to test) If it works then it will be an issue with the xhr request.

    jared

    5 Jul 11 at 11:54 pm

  13. Any idea how to retrieve all the node UUID from the server using RESTful? I want to set all node to inherit parent permission.

    Charles

    15 Jun 12 at 1:08 am

  14. Maybe you can explain your use case so we can better understand why you want to do this. There are areas where this is on by default and areas where it isn’t and probably shouldn’t be.

    jared

    13 Jul 12 at 12:06 pm

Leave a Reply