Wednesday, March 21, 2012

How to do user management using POST API / CURL in CQ5.5

Use case There is a new POST API you can use to do user / Group / ACL / Profile management in CQ5.5

Solution You can use POST command (Using Curl to perform these operations as well)

HttpClient client = new HttpClient();
client.getState().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("admin", "admin"));


To create User
PostMethod post = new PostMethod("http://localhost:4502/libs/granite/security/post/authorizables");
post.addParameter("createUser", "");
post.addParameter("authorizableId", "<uid>");
post.addParameter("rep:password", "<pwd>");

You can do following set of operations using /libs/granite/security/post/authorizables


deleteAuthorizable
createUser
createGroup


Add member
PostMethod post = new PostMethod("http://localhost:4502/home/groups/m/mygroup.rw.html");
post.addParameter("addMembers", user);

Remove Member
PostMethod post = new PostMethod("http://localhost:4502/home/groups/m/mygroup.rw.html");
post.addParameter("removeMembers", user);

You can do following set of operations using /home/<Path to user or group>.rw.html

disableUser
addImpersonators
removeImpersonators
addMembers
removeMembers
membership


This is just few thing you can do using new Security API. There are many services to perform read operations. Complete set is available with Very Nice detailed Java Doc under,

com.adobe.granite.security.user.servlets

Links to come.

Some Curl Command example

Get User Info

$ curl -u admin:admin http://localhost:4502/libs/granite/security/<username>.json

Create User

$ curl -u admin:admin -FcreateUser= -FauthorizableId=testuser -Frep:password=test http://localhost:4502/libs/granite/security/post/authorizables

Create Group

$ curl -u admin:admin -FcreateGroup= -FauthorizableId=testGroup1 http://localhost:4502/libs/granite/security/post/authorizables

Create user with Profile

$ curl -u admin:acreateUser= -FauthorizableId=testuser -Frep:password=test -Fprofile/<Property>=propertyvalue http://localhost:4502/libs/granite/security/post/authorizables

Set a Profile Property on an Existing User

$ curl -u admin:admin -Fprofile/<Property>=propertyvalue http://localhost:4502/home/users/t/testuser1.rw.html

Create a User as a Member of a Group

$ curl -u admin:admin -FcreateUser= -FauthorizableId=testuser -Frep:password=mypassword -Fmembership=contributor http://localhost:4502/libs/granite/security/post/authorizables

Add a User to a Group

$ curl -u admin:admin -FaddMembers=testuser http://localhost:4502/home/groups/t/testGroup.rw.html

Remove a User from a Group

$ curl -u admin:admin -FremoveMembers=testuser http://localhost:4502/home/groups/t/testGroup.rw.html

Set a User’s Group Memberships

$ curl -u admin:admin -Fmembership=contributor -Fmembership=author http://localhost:4502/home/users/t/testuser.rw.html

Delete user and Group

$ curl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/users/t/testuser

$ curl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/groups/t/testGroup

Permission Management (CQ5.6 onward):

http://sling.apache.org/documentation/bundles/managing-permissions-jackrabbit-accessmanager.html

For previous version you can try to use jar file from http://mvnrepository.com/artifact/org.apache.sling/org.apache.sling.jcr.jackrabbit.accessmanager

Read Permission:

$ curl -u admin:admin -F:applyTo=myuser http://localhost:4502/<Path>.acl.json

OR

$ curl -u admin:admin -F:applyTo=myuser http://localhost:4502/<Path>.eacl.json


Delete Permission:

$ curl -u admin:admin -F:applyTo=myuser http://localhost:4502/<Path>.deleteAce.html

Modify Permission:

$ curl -u admin:admin -FprincipalId=<Some User> -Fprivilege@jcr:all=granted http://localhost:4502/<Path>.modifyAce.html



API Doc:
http://dev.day.com/docs/en/cq/5-5/javadoc/com/adobe/granite/security/user/servlets/AuthorizableServlet.html

Sling Doc:

http://sling.apache.org/site/managing-users-and-groups-jackrabbitusermanager.html

Code:

http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/

Special Thanks to Justin Edelson from Adobe to provide this information

