Resourceresolver access in services
As AEM6 had been released at the end of May 2014, we had a look at the API changes and one thing which came to our eye was that getAdministrativeResourceResolver got deprecated with the newly included Sling version which is used in AEM6.
The documentation now states that instead of getAdministrativeResourceResolver a new method called getServiceResourceResolver should be used.
The reason for this change is mainly to improve security and prevent abuse of this method, as (pre AEM6 era) many developers just use getAdministrativeResourceResolver due to its convenience.
So how can we use getServiceResourceResolver method?
Lets have a look at the following use case:
- ReadService should only be allowed read access rights on /content/mydata
- WriteService on the other hand should be allowed read / write access rights on /content/mydata
Setting up a new project
We start off by setting up a new project with the maven archetype and changing the dependency (with the new convenient dependency which includes all AEM dependencies in one ) to the ones from AEM6.
Next, we will create two new users readuser and writeuser with the appropriate access rights. Then we will create the two services which actually use the user based resource resolvers.
@Service
@Component(immediate=true)
public class WriteServiceImpl implements WriteService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference
private ResourceResolverFactory resolverFactory;
@Activate
public void doAWriteOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "writeService");
ResourceResolver resolver = null;
try {
resolver = resolverFactory.getServiceResourceResolver(param);
log.info(resolver.getUserID());
Resource res = resolver.getResource("/content/mydata/jcr:content");
ValueMap readMap = res.getValueMap();
log.info(readMap.get("jcr:primaryType", ""));
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);
if(modMap != null){
modMap.put("myKey", "myValue");
resolver.commit();
log.info("Successfully saved");
}
} catch (LoginException e) {
log.error("LoginException",e);
} catch (PersistenceException e) {
log.error("LoginException",e);
}finally{
if(resolver != null && resolver.isLive()){
resolver.close();
}
}
}
}
@Service
@Component(immediate=true)
public class ReadServiceImpl implements ReadService{
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference
private ResourceResolverFactory resolverFactory;
@Activate
public void doAReadOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "readService");
ResourceResolver resolver = null;
try {
resolver = resolverFactory.getServiceResourceResolver(param);
log.info(resolver.getUserID());
Resource res = resolver.getResource("/content/datatoreadandwrite/jcr:content");
ValueMap readMap = res.getValueMap();
log.info(readMap.get("jcr:primaryType", ""));
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);
if(modMap != null){
modMap.put("myKey", "myValue");
resolver.commit();
log.info("Successfully saved");
}
} catch (LoginException e) {
log.error("LoginException",e);
} catch (PersistenceException e) {
log.error("LoginException",e);
}finally{
if(resolver != null && resolver.isLive()){
resolver.close();
}
}
}
}
The only difference between those services, is the different ResourcerResolverFactory.SUBSERVICE parameter which is passed.
Are you looking for Adobe Experience Manager developpers?
Map the users to the corresponding services
In the final step we will map the users to the corresponding services. This can be done via a configuration called “Apache Sling Service User Mapper Service” which is configurable in the OSGI configuration admin interface. There we add the following two entries:
ch.inside.cqblog-bundle:readService=readuser
ch.inside.cqblog-bundle:writeService=writeuser

As described in the description, a new configuration has to be configured like this:
‘serviceName [ “:” subServiceName ] “=” username’.
- serviceName: The symbolic name of the bundle which provides this service.
- subServiceName: The value of the passed attribute with the ResourceResolverFactory.SUBSERVICE key.
- username: The username of the user which should be mapped with this service.
(A bundle wide configuration can be achieved when subServiceName is omitted.)
After installing the bundle, we should now see the following two entries in the log file:
*INFO* ch.inside.cqblog.impl.ReadServiceImpl readuser
*INFO* ch.inside.cqblog.impl.ReadServiceImpl nt:unstructured
*INFO* ch.inside.cqblog.impl.WriteServiceImpl writeuser
*INFO* ch.inside.cqblog.impl.WriteServiceImpl nt:unstructured
*INFO* ch.inside.cqblog.impl.WriteServiceImpl Successfully saved
As you can see, will not even retrieve a ModifiableValueMap if the access rights aren’t sufficient.
This new configuration possibility offers an easy way to map resource resolver to users when retrieved over getServiceResourceResolver.
Looking for more great ressources?
Subscribe to our newsletter and we will send you the next article about Adobe Experience Manager.
We’re using cookies to provide you with a better user experience of our website, e.g. by storing your preferred language. By using our website you’re accepting the usage of cookies.