Friday, 20 June 2014

Sling Authentication

Let's look at generic request processing of Sling: Sling is linked into the outside world by registering the Sling Main Servlet – implemented by the SlingMainServlet class in the Sling Engine bundle – with an OSGi HttpService. This registration is accompanyied with an implementation instance of the OSGi HttpContext interface, which defines a method to authenticate requests: handleSecurity.
This method is called by the OSGi HTTP Service implementation after the servlet has been selected to handle the request but before actually calling the servlet's service method.




  1. First the OSGi HTTP Service implementation is analyzing the request URL to find a match for a servlet or resource registered with the HTTP Service.
  2. Now the HTTP Service implementation has to call the handleSecurity method of the HttpContext object with which the servlet or resource has been registered. This method returns true if the request should be serviced. If this method returns false the HTTP Service implementation terminates the request sending back any response which has been prepared by the handleSecurity method. Note, that the handleSecurity method must prepare the failure response sent to the client, the HTTP Service adds nothing here. If the handleSecurity method is successful, it must add two (or three) request attributes described below.
  3. When the handleSecurity method returns true the HTTP Service either calls the Servlet.service method or sends back the requested resource depending on whether a servlet or a resource has been selected in the first step. {column} {section}
The important thing to note here is, that at the time the handleSecurity method is called, the SlingMainServlet is not yet in control of the request. So any functionality added by the SlingMainServlet, notably the SlingHttpServletRequest and SlingHttpServletResponse objects are not available to the implementation of the handleSecurity method.


Deprecation of administrative authentication

Originally the ResourceResolverFactory.getAdministrativeResourceResolver and SlingRepository.loginAdministrative methods have been defined to provide access to the resource tree and JCR Repository. These methods proved to be inappropriate because they allow for much too broad access.
Consequently these methods are being deprecated and will be removed in future releases of the service implementations.
The following methods are deprecated:
  • ResourceResolverFactory.getAdministrativeResourceResolver
  • ResourceProviderFactory.getAdministrativeResourceProvider
  • SlingRepository.loginAdministrative

Friday, 19 July 2013

How to serve stale content in case no render is available

In order to enable this feature, an additional flag /serveStaleOnError has to be set below the/cache section:

dispatcher.any

/cache
 
  # Flag indicating whether the dispatcher should serve stale content if
  # no remote server is available.
  /serveStaleOnError "1"
Please note that only the following response codes are considered:
  • 502 - Bad Gateway
  • 503 - Service Unavailable
  • 504 - Gateway Timeout

Wednesday, 20 February 2013

Creating Custom Namespaces


Adobe CQ uses namespaces to maintain modularity between the properties and also tags.  namespaces help in distinguishing different modules of the project. We create thousand of properties in our project and many times it consists of just words. Hence to make the properties names meaningful we can add a namespace to project related namespaces.
Note that the namespace is unique to your project and doesn’t conflict with existing namespaces.
Steps for creating Custom Namespace:
Step 1: Log into CRX and follow this path:http://servername:port/crx/explorer/nodetypes/index.jsp  or click on Node Administration link from the CRX Console.
Step 2:  You will be navigated to the below screen. On the left panel, all the node types will be displayed. Click on the Namespaces link on the right as displayed below:
  
Click on namespaces





 Step 3: Below screen will appear and click on New button and enter the namespace URI and prefix . The namespace provided below is just an example.
enter new





 Step 4: The namespace will be created and it can now be used in your project.
Namespace created





 Let me know if any questions.
Hope this helps. Thanks!

Custom Tag Libs for Adobe CQ


