Friday, March 23, 2012

How to Use Crypto support in Adobe CQ / AEM

Use Case: You want to protect sensitive information in OSGI configuration

Solution: CQ > 5.5 (Granite platform) introduces a new crypto cupport service (com.adobe.granite.crypto.CryptoSupport) to protect sensitive information.

To store protected configuration, the Apache Felix Web Console should be used.

to unprotected data you can use CryptoSupport.unprotect(String) method.


public class Test {
private CryptoSupport cryptoSupport;
private void configure(Map config) {
final String protectedConfig = config.get("password");
final String plainTextConfig;
if (this.cryptoSupport.isProtected(protectedConfig)) {
plainTextConfig = this.cryptoSupport.unprotect(protectedConfig);
} else {
plainTextConfig = protectedConfig;

You can also use crypto support JSON call to get data. For example following curl command will return protected sting you can use

$ curl -uadmin:admin -F datum=password http://localhost:4502/system/console/crypto/.json
{"protected": "{4dd7095d321134b5e6737311fa82afaa335390762e43136ee8acb3897296865d}"}

Note: Crypt generated on one machine will not work on other machine as each one has different Key. In order to make key work across all instance, You can create package of /etc/key and install it in all instances and then restart "com.adobe.granite.crypto" bundle from system console.

If you want to deploy these key as part of code across all instances then first down load hmac and master binary from /etc/key

then create a node under /etc/key in your file system (Code repo)

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="" xmlns:jcr="" xmlns:rep="internal"

under /etc/key add two files name "hmac.binary" and "master.binary" that you copied from system where secret was generated.

Deploy your code. Make sure to restart "com.adobe.granite.crypto" for very first time you upload these key. (You can also do this using CURL command)

Crypto Suport API:

How to create encoded password that you can use for curl in CQ / WEM

Use Case: In Curl command most of the time you have to enter user credentials to perform CRUD operation. Some people might have security concern sharing admin password with other users.

Solution: You can use following java program to create encrypted password that you can use in curl command


public class Test {
public static void main(String[] args) {
String password = "admin";
try {
for (byte x : password.getBytes("UTF-8")) {
System.out.print("%" + Integer.toHexString((x & 255) + 256).substring(1));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block


1) Create
2) Copy paste above code
3) Run program by changing password value (Or pass it through command line arg)
4) Use output of program to use it in CURL

Special thanks to Thomas Mueller From Adobe for providing this information.

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();
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


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

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

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


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,

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/

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/

Remove a User from a Group

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

Set a User’s Group Memberships

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

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):

For previous version you can try to use jar file from

Read Permission:

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


$ 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:

Sling Doc:


Special Thanks to Justin Edelson from Adobe to provide this information

Tuesday, March 20, 2012

How to run online backup / Datastore GC / Tar Optimization using curl in CQ5.5

Use case: Curl command for online backup / Datastore GC / Tar Optimization for CQ5.4 does not work for CQ5.5 any more

Reason: Many CRX related operation is moved to JMX. Now you can use any JMX console or JMX API to invoke these operations.

Solution: You can use following curl commands

For online backup

curl -u <UID>:<PASSWORD> -X POST http://<HOST>:<PORT>/system/console/jmx/com.adobe.granite:type=Repository/op/startBackup/java.lang.String?target=<PATH OF BACKUP>/

Following options are available for backup

Delay (Default is 10 mili second)

curl -u <UID>:<PASSWORD> -X POST

Note After running this from front end you will see (null) as response. You have to check CRX log to verify if backup started. In CRX log (/crx-quickstart/logs/error.log) you would see message like this

*INFO* [Backup Worker Thread] Backup started.
*INFO* [Backup Worker Thread] Read size (1.234 gb) in 1.97s

OR Use following CURL for online backup

curl -u admin:admin --data "delay=3&force=false&" http://HOST:PORT/libs/granite/backup/content/admin/backups/

delay: Time delay between write block.
force: To override last one
Target: Absolute path of backup. If path is not provided and just file name is given, Then it will use current path of installation.

Once backup is started, You can cancel it using following curl command

curl -u admin:admin http://HOST:PORT/libs/granite/backup/content/admin/backups.cancel.html

You can also track online progress using following URL


For Datastore GC

curl -u <UID>:<PASSWORD> -X POST http://<HOST>:<PORT>/system/console/jmx/com.adobe.granite:type=Repository/op/runDataStoreGarbageCollection/java.lang.Boolean

To delete data and delay as 2

curl -u admin:admin -X POST --data "delete=true&delay=2" http://HOST:PORT/system/console/jmx/com.adobe.granite%3Atype%3DRepository/op/runDataStoreGarbageCollection/java.lang.Boolean

CRX Log message to look for

*INFO* [ [1332343886706] POST /system/console/jmx/com.adobe.granite%3Atype%3DRepository/op/runDataStoreGarbageCollection/java.lang.Boolean HTTP/1.1] Scanning /libs/wcm/core/content/siteadmin/actions/create/menu/createPage

Automate DataStore GC (AEM 5.6 onward)

Option 1: Using Configuration

create new configuration name 

<some path for config>/ with following values

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="" xmlns:cq="" xmlns:jcr=""
    jobName="Datastore Garbage Collector"
    schedule="00 00 23 ? * SUN"
    deleteNodes="{Boolean}true" />

This mean that run Datastore Garbage collection every Sunday at 11 PM.

Option 2: Using CURL and CRON job. Create a Cron job on your machine and run CURL command given above.

For Tar optimization

curl -u <UID>:<PASSWORD> -X POST http://<HOST>:<PORT>/system/console/jmx/com.adobe.granite:type=Repository/op/startTarOptimization/

CRX Log Message to look for /crx-quickstart/repository/workspaces/crx.default/data_00000.tar id:0 length:75436032 append:75435008 943288331 optimize: 2420224

Similarly you can use CURL command to different JMX operation listed in


How to identify master using Curl Command And then run backup only on master

ISMASTER=`curl -s -u admin:admin http://HOST:PORT/system/console/jmx/com.adobe.granite:type=Repository | grep -A 1 crx.cluster.master | sed 's/\<\/*td\>//g' | awk 'NR>1' | awk '{ print $1 }'`
if [ $ISMASTER != 'true' ]; then
echo "Not running backup, that is the slave node";
exit 1;
echo "Running online backup this is master Node"
# Your curl command for online backup goes here

Special Thanks to Andrew Khoury from Adobe for providing this CURL command.

Use firebug to get complete URL and then replace it in above curl command.

Friday, March 16, 2012

How To Integrate a SOAP Web-Service Toolkit with Adobe CQ / WEM

Very nice blog post for this can be found here



For Axis 2

Method 1
1) Create Axis2 Fragment bundle using this pom.xml (You might have to change Export-Package section based on your project)
2) Already created Axis2 fragment bundle can be downloaded from here (This is working for OOTB CQ5.4)
3) Put this to install folder of your application. Make sure that it is in fragment state in OSGI
4) Restart your instance (Fragment bundle resolution will take place upon restart)