43 comments:

  1. I have incorporated this information and other stuff I've found through experimenting into the cq5-users script in https://github.com/42Lines/cq5tools which works with both 5.4 and 5.5. Hopefully this script will save others time.

    ReplyDelete
    Replies
    1. Hi Jim,

      Create user is working perfectly fine but the addmembers to group is not working. I am trying it in CQ5.4. I tried the following command to add existing member to a group

      curl -s --data addMembers=curltest1@verizon.com --user admin:admin http://localhost:9091/home/groups/a/administrators.rw.html

      Please correct me if i am doing anything wrong here

      Waseem

      Delete
    2. I figured it out myself...

      To add a member curltest3@test.com to group administrators use the command below

      curl -s -u admin:admin -F :status="browser" -F _charset_="utf-8" -F memberAction="memberOf" -F memberEntry="administrators" http://localhost:9091/home/users/c/curltest3@test.com

      Then to remove this user from administrators use the following command

      curl -s -u admin:admin -F :status="browser" -F _charset_="utf-8" -F memberAction="memberOf" -F memberEntry="" http://localhost:9091/home/users/c/curltest3@test.com

      Delete
    3. @Waseem,

      Granite security API is not supported in CQ5.4 thats why <user/group>.rw.html does not work for CQ5.4

      Delete
  2. Jim,

    Thanks for sharing .. I guess your script will apply for CQ5.4 .. For CQ5.5 you could use granite platform API (Post servlet) to manage user / group.

    Yogesh

    ReplyDelete
  3. The script works with 5.5 as well. I prefer to using the script to stringing together a curl command.

    ReplyDelete
  4. @Jim,

    Yes, Script will work with CQ5.5, what I meant to say that you can use new concise API for CQ5.5 for user and profile management. I have listed some curl command for CQ5.5 that you can use. Hopefully it will help.

    Yogesh

    ReplyDelete
  5. @Jim,

    By the way .. Your scripts are really good .. will love to see more of those to manage different task.

    Yogesh

    ReplyDelete
  6. I would love scripts to show a given page's last activation & modified time


    --
    Sun

    ReplyDelete
    Replies
    1. @Sun,

      That wouldn't be difficult at all see this http://www.wemblog.com/2011/10/how-to-find-all-pages-modified-or.html for example to get query which you could use it in CURL command.

      Delete
  7. Interesting article. Do you know of a similar technique to curl html fragments into par/text nodes?
    E.g., something along this line:
    curl -u foo:bar -v -F":operation=import" -F":contentType=jcr:html" -F":name=news" -F":contentFile=@file.html" http://localhost:4502/content/aaa/en/jcr:content/par/text

    ReplyDelete
    Replies
    1. @Parker,

      Yes, I guess you can do that .. I use following example some time

      curl -u admin:admin -F:operation=copy -F:dest=DEST SOURCE. You can find all servlet post operation here http://sling.apache.org/site/manipulating-content-the-slingpostservlet-servletspost.html

      Delete
  8. When I run this command with CQ5.5 instance-$ curl -u admin:admin http://localhost:4502/libs/granite/security/.json, I am getting the below error. Please help.
    No resource found

    Cannot serve request to /libs/granite/security/admin.json in /libs/sling/servlet/errorhandler/404.jsp

    Request Progress:

    0 (2012-05-10 09:52:04) TIMER_START{Request Processing}
    0 (2012-05-10 09:52:04) COMMENT timer_end format is {,}
    0 (2012-05-10 09:52:04) LOG Method=GET, PathInfo=/libs/granite/security/admin.json
    0 (2012-05-10 09:52:04) TIMER_START{ResourceResolution}
    0 (2012-05-10 09:52:04) TIMER_END{0,ResourceResolution} URI=/libs/granite/security/admin.json resolves to Resource=NonExistingResource, path=/libs/granite/security/admin.json
    0 (2012-05-10 09:52:04) LOG Resource Path Info: SlingRequestPathInfo: path='/libs/granite/security/admin.json', selectorString='null', extension='json', suffix='null'
    0 (2012-05-10 09:52:04) TIMER_START{ServletResolution}
    0 (2012-05-10 09:52:04) TIMER_START{resolveServlet(NonExistingResource, path=/libs/granite/security/admin.json)}
    0 (2012-05-10 09:52:04) LOG {0}: no servlet found
    0 (2012-05-10 09:52:04) TIMER_END{0,resolveServlet(NonExistingResource, path=/libs/granite/security/admin.json)} Using servlet org.apache.sling.servlets.get.DefaultGetServlet
    0 (2012-05-10 09:52:04) TIMER_END{0,ServletResolution} URI=/libs/granite/security/admin.json handled by Servlet=org.apache.sling.servlets.get.DefaultGetServlet
    0 (2012-05-10 09:52:04) LOG Applying Requestfilters

    ReplyDelete
    Replies
    1. @murali
      Command is curl -u admin:admin http://localhost:4502/libs/granite/security/<username>.json

      Delete
  9. I am able to create multiple groups with below code and would like to attach specific permissions to groups with granite API. Can you give some pointers?

    public static void createGroup(String groupId, String groupName) {
    String repoURL = "http://localhost:4502/libs/granite/security/post/authorizables";
    PostMethod post = new PostMethod(repoURL);
    NameValuePair[] formData = {
    new NameValuePair("createGroup", groupId),
    new NameValuePair("authorizableId", groupId),
    new NameValuePair("name_xss", groupName),
    new NameValuePair("givenName", groupName),
    new NameValuePair("name", groupName),
    new NameValuePair("home", "/home/groups/abc/pqr")
    };
    post.setRequestBody(formData);
    HttpClient client = new HttpClient();
    client.getState().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
    new UsernamePasswordCredentials("admin", "admin"));
    String response = null;
    int status;
    try {
    status = client.executeMethod( post );
    response = post.getResponseBodyAsString();
    System.out.println("response:status - " + response + ":" + status);
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    post.releaseConnection();
    }
    }

    ReplyDelete
    Replies
    1. Hello,

      You can not apply permission using granite POST API. Here is one example of how you can create permission using API http://wemcode.wemblog.com/add-acl-to-node. I guess using post you might have to create /content/rep:policy and then /content/rep:policy/allow or deny with property to create permission. But Never tested it.

      Yogesh

      Delete
    2. Hi Yogesh,

      I'm able to create the user by using the below code but all it's property is set at the node level instead of profile level i.e under the user node profile node is there where it should get set exactly...Can u please suggest me what will i do..Thanx

      String userFullName = firstName + " " + lastName;
      String repoURL = "http://localhost:5402/libs/granite/security/post/authorizables";
      PostMethod post = new PostMethod(repoURL);
      NameValuePair[] formData = {
      new NameValuePair("createUser", userId),
      new NameValuePair("authorizableId", userId),
      new NameValuePair("name_xss", userFullName),
      new NameValuePair("givenName", firstName),
      new NameValuePair("familyName", lastName),
      new NameValuePair("rep:password", password),

      };

      post.setRequestBody(formData);
      if(incomingData!=null && incomingData.length!=0){
      post.addParameters(incomingData);
      }
      HttpClient client = new HttpClient();

      client.getState().setCredentials(
      new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
      new UsernamePasswordCredentials("admin", "admin"));
      String response = null;
      int status;
      try {
      status = client.executeMethod(post);
      response = post.getResponseBodyAsString();
      System.out.println("response:status - " + response + ":"
      + status);
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      post.releaseConnection();
      }
      }

      Delete
    3. I am wondering if its possible to create Profile node using Post command.Any help Yogesh?

      Delete
  10. I would like to use curl to list all users. Where are the possible values for the memberAction parameter documented?

    Thank you.

    ReplyDelete
    Replies
    1. You can find all available property here http://dev.day.com/docs/en/cq/current/javadoc/com/adobe/granite/security/user/servlets/AuthorizableServlet.html You can additionally use query builder API to get this data as well

      Delete
    2. Bill,

      I have created a tool to list all members of group in table formate. Please see http://wemcode.wemblog.com/listmem

      Yogesh

      Delete
  11. Some facts and other informative points given here are quite considerable and to the point as well would be so far better to look for more of this kind to have better results.

    ReplyDelete
  12. There is actually a bug in the addMembers API. If your members happen to contain non-ascii characters, you have to send a URL-encoded UTF-8 string. For example, if you need to add a principal called «ü» to a group then you actually have to send

    addMembers=%C3%BC

    instead of the raw byte stream (which works properly when you actually create that principal or do any other kind of mutations on that object).

    Swen

    ReplyDelete
    Replies
    1. Thank you pointing that out Swen. However I feel this should be handled by product. Please create a enhancement request with Adobe to fix this.

      Yogesh

      Delete
  13. This comment has been removed by a blog administrator.

    ReplyDelete
  14. How can disable the user using cURL?

    I have tried below one but its not working:

    curl -u admin:admin -Frep:disabled=true http://localhost:4502/home/users/t/testuser.rw.html

    getting below error message:

    javax.jcr.nodetype.ConstraintViolationException: Unable to perform operation. Node is protected.

    ReplyDelete
  15. I have tried the Modify Permission command but it returns the following error. Can you please give me some advice? I am currently using CQ5.5 for my project

    ==============================================================================
    Error while processing /content

    Status
    500
    Message
    javax.jcr.RepositoryException: Failed to resolve path privilege@jcr:all relative to node /content
    Location /content
    Parent Location /
    Path
    /content
    Referer
    ChangeLog

    Go Back

    Modified Resource

    Parent of Modified Resource
    ========================================================================

    below is the command I run:

    curl -u admin:admin -FprincipalId=testuser -Fprivilege@jcr:all=granted http://localhost:4502/content.modifyAce.html

    Thanks!

    ReplyDelete
    Replies
    1. Also can you try to install http://mvnrepository.com/artifact/org.apache.sling/org.apache.sling.jcr.jackrabbit.accessmanager/2.1.0 in your CQ instance and try again if above does not work.

      Yogesh

      Delete
    2. Thanks, it works after I installed the osgi bundle to my CQ instance

      But can the POST API grant replicate permission of a node to a principal?

      I tried the follow command:
      curl -u admin:admin -FprincipalId=test_group -Fprivilege@crx:replicate=granted http://localhost:4502/content/geometrixx.modifyAce.html

      But it returns 500 and the error msg as follow:

      javax.jcr.nodetype.ConstraintViolationException: no matching property definition found for {}principalId

      Please advice

      Delete
    3. Hello KO,

      Are you still facing this issue ?

      Yogesh

      Delete
  16. HttpClient client = new HttpClient();
    client.getState().setCredentials(
    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
    new UsernamePasswordCredentials("admin", "admin"));
    PostMethod post = new PostMethod("http://localhost:4502/libs/granite/security/post/authorizables");
    post.addParameter("createUser", "csimms");
    post.addParameter("authorizableId", "csimms");
    post.addParameter("rep:password", "password");
    Session session = null;
    try {
    int status = client.executeMethod(post);

    when I execute the above code, I get the following error
    javax.jcr.AccessDeniedException: Missing permission to create intermediate authorizable folders.

    any ideas what I am doing wromg
    I am able to create new user using curl command

    ReplyDelete
    Replies
    1. Hello Girish,

      Does CURL command works for you to create user ?

      Yogesh

      Delete
  17. I'd like to know if there is a way that inactive (say 90 days without logging in) users can be deactivated or deleted. A way to automatically deactivate accounts would be ideal, however, a report would be sufficient.

    Thank you.

    ReplyDelete
    Replies
    1. Logu,

      This feature is not available OOTB. However you can implement this by creating custom auth handler that will set login time stamp and then a scheduler that will go through all users and delete them if time stamp is greater than 90 days. See example of token auth handler which sets login token and then there is a scheduler which cleans those token after 24 hour.

      Yogesh

      Delete
  18. I am using CQ 5.6.1 and tried the above command to get the user information to find users group.
    But while accessing the command in browser, i got the error page as below. Can you help on this?
    URL : http://:4502/libs/granite/security/kumasa05.json

    No resource found

    Cannot serve request to /libs/granite/security/kumasa05.json in /apps/sling/servlet/errorhandler/404.jsp

    Request Progress:

    0 (2014-10-09 16:28:13) TIMER_START{Request Processing}
    0 (2014-10-09 16:28:13) COMMENT timer_end format is {,}
    0 (2014-10-09 16:28:13) LOG Method=GET, PathInfo=/libs/granite/security/kumasa05.json
    0 (2014-10-09 16:28:13) TIMER_START{ResourceResolution}

    ReplyDelete
    Replies
    1. URL : http://HOSTNAME:4502/libs/granite/security/kumasa05.json

      Delete
  19. This comment has been removed by the author.

    ReplyDelete
  20. How can I assign an user to multiple groups?

    I use this command to assign a member to a group and it works.

    curl -s -u admin:admin -F :status="browser" -F _charset_="utf-8" -F memberAction="memberOf" -F memberEntry="cadence-public-acountholder" http://localhost:4502/home/users/t/testuser8@mailinator.com

    Issue is if I use this same command to assign the user to different group it removes the user from the earlier group and adds him to the new group.

    Any help would be much appreciated.


    Thank you!
    Vishwanath

    ReplyDelete
  21. Cannot serve request to /projects.html in org.apache.sling.servlets.get.DefaultGetServlet

    ReplyDelete
  22. Not Found

    Cannot serve request to /etc/replication/agents.author/flush.html in org.apache.sling.servlets.get.DefaultGetServlet

    Request Progress:

    0 TIMER_START{Request Processing}
    0 COMMENT timer_end format is {,}
    0 LOG Method=GET, PathInfo=/etc/replication/agents.author/flush.html
    0 TIMER_START{ResourceResolution}
    1 TIMER_END{1,ResourceResolution} URI=/etc/replication/agents.author/flush.html resolves to Resource=JcrNodeResource, type=cq:Page, superType=null, path=/etc/replication/agents.author/flush
    1 LOG Resource Path Info: SlingRequestPathInfo: path='/etc/replication/agents.author/flush', selectorString='null', extension='html', suffix='null'
    1 TIMER_START{ServletResolution}

    ReplyDelete