April 1, 2020
Estimated Post Reading Time ~

How to Use Sessions and Resource Resolver through Service Authentication In AEM 6

Use Case: As per http://sling.apache.org/documentation/the-sling-engine/service-authentication.html and http://docs.adobe.com/content/docs/en/aem/6-0/develop/ref/diff-previous/changes/changes-summary.html using admin session and admin resource resolver through ResourceresolverFactory is now deprecated. Using Service based Authentication for Resourceresolver and Respository session solves problem like (Directly From Sling Doc),

Prevent over-use and abuse of administrative ResourceResolvers and/or JCR Sessions
Allow services access to ResourceResolvers and/or JCR Sessions without requiring to hard-code or configure passwords
Allow services to use service users which have been specially configured for service level access (as is usually done on unixish systems)
Allow administrators to configure the assignment of service users to services

Solution:
NOTE: Use Service Accounts for alice and bob users [jcr:primaryType=rep:SystemUser] instead of regular accounts.

Lets see we have two user "alice" and "bob", with following property,

"alice" only have READ access to document under /content/somepath path
"bob" has both read and write access to document under /content/somepath path
Now we have two service "ReadService" and "WriteService", with following property

ReadService should only be allowed to read anything under /content/somepath path
WriteService should be allowed for both read and write under /content/somepath path

Assume your package name is blog.aem4beginner.com
Step 1: Create ReadService and WriteService using resourceResolver Or adminSession using new Authentication Service based API

@Service
@Component(immediate=true)
public class WriteServiceImpl implements WriteService {

private final Logger log = LoggerFactory.getLogger(getClass());

@Reference
private ResourceResolverFactory resolverFactory;

//If you are planning to use repository session
//@Reference
//private SlingRespository repository;
//private Session session = null;

@Activate
public void doAWriteOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "writeService");
ResourceResolver resolver = null;
try {
//Deprecated Method using admin resolver
//resolver = resolverFactory.getAdministrativeResourceResolver(null);
resolver = resolverFactory.getServiceResourceResolver(param);
//If you are planning to use repository session instead of repository.loginAdministrative
//session = repository.getService("writeService",null);
log.info(resolver.getUserID());
Resource res = resolver.getResource("/content/somepath");
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();
}
//Close session if you are using session
}
}
}

view rawWriteService.java hosted with ❤ by GitHubStep 2: Create ReadService same way


@Service
@Component(immediate=true)
public class ReadServiceImpl implements ReadService{

private final Logger log = LoggerFactory.getLogger(getClass());

@Reference
private ResourceResolverFactory resolverFactory;

//If you are planning to use repository session
//@Reference
//private SlingRespository repository;
//private Session session = null;

@Activate
public void doAReadOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "readService");
ResourceResolver resolver = null;
try {
//Deprecated Method using admin resolver
//resolver = resolverFactory.getAdministrativeResourceResolver(null);
resolver = resolverFactory.getServiceResourceResolver(param);
//If you are planning to use repository session instead of repository.loginAdministrative
//session = repository.getService("readService",null);
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();
}
//Close session if you are using session
}
}
}

view rawReadService.java hosted with ❤ by GitHubStep 3: Update org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl config by creating osgi:config node under /apps/<your-apps>/config.<Place where you want to run this>/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml you can directly go to osgi config through Felix console and change this as well look for “Apache Sling Service User Mapper Service” for that.



Syntax for service mapping to user is ‘serviceName [ ":" subServiceName ] “=” username’.
and Entry of OSGI config will look like this,

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
user.mapping="[com.adobe.granite.oauth.server=oauthservice,com.adobe.granite.oauth.server:authentication-handler=admin,com.day.cq.cq-search-suggest=suggestionservice,blog.
aem4beginner.com:writeService=bob, blog.aem4beginner.com:readService=alice]"/>


After installing the bundle and configuration and code, You would see something like this in log

*INFO* blog.
aem4beginner.com.ReadServiceImpl alice
*INFO* blog.
aem4beginner.com.ReadServiceImpl <node type of somepath>

*INFO* blog.
aem4beginner.com.WriteServiceImpl bob
*INFO* blog.
aem4beginner.com.WriteServiceImpl <node type of somepath>
*INFO* blog.
aem4beginner.com.WriteServiceImpl Successfully saved

If you need to use an admin session for the configuration you can do something like a blog.
aem4beginner.com:WriteService=admin in osgi config above. Good practice is to have these session based on groups depending upon which group have access to what service.

You might need following dependencies in your POM for API to be available

<dependency>
    <groupid>com.adobe.aem</groupid>
    <artifactid>aem-api</artifactid>    <version>6.0.0.1</version>    <scope>provided</scope>
</dependency>


Please check http://stackoverflow.com/questions/31350548/resourceresolverfactory-getserviceresourceresolver-throws-exception-in-aem-6-1 with some of the changes in AEM6.1 of how to use this.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.