Note If you have custom jar that uses Axis2. You can put them under libs folder (To same level where your pom.xml or bnd file is).

Make sure that you have following entry in bnd file

Import-Package: *;resolution:=optional
Private-Package: *
Dynamic-Import: *
Embed-Dependency: *;scope=compile|runtime
Embed-Directory: /libs
Embed-Transitive: true

Method 2 (Method 1 is recommended)
If you are keen to use Axis2 with CQ5.X. I have compiled set of OSGI bundle that you can use for this.

1) Download all bundles from here
2) Put them in /apps//install folder
3) Use Axis2 API in your project
4) All Jar file (Non OSGI) can be found here
5) Also see how to convert Jar file in to OSGI bundle
6) Make sure that you put all non OSGI class file in bundle class path of your custom OSGI bundle where you are using Axis2 API.
7) If you ar using Maven, You can use this pom.xml dependencies

<!-- Axis2 Dependencies -->

Please test it before use. Axis2 Integration is still work in progress .. I will update once have concrete result

Tuesday, March 6, 2012

How to change Admin password in CQ5.5

Use case Change admin password

Good news Till now you have to change admin password at multiple location if you are using CQ5.4, see here

From CQ5.5 onward you just have to change admin password once. There are multiple ways though,

1) Using CRX explorer (Old way)