Follow the below steps for creating custom Tab libraries:
Step 1: Write a java Class with the method  you want as a tag lib.
I’m providing an example java class here:
/**
*
*/
package com.company.cq.taglibs;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.DynamicAttributes;
import javax.servlet.jsp.tagext.TagSupport;
/**
* @author apelluru
*
*/
public class ReusableTagLibs extends TagSupport implements DynamicAttributes {
@Override
public int doStartTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
out.print(getLabel(“”,”"));
}catch (Exception e) {
// TODO: handle exception
}
return SKIP_BODY;
}
private String getLabel(String prop, String value) {
return “hello”;
}
public void setDynamicAttribute(String uri, String localName, Object value) {
}
}
Step 2: Write a tld file for your tab library
The path of the tld file may be in  resource/META-INF folder of your src folder. If META-INF folder is not present then create it.
The tld file will look like this:
<?xml version=”1.0″ encoding=”UTF-8″?>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>locale</shortname>
<info>Taglib for CQ localization</info>
<tag>
<name>label</name>
<tagclass>com.company.cq.taglibs.ReusableTagLibs</tagclass>
<info>Localization function</info>
<attribute>
<name>property</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<dynamic-attributes>true</dynamic-attributes>
</attribute>
<attribute>
<name>context</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<dynamic-attributes>true</dynamic-attributes>
</attribute>
<attribute>
<name>encoding</name>
<required>false</required>
</attribute>
<dynamic-attributes>true</dynamic-attributes>
</tag>
</taglib>
Step 3: Build the bundle.
Step 4: Include the tag library in your jsp
<%@taglib prefix=”reusable” uri=”/apps/reusablecomponents/dm/src/impl/src/main/resources/META-INF/reusable.tld” %>
Use the tag in your JSP like this:    <reusable:label  property=”hello” context=”<%= pageContext %>”/>

CQ 5.5 upgrade from 5.4 learnings


Here are few learning that I got when we upgraded CQ 5.4 to CQ 5.5:
1. DO NOT customize the out of the box libraries until unless it’s really required. Customizing the OOTB functionality will be problematic when new version of the product add more features on the libraries you’ve overridden.
2. Analytics integration with CQ 5.5 has been made very simple and all the configuration are provided on the CQ side. We used analytics integration in CQ 5.4 hence we re-integrated by modifying the settings.
3. If you have overridden init.jsp(CQ 5.4) in your project then UNDO/REDO won’t work. This is because a new service class has been introduced which handles the undo/redo request and initialized in init.jsp. Hence you need to merge the init.jsp (CQ 5.4) to init.jsp (CQ 5.5).
4. Few API changes has been made. Please checkhttp://dev.day.com/docs/en/cq/current/diff_5-4_5-5/changes.h… for more information. If a class you’ve used in 5.4 doesn’t work, search for alternate class. (Examples: AnalyticsHelper.java has been removed, wrote my own method to get the analytics resource).
5. Maintain at least one instance of CQ 5.4 running as a backup. It will also help in comparing between 5.5 & 5.4.
6. Dropdown/Tag fields in dialogs shrink after upgrade. I fixed it by adding a width property to the fields.
7. If you’ve customized OOTB functionality then you may see many Internal Server Errors. This is due to the Resource Not found Exception since class/configuration in 5.5 has been modified/removed.
8. Delete your workflow instances and temporary data (unused package, tmp files) from CRX before the upgrade. This will help in faster upgrade.
9. Continuous log monitoring will help in finding the issues which doesn’t appear on the UI.
10. Most importantly if New Page options or Page Properties are disabled completely then it may be due to missing “jcr:content” node on the page. Also this may cause due to permissions.
11. LDAP permission were getting wiped out with every deployment of our project package. Adobe has provided a fix for it.
12. Install CQ 5.5.1, it fixes may of the internal issues.
13. Old Scr annotations (E.g., scr.reference) has been deprecated and hence you need to use new scr annotations (@Reference()). Bundles won’t build with the old annotations.
Note: Though our upgrade instance was running fine in Pre-PROD environments, we had a meeting with Adobe, they have validated all the configuration settings, logs and showed a green flag.

Tuesday, 19 February 2013

Create custom xtype multi textfield, pathfield, new window options


