Thursday, July 6, 2017

Exposing the resources through OAuth - AEM

This post will explain the approach to expose the resources through OAuth in AEM.

Refer for the basic configurations to expose the the resources thorough OAuth.

Exposing /etc/designs/geometrixx/static.css through OAuth

Configure the "Allowed Scope" as "/etc/designs/geometrixx"(based on the resource that should be exposed) in "Adobe Granite OAuth Resource Server"

The OAuth Authentication handler is not enabled by default and it looks to be an product defect.

Save the configurations(without any change) of "Adobe Granite OAuth Server Authentication Handler" to enable the handler (Perform the same step for previous post also)

Authorize the user:


Receive the access token using the code received:

curl -H "Content-Type: application/x-www-form-urlencoded" -d "code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJmamdzbnNibmxxZ3A1bDNjazY3b3NlYjBmOS1ldWNuLTF1YiIsInN1YiI6ImFkbWluIiwiZXhwIjoxNDk5MjkyNzQ0LCJpYXQiOjE0OTkyOTIxNDQsInNjb3BlIjoiL2V0Yy9kZXNpZ25zL2dlb21ldHJpeHgifQ.5ex1DvYLhYdoKjUvpscbyUpL5CWc02gjcpyPMJAPpMs&grant_type=authorization_code&redirect_uri=http://localhost:8080/test&client_id=fjgsnsbnlqgp5l3ck67oseb0f9-eucn-1ub&client_secret=r83jf37qc2jj4ggo8hmhcoqcc8" http://localhost:4502/oauth/token

Receive the Resource using the access token received:

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJmamdzbnNibmxxZ3A1bDNjazY3b3NlYjBmOS1ldWNuLTF1YiIsImlzcyI6IkFkb2JlIEdyYW5pdGUiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTQ5OTI5NTc4NywiaWF0IjoxNDk5MjkyMTg3LCJzY29wZSI6Ii9ldGMvZGVzaWducy9nZW9tZXRyaXh4In0.LfZxnZTL38bqHJaVJvcraLzaBu5axfdhuVQz7WFGLoE" http://localhost:4502/etc/designs/geometrixx/static.css

The below step should be followed for publisher(assuming anonymous access is enabled) - Enable the authentication for the resource /etc/designs/geometrixx

Tuesday, May 30, 2017

How to expose Regex based rest service in AEM

This post will explain the approach to expose the regex based rest service in AEM. By default OSGI will not support exposing regex based rest services and it will only support the services based on the specified Path or Resource Type.

Install OSGI JAX-RS connector:

Install(/system/console/bundles) jersey-all, publisher, provider-security and other required bundles e.g. provider-gson for JSON support and make sure the bundles are in Active state.

The bundles can be downloaded from following URL -

Develop the Servlet with required path mapping:

package com.albinsblog.samples.core;

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


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component(metatype = false)
@Path("/{catagroy}/{title}/p/{code : \\d{5}}")
public class RegexServlet {

public String getProductDetails(@Context HttpServletRequest request, @Context HttpServletResponse response,@PathParam("catagroy") String catagroy,@PathParam("title") String title,@PathParam("code") String code) {

  return "code="+code+";catagroy="+catagroy+";title="+title;


Add the following dependency in POM.xml


The servlet will accept the request with matching pattern - the Servlet path should be starting with /services

The Path Regex pattern specified in the Servlet will match for the following URL  - localhost:4502/services/categoryTest/Sampletitle/p/12345 (Code should be 5 digit)

Friday, May 19, 2017

Java PayPal API integration through proxy server

Getting the below exception while integrating PayPal API with Java, based on the analysis the direct communication to the API is not enabled from the server and the communication should be directed via Proxy server.

09:10:50.525 [main] ERROR com.paypal.base.HttpConnection -  Retry  No : 1...
09:11:54.577 [main] ERROR com.paypal.base.HttpConnection - Caught exception while handling error response Connection timed out
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.7.0_67]

Setting the proxy server in the API:

 HashMap<String,String> config=new HashMap<String,String>();
config.put("http.UseProxy", "true");
config.put("http.ProxyPort", "80");
config.put("http.ProxyHost", "");
config.put("http.ProxyUserName", null);
config.put("http.ProxyPassword", null);

APIContext context = new APIContext(clientId, clientSecret, "sandbox",config);

Change the values of  ProxyHost,  ProxyPort, ProxyUserName and ProxyPassword accordingly.

The communication will be success after this.

Tuesday, May 9, 2017

Issue with AEM DTM Integration while connecting via proxy

The below exception is thrown while integrating AEM with DTM

08.05.2017 14:06:35.894 *ERROR* [ [1494270332788] POST /etc/cloudservices/dynamictagmanagement/test/jcr:content.companies.json HTTP/1.1] com.adobe.cq.dtm.impl.util.DTMConfigurationUtil Failed to obtain a response from the DTM API Server.
org.apache.http.conn.ConnectTimeoutException: Connect to [] failed: Connection timed out
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(
        at org.apache.http.impl.execchain.MainClientExec.execute(
        at org.apache.http.impl.execchain.ProtocolExec.execute(
        at org.apache.http.impl.execchain.RetryExec.execute(
        at org.apache.http.impl.execchain.RedirectExec.execute(
        at org.apache.http.impl.client.InternalHttpClient.doExecute(
        at org.apache.http.impl.client.CloseableHttpClient.execute(
        at org.apache.http.impl.client.CloseableHttpClient.execute(
        at com.adobe.cq.dtm.impl.util.DTMConfigurationUtil.callDTMApi(
        at com.adobe.cq.dtm.impl.servlets.DTMCompaniesServlet.doPost(

Caused by: Connection timed out
        at Method)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(
        ... 138 common frames omitted

Based on the analysis the DTM cloud connector is not using the the proxy server details configured to establish the connection.
This is the defect with the connector, raise a ticket with Adobe support team to  receive the fix.

As a temporary fix update in bundle - /libs/cq/cloudservices/install/cq-dtm-0.1.8.jar to support proxy server while establishing the connectivity. - callDTMApi

 HttpHost proxy = new HttpHost("",80);
 RequestConfig config = RequestConfig.custom().setProxy(proxy).build();   

Refer the following post for updating the java class in a bundle -

This post is written based on the AEM version AEM 6.1 SP1.

Monday, May 8, 2017

How to get the basic profile details of a user in external clients through OAuth - AEM

This post will explain the approach to get the basic profile details of a user through OAuth - AEM/Adobe CQ5

Configure the OAuth client - AEM:
Login to AEM through Admin credential
Access - http://localhost:4502/libs/granite/oauth/content/clients.html and click on "Create a new app" or "Add New Client"

Enter Client ID and "Redirect URI" - The URL to which the user will be redirected after successful authorization(external client URL)

Redirect the user to below URL to authorize the user with AEM

http://localhost:4502/oauth/authorize?response_type=code&client_id=<Client Id from OAuth client>&scope=profile&redirect_uri=<The URL to which the user will be redirected after authorization>

User will be prompted to login if already not logged in and after successful login user will be redirect to a page to authorize the request.

After successful authorization the user will be redirected to the service URL configured in the OAuth client with the code.



The state parameter sent in the request will be send back in the response by AEM - this can be used to verify the authenticity of the request and response(This will help to stop Cross Site Request Forgery (XRSF).)



Receive the access token:

After authorization AEM will redirect the user to the URL specified as redirect url in the OAuth client, connect to the token endpoint in the service with the code received in the URL to fetch the access token.



Content-Type: application/x-www-form-urlencoded

Input Parameters:
code= The code received from the previous response
redirect_uri=Redirect URI from OAuth client configuration
client_id= Client Id from OAuth client configuration
client_secret=Client Secret from OAuth client configuration

e.g. through CURL
curl -H "Content-Type: application/x-www-form-urlencoded" -d "code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJiaGVhamE1bnEwMmcxa2xjZnVwYzcxYzlsMS1sd3I3d3ZobCIsInN1YiI6ImFsYmluIiwiZXhwIjoxNDkzOTI2Mjc3LCJpYXQiOjE0OTM5MjU2NzcsInNjb3BlIjoicHJvZmlsZSJ9.cGGuC2UoSyR3vrl8abVZtgZt-3-6y-wuohEVJxitBJs&grant_type=authorization_code&redirect_uri=http://localhost:8080/test&client_id=lkeadg8fol2h6or98sutint8l0-eucn-1ub&client_secret=f4sv6cv4s91qqskbtconja37lc" http://localhost:4502/oauth/token


Receive the profile data:
Connect to the profile endpoint with the access token received in the previous step to fetch the basic user profile data.



Authorization: Bearer <access token>

e.g. through CURL
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJiaGVhamE1bnEwMmcxa2xjZnVwYzcxYzlsMS1sd3I3d3ZobCIsImlzcyI6IkFkb2JlIEdyYW5pdGUiLCJzdWIiOiJhbGJpbiIsImV4cCI6MTQ5MzkyOTgzNywiaWF0IjoxNDkzOTI2MjM3LCJzY29wZSI6InByb2ZpbGUifQ.jkmQzy7exD5ShcX-CneX-YYY0WzC7OHGN8WHLb_Zkqg" http://localhost:4502/libs/oauth/profile

{"path":"/home/users/a/nNZl6ouZfBrbxReawJfm/profile","user":{"authorizableId":"albin"},"gender_xss":"male","gender":"male","aboutMe_xss":"test","aboutMe":"test","email_xss":"","email":"","state_xss":"MN","state":"MN","familyName_xss":"Issac","familyName":"Issac","country_xss":"United States","country":"United States","givenName_xss":"Albin","givenName":"Albin"}

This post is written based on the AEM version AEM 6.1 SP1

Saturday, May 6, 2017

How to display the git tags based on the environment in Jenkins parameter

This post will explain how to display the git tags based on the environment in Jenkins parameter - Displaying the dynamic list with tag names filtering the tags with environment name e.g. QA, UAT, PROD(the environment name should be included in the tag while creating)

Select "This build is parameterized" in Jenkins job configuration
Add new parameter of type Extensible Choice
Enter the name "Tag" and select the Choice Provider as "System Groovy Choice Parameter"
Enter the below script in "Groovy System Script"

def gettags = "git ls-remote -t".execute()
def tags = []
def t1 = []
gettags.text.eachLine {tags.add(it)}
for(i in tags)
   def tagName=i.split()[1].replaceAll('\\^\\{\\}', '').replaceAll('refs/tags/', '')
t1 = t1.unique()
return t1

Change the git repository details and the string based on that the tags should be filtered e.g QA, UAT, PROD

Click on "Run the script now" to test the script - this will displayed the filtered tags.
Save the configurations finally

Wednesday, April 26, 2017

Error while submitting the Eloqua form - Value must not contain any URL

I was getting the following error while submitting the Eloqua form

<!DOCTYPE html>
<body bgcolor="#ffffff">
<div align="center" style="margin: 60px;">
<div align="left" style="width: 400px; font-size: 14pt; font-family: Tahoma, Arial, Helevtica; font-weight: bold;">
<img src="/EloquaImages/ConfirmationPage/error.gif" width="32" height="50" border="0" align="left">  The Information Provided is Incomplete or Invalid. </div>
<div align="left" style="width: 400px; font-size: 10pt; font-family: Arial, Helevtica; padding-left: 45px; padding-top: 10px; padding-right: 45px;">
<p>Reference- Value must not contain any URL&#39;s<br/></p>

The Reference filed is configured as hidden in Eloqua and also sending the URL as the input.

Based on the reading Oracle Eloqua 483 Release enabled by default "Must Not Contain URL" validation on all hidden fields but user was not able to modify this validation. But Eloqua 487 Release provided the access to users to modify the validation on hidden fields

Disable "Must Not Contain URL" validation in the hidden field that expecting the URL as input.

Sunday, April 16, 2017

how to include custom metatag headers from AEM Tags

This post explains the approach to include custom metatag headers from AEM Tags.

Customize the page properties dialog:

Customize the page properties dialog to add the field to select custom tags

Copy /libs/foundation/components/page/dialog and /libs/foundation/components/page/tab_basic under custom page rendering component e.g. /apps/training/components/page-content/

Create a node of type cq:widget under tab_basic with the following properties

Name Type Value
allowBlank Boolean true
fieldLabel String Page Type
name String ./page-type
namespaces String[] page-type
xtype String tags

Refer for more details on customizing the page properties dialog.

Define new tag namespace & tags:
Create new tag namespace(page-type) through http://localhost:4502/tagging

Create required tags under page-type namespace

Override the the head.jsp if the page component is inhering from foundation/components/page. Add required logic in head.jsp to include the custom metatags from AEM tags.
%><%@ include file="/libs/foundation/global.jsp"%><%
%><%@ page contentType="text/html; charset=utf-8" import="com.albinsblog.samples.core.TagsUtil,*"%><%

TagManager tagManager = resourceResolver.adaptTo(TagManager.class);
String[] pageTypeTags = properties.get("./page-type", String[].class);
String pageTypes = TagsUtil.getTagTitles(tagManager, pageTypeTags);
 <cq:include script="/libs/wcm/core/components/init/init.jsp"/>
   <meta name="page-types" content="<%= pageTypes %>" />
</head> - util class to fetch the tag titles and convert the titles to required formats.

public class TagsUtil {
public static String getTagTitles(TagManager tagManager, String[] typeTags) {
StringBuffer typeBuffer = new StringBuffer();
if (typeTags != null) {
for (String typeTagId : typeTags) {
Tag typeTag = tagManager.resolve(typeTagId);
if (typeTag != null) {
String tagPath = typeTag.getTitlePath();
String[] splitTags = tagPath.split(":");
String tagName = splitTags[1];
if (typeTag != null)
typeBuffer.append(tagName + ";"); }
if (typeBuffer.length() != 0)
typeBuffer.deleteCharAt(typeBuffer.length() - 1);
return typeBuffer.toString();
Configure required tags in page properties dialog

The defined metatag will be added to the page 

Friday, April 14, 2017

Integration of AEM with Salesforce - Part4

This post will explain the approach to extend the basic AEM Salesforce connector to create/update the Salesforce objects.

Refer the following post for details on integrating Salesforce with AEM

Prerequisite  - Configure the Salesforce cloud connection, refer the above mentioned post for more details.
Enable the Salesforce cloud configuration for the Home page of the websites.


Add the below Maven dependency to the project
For 6.0 and 6.1

For 6.2

Change the version based on your server

Create a Java Class ( that will use the base connector to create/update Salesforce objects - This code provides the support to OPPORTUNITY, change the code accordingly to enable the support for other objects.

import javax.jcr.Node;
import javax.jcr.RepositoryException;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.cq.mcm.salesforce.SalesforceClient;
import com.adobe.cq.mcm.salesforce.SalesforceResponse;
import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;

public class SalesforceUpdateProcess  
  private static final Logger log = LoggerFactory.getLogger(SalesforceUpdateProcess.class);

  private CryptoSupport cryptoSupport;
  public void update(Configuration cloudConfig, SalesforceUpdateParameters parameters, ResourceResolver resolver)
   throws Exception
   if (cloudConfig != null)
     String instanceUrl = (String)cloudConfig.get("instanceurl", "");
     String accessToken = (String)cloudConfig.get("accesstoken", "");
     String clientId = (String)cloudConfig.get("customerkey", "");
     String encryptedCustomerSecret = (String)cloudConfig.get("customersecret", "");
     String encryptedRefereshToken = (String)cloudConfig.get("refreshtoken", "");
       String customerSecret = encryptedCustomerSecret;
       String refreshToken = encryptedRefereshToken;
       if (this.cryptoSupport.isProtected(encryptedCustomerSecret)) {
         customerSecret = this.cryptoSupport.unprotect(encryptedCustomerSecret);
       if (this.cryptoSupport.isProtected(encryptedRefereshToken)) {
         refreshToken = this.cryptoSupport.unprotect(encryptedRefereshToken);
       JSONObject requestData = new JSONObject(parameters.getInputData());
                String requestDataString = requestData.toString();
       SalesforceClient salesforceClient = new SalesforceClient();
                String sObjectName="";
                if (SalesforceUpdateParameters.SalesforceObjectType.OPPORTUNITY.equals(parameters.getObjectType())) {
                StringBuilder salesforcePath = new StringBuilder("/services/data/v20.0/sobjects/"+sObjectName+"/");
                if (SalesforceUpdateParameters.SalesforceOperationType.UPDATE.equals(parameters.getOperationType())) 
                }else if (SalesforceUpdateParameters.SalesforceOperationType.CREATE.equals(parameters.getOperationType())) {
                SalesforceResponse salesforceResponse = salesforceClient.executeRequest();
       if (salesforceResponse.getAccessTokenUpdated().booleanValue())
         String configPath = cloudConfig.getPath();
         Resource configResource = resolver.getResource(configPath);
         Node configNode = ((Node)configResource.adaptTo(Node.class)).getNode("jcr:content");
         configNode.setProperty("accesstoken", salesforceClient.getAccessToken());
       if (salesforceResponse.getCode()!=204 && salesforceResponse.getCode()!=201)
        throw new Exception("Error in Update"+salesforceResponse.getBody());
     catch (RepositoryException e)
       log.error("Repository Exception in Update " + e.getMessage());
       throw new Exception("Repository Exception in Update " + e.getMessage());
     catch (CryptoException e)
       log.error("Cryto Exception in Update " + e.getMessage());
       throw new Exception("Crypto Exception in Update " + e.getMessage());
     catch (JSONException e)
       log.error("JSON Exception in Update " + e.getMessage());
       throw new Exception("JSON Exception in Update " + e.getMessage());
     catch (Exception e)
       log.error("Exception in Update " + e.getMessage());
       throw new Exception("Exception in Update " + e.getMessage());
  protected void bindCryptoSupport(CryptoSupport paramCryptoSupport)
    this.cryptoSupport = paramCryptoSupport;
  protected void unbindCryptoSupport(CryptoSupport paramCryptoSupport)
    if (this.cryptoSupport == paramCryptoSupport) {
      this.cryptoSupport = null;

Create a Java class( that will provide the support for required Salesforce objects -  - This code provides the support to OPPORTUNITY, change the code accordingly to enable the support for other objects.

import java.util.HashMap;

public class SalesforceUpdateParameters
  private HashMap<String,String> inputData;
  private SalesforceObjectType objectType;  
  private SalesforceOperationType opeationType;
  private String salesforceObjectId;
  public static enum SalesforceOperationType
    private SalesforceOperationType() {}
  public SalesforceOperationType getOperationType()
    return this.opeationType;
  public void setOpeationType(SalesforceOperationType opeationType)
    this.opeationType = opeationType;
  public void setOpeationType(String opeationType)
    if ( {
      this.opeationType = SalesforceOperationType.UPDATE;
    } else if ( {
        this.opeationType = SalesforceOperationType.CREATE;
  public static enum SalesforceObjectType
    private SalesforceObjectType() {}
  public SalesforceObjectType getObjectType()
    return this.objectType;
  public void setObjectType(SalesforceObjectType objectType)
    this.objectType = objectType;
  public void setObjectType(String objectType)
    if ( {
      this.objectType = SalesforceObjectType.OPPORTUNITY;
  public HashMap<String,String> getInputData()
    return this.inputData;
  public void setInputData(HashMap<String,String> inputData)
    this.inputData = inputData;
public String getSalesforceObjectId() {
return salesforceObjectId;
public void setSalesforceObjectId(String salesforceObjectId) {
this.salesforceObjectId = salesforceObjectId;

Create a components that will invoke to create/update the Salesforce objects by providing required parameters.


            String[] cloudConfigs = pageProperties.getInherited("cq:cloudserviceconfigs", new String[]{});
            ConfigurationManager configurationManager = resourceResolver.adaptTo(ConfigurationManager.class);

                Configuration salesforceConfig = configurationManager.getConfiguration("salesforce",cloudConfigs);

SalesforceUpdateProcess updateClient = sling.getService(SalesforceUpdateProcess.class);
                SalesforceUpdateParameters updateParameters = new SalesforceUpdateParameters();

                HashMap<String,String> inputData=new HashMap<String,String>();//Send only the required field for update
                inputData.put("Description","Test Description");

                updateParameters.setOpeationType(SalesforceUpdateParameters.SalesforceOperationType.CREATE);//Create New Object
                //updateParameters.setOpeationType(SalesforceUpdateParameters.SalesforceOperationType.UPDATE);//Update the existing object by providong the id
                //updateParameters.setSalesforceObjectId("0069000000rjArf");//Object id to update

                updateClient.update(salesforceConfig, updateParameters, resource.getResourceResolver());

 <div id="cloudconfigerror">
                    Salesforce Cloud Service Configuration could not be found for this page.
                }catch(Exception e)
 <div id="error">
     Exception occurred while Create/Update. Please contact Administrator.


Contact Form


Email *

Message *