2) Using granite http://host:port/libs/granite/security/content/admin.html#edit:/home/users/a/admin

3) using curl command

curl -u admin:OLD_PWD -F rep:password="NEW_PWD" http://host:port/home/users/a/

You can also use security API for do user related task, Something like this

curl -d "createUser=true&authorizableId=$userId&rep:password=pw&membership=administrators" -u "admin:admin" http://host:port/libs/granite/security/post/authorizables

(There is set of operation you can do using this, JAVA DOC coming soon)

For any other user other than admin you can use CURL to change password as

curl rep:password="test" --user admin:ADMIN_PASSWORD http://host:port/home/users/a/

You still have to use CURL command to change replication agent password mention here

For CQ5.6:

Above curl command does not work for CQ 5.6 instead use this command to change admin password

curl -u admin:<OLD PASSWORD> -Fplain=<NEW PASSWORD> -Fverify=<NEW PASSWORD>  -Fold=<OLD PASSWORD> -FPath=/home/users/a/admin http://HOST:PORT/crx/explorer/ui/setpassword.jsp

BELOW DOES NOT WORK IN CQ5.6 thats why have strike. Looking in to this.

You can also try to change password of a USER. For that you first have to download and then install it using felix console or through your code.

Note For all cases you need current admin password to perform operation. As always please test it before use.

Thanks Alex from Adobe for Helping.

Sunday, March 4, 2012

How to expose a class through JMX in CQ5.5 / WEM

Use case: Starting with CQ5.5 / CRX2.3, JMX has eventually been integrated to expose various repository related statistics and information. There are also certain operations that can be triggered via JMX, such as online backup or TarPM optimization.

The Felix Console comes with a dedicated JMX plugin to access the JMX interface.

You can use any JMX client (Visual VM, Jconsole) to perform these operation, Here is screen shot of how it will look like

You can also perform JMX related operation through felix console

The main 2 classes that provide JMX information and data in CRX are as follows:
The former is an interface which defines the methods being exposed to JMX. These methods can be either read-only, so purely informative or writeable as well in which case e.g. configuration settings can be adjusted during runtime.

Creating custom JMX classes

Creating custom so called MBean classes is also quite straightforward. In the end, such classes are plain OSGi components that need to declare the interface, these are then automatically discovered during deployment and registered with JMX.

Here is sample class

package com.adobe.test;

import com.adobe.granite.jmx.annotation.Description;

@Description("JMX MBean example")
public interface JMXTestMBean {
@Description("Get bean name")
public String getName();
@Description("Get Bean Id")
public String getId();
@Description("Get repository Description")
public String getRepositoryName();

And implementation

package com.adobe.test.impl;


import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;

import com.adobe.test.JMXTestMBean;

@Property(name="jmx.objectname", value="com.adobe.test:type=test")
public class JMXTestMBeanImpl extends StandardMBean implements JMXTestMBean {

@Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private SlingRepository repository;

public JMXTestMBeanImpl() throws NotCompliantMBeanException {

protected String getDescription(MBeanInfo arg0) {
return "MBean Test example";

protected String getDescription(MBeanAttributeInfo mBeanAttributeInfo) {
return "MBean Attribute";

public String getName() {
// TODO Auto-generated method stub
return "Test JMX Bean";

public String getId() {
// TODO Auto-generated method stub
return "v0.1";

public String getRepositoryName(){
return repository.getDescriptor("");


You can get entire package from here