CQ.form.CustomMultiField = CQ.Ext.extend(CQ.form.CompositeField, {

hiddenField: null,

linkText: null,

linkURL: null,

openInNewWindow: null,

constructor: function (config) {

config = config || {};

var defaults = {
    "border": true,
    "labelWidth": 75,
    "layout": "form"
    };  
config = CQ.Util.applyDefaults(config, defaults);
CQ.form.CustomMultiField.superclass.constructor.call(this, config);
},

initComponent: function () {
 
    CQ.form.CustomMultiField.superclass.initComponent.call(this);
 
    // Hidden field
    this.hiddenField = new CQ.Ext.form.Hidden({
         name: this.name
    });
    this.add(this.hiddenField);
 
    this.linkText = new CQ.Ext.form.TextField({
        cls: "customwidget-1",
        maxLength: 100,
        emptyText: "Enter Title",
        maxLengthText: "A maximum of 100 characters is allowed for the Link Text.",
        width: 335,
        allowBlank: true,
        name : "item",
        listeners: {
        change: {
        scope: this,
        fn: this.updateHidden
    }
    }
    });  
    this.add(this.linkText);
 
    this.linkURL = new CQ.form.PathField({
        cls: "customwidget-2",
        allowBlank: true,
        emptyText: "Enter Title URL",
        width: 335,
        listeners: {
         change: {
            scope: this,
            fn: this.updateHidden
        },      
        dialogclose: {
            scope: this,
            fn: this.updateHidden
        }
       }
    });
    this.add(this.linkURL);
 
    // Link openInNewWindow
    this.openInNewWindow = new CQ.Ext.form.Checkbox({
        cls: "customwidget-3",
        boxLabel: "New window",
        listeners: {
        change: {
        scope: this,
        fn: this.updateHidden
        },
        check: {
        scope: this,
        fn: this.updateHidden
    }
    }
    });
    this.add(this.openInNewWindow);
 
},

processInit: function (path, record) {  
    this.linkText.processInit(path, record);
    this.linkURL.processInit(path, record);
    this.openInNewWindow.processInit(path, record);
},

setValue: function (value) {
    var link = JSON.parse(value);
    this.linkText.setValue(link.text);
    this.linkURL.setValue(link.url);
    this.openInNewWindow.setValue(link.openInNewWindow);
},
getValue: function () {
return this.getRawValue();
},

getRawValue: function () {  
    var link = {
    "url": this.linkURL.getValue(),
    "text": this.linkText.getValue(),
    "openInNewWindow": this.openInNewWindow.getValue()
    };  
    return JSON.stringify(link);
},
updateHidden: function () {
this.hiddenField.setValue(this.getValue());
}
});

CQ.Ext.reg("CustomMultiField", CQ.form.CustomMultiField);



Then Dialog



<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Dialog"
    width="550"
    xtype="dialog">
    <items
        jcr:primaryType="cq:Widget"
        xtype="tabpanel">
        <items jcr:primaryType="cq:WidgetCollection">
            <tab1
                jcr:primaryType="cq:Panel"
                title="Links Component">
                <items jcr:primaryType="cq:WidgetCollection">
                    <links
                        jcr:primaryType="cq:Widget"
                        border="false"
                        fieldDescription="Press + to add more links"
                        fieldLabel="Links"
                        hideLabel="true"
                        name="./links"
                        xtype="multifield">
                        <fieldConfig
                            jcr:primaryType="cq:Widget"
                            xtype="CustomMultiField"/>
                    </links>
                </items>
            </tab1>
        </items>
    </items>
</jcr:root>







Tuesday, 20 November 2012

Encryption And Decryption in Java



import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.commons.codec.binary.*;

 public class DESDecrypt {
 
    private String characterEncoding = "UTF-8";
    private String cipherTransformation = "AES/CBC/PKCS5Padding";
    private String aesEncryptionAlgorithm = "AES";  
 
    private byte[] decrypt(byte[] cipherText, byte[] key, byte[] initialVector) throws Exception
    {
        Cipher cipher = Cipher.getInstance(cipherTransformation);
        SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
        cipherText = cipher.doFinal(cipherText);
        return cipherText;
    }

    private byte[] encrypt(byte[] plainText, byte[] key, byte[] initialVector) throws Exception
    {
        Cipher cipher = Cipher.getInstance(cipherTransformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        plainText = cipher.doFinal(plainText);
        return plainText;
    }

    private byte[] getKeyBytes(String key) throws Exception{
 
        byte[] keyBytes= new byte[16];
        byte[] parameterKeyBytes= key.getBytes(characterEncoding);
        System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));      
        return keyBytes;
    }
 
    public String encrypt(String plainText, String key) throws Exception{
 
        byte[] plainTextbytes = plainText.getBytes(characterEncoding);
        byte[] keyBytes = getKeyBytes(key);
        return Base64.encodeBase64String(encrypt(plainTextbytes, keyBytes, keyBytes));
    }

    public String decrypt(String encryptedText, String key) throws Exception{
     
        byte[] cipheredBytes = Base64.decodeBase64(encryptedText);
        byte[] keyBytes = getKeyBytes(key);
     
        return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding);
    }
 
}