Tuesday, August 9, 2016

HTL (Sightly) Chit Note - Part 1

In this article, I am going to create a chit note for frequently used HTL syntax that will come handy while working with AEM.

1. HTL does not support JSP tag libraries.


2. Including a script: data-sly-include instead of cq:include

<cq:include script="template.html"/> //Including a HTL file in JSP
<sly data-sly-include="template.jsp"/> //Including a JSP file in HTL

The element on which a data-sly-include has been set is ignored and not displayed.

3. Including a Resource: data-sly-resource

Includes the result of rendering the indicated resource through the sling resolution and rendering process. Basic syntax-

<article data-sly-resource="path/to/resource"></article>

Override resourceType of an include-
<article data-sly-resource="${'path/to/resource' @ resourceType='my/resource/type'}"></article>

Change the wcmmode-
<article data-sly-resource="${'path/to/resource' @ wcmmode='disabled'}"></article>

Include resource parent div


<sly data-sly-resource="${'btn1' @ resourceType='my/components/content/button', decoration=true}"></sly>

4. Changing element tag: data-sly-element

This replaces the element name of the host element-
<h1 data-sly-element="${titleLevel}">text</h1>

Replaces the h1 with the value of titleLevel.

For security reasons, data-sly-element accepts only limited element names.

5. Including clientlibs: data-sly-use and data-sly-call 

In a single statement-

<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html"
     data-sly-call="${clientlib.all @ categories=['myCategory1', 'myCategory2']}"/>

In Separate statements-

<!doctype html>
<html data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
    <head>
        <!-- HTML meta-data -->
        <css data-sly-call="${clientlib.css @ categories='myCategory'}"/>
    </head>
    <body>
        <!-- page content -->
        <js data-sly-call="${clientlib.js @ categories='myCategory'}"/>
    </body>
</html>


6. If Statement: data-sly-test

HTL uses data-sly-test block statement to implement "if" behavior. There is no direct if-else implementation. You need to utilize data-sly-test in an efficient manner to achieve this.

A). Positive condition: if
<h1 data-sly-test="${properties.jcr:title}"> ${properties.jcr:title}</h1>
Negative condition: else
<h1 data-sly-test="${!properties.jcr:title}"> ${pageProperties.name | "Untitled" }</h1>

You can also use relational operators i.e.- "<=", ">=", "==" etc. in your test condition.

B). Always cache test block statement results in an identifier if it repeats itself

<h1 data-sly-test.hasTitle="${properties.jcr:title}"> ${properties.jcr:title}</h1> //if
<h1 data-sly-test="${!hasTitle}"> ${pageProperties.name | "Untitled" }</h1> //else

7. data-sly-unwrap/ sly Element

AEM 6.0 (HTL1.0) has an attribute "data-sly-unwrap" to avoid rendering of referenced HTML tag in context. 

<!-- /* This */ -->
<p data-sly-use.nav="navigation.js" data-sly-unwrap>Hello World</p>

<!-- /* Produces */ -->
Hello World

<!-- /* you can also put condition in data-sly-unwrap */ -->

<p data-sly-unwrap="${someCondition}">Hello World</p>

The above statement will render the hosting element only when the condition evaluates to false. 

AEM 6.1 (HTL1.1) has introduced a new element- "sly" to achieve this. So it is suggested to use sly statement instead of data-sly-unwrap in HTL 1.1 onwards.

<sly data-sly-test="${someCondition}">Hello World</sly>

8. Iterating through a list: data-sly-list Element

<ul data-sly-list="${listObject}">
    <li>Index: ${itemList.index}, Value: ${item}</li>
</ul>

Here itemList provides following properties-
  • index : counter (0-n)
  • count : counter (1-n)
  • first : if the current item is the first item
  • middle: if the current item is neither the first nor the last item
  • last: if the current item is the last item
  • odd: if index is odd
  • even: if index is even
You can also rename the item/ itemList variable name (This is suggested approach to use identifiers instead of using default item naming)-

<dl data-sly-list.child="${currentPage.listChildren}">
    <dt>index: ${childList.index}</dt>
    <dd>value: ${child.title}</dd>
</dl>

9. Use of Display Context

To protect against cross-site scripting (XSS) vulnerabilities, HTL automatically recognises the context within which an output string is to be displayed within the final HTML output, and escapes that string appropriately.

<p style="color: ${properties.color @ context='styleToken'};"></p>
<p>URL: ${teaser.link @ context = 'uri'}</p>

${properties.jcr:title @ context='html'}    <!--/* Use for HTML output. Removes markup posing XSS risks */-->
${properties.jcr:title @ context='text'}     <!--/* Use for plain text content - Encodes all HTML */-->
${properties.jcr:title @ context='elementName'}   <!--/* Allows only white-listed element names, outputs 'div' otherwise */-->
${properties.jcr:title @ context='attributeName'} <!--/* Outputs nothing if the value doesn't map to a valid HTML attribute; Doesn't allow 'style' and 'on*' attributes */-->
${properties.jcr:title @ context='attribute'}     <!--/* Applies HTML attribute escaping */-->
${properties.jcr:title @ context='uri'}     <!--/* Outputs nothing if the value contains XSS risks */-->
${properties.jcr:title @ context='scriptToken'}   <!--/* Outputs nothing if value doesn't correspond to the JavaScript token syntax */-->
${properties.jcr:title @ context='scriptString'}  <!--/* Applies JavaScript string escaping */-->
${properties.jcr:title @ context='scriptComment'} <!--/* Context for Javascript block comments. Outputs nothing if value break out of the comment context */-->
${properties.jcr:title @ context='scriptRegExp'}  <!--/* Applies JavaScript Regex escaping */-->
${properties.jcr:title @ context='styleToken'}    <!--/* Outputs nothing if the value doesn't correspond to the CSS token syntax */-->
${properties.jcr:title @ context='styleString'}   <!--/* Applies CSS string escaping */-->
${properties.jcr:title @ context='styleComment'}  <!--/* Context for CSS comments. Outputs nothing if value break out of the comment context */-->
${properties.jcr:title @ context='comment'}       <!--/* Applies HTML comment escaping */-->
${properties.jcr:title @ context='number'}        <!--/* Outputs zero if the value is not a number */-->
${properties.jcr:title @ context='unsafe'}  <!--/* Use at your risk, this disables XSS protection */-->

10. HTL Comments:

<!--/* An HTL Comment */-->


11. Formatting in Expression:

To format string, you can use Numbered parameters for injecting variables:

${'Assets {0}' @ format=properties.assetName}   <!--/* A shortcut of the array notation, useful when it has one element */-->
${'Assets {0}' @ format=[properties.assetName]}
${'Assets {0} - {1} of {2}' @ format=[properties.first, properties.last, properties.total]}

12. i18n: Internationalization

Following syntax is used to localize string literals in HTL-

${'Assets' @ i18n} <!--/* Translates the string to the resource language */-->

${'Assets' @ i18n, locale='en-US', hint='Translation Hint'} <!--/* Complete syntax with locale and hint options */-->

The i18n option can be combined with the format option, which replaces the placeholders after the string has been run through the dictionary:

${'Assets {0} - {1} of {2}' @ i18n, format=[properties.first, properties.last, properties.total]}

13. Array Join: Implode function

The join option allows to control the output of an array object by specifying the separator string.

${['one', 'two'] @ join='; '} <!--/* outputs: one; two */-->

14. URI Manipulation

Following options are available-
  • scheme (To prepend with http/ https)
    ${'http://example.com/path/page.html' @ scheme='https'} <!-- outputs: https://example.com/path/page.html -->
  • domain
    ${'///path/page.html' @ domain='example.org'} <!-- outputs: //example.org/path/page.html -->
  • path
    ${'http://example.com/this/one.selector.html/suffix?key=value#fragment' @ path=''} <!-- outputs: http://example.com/this/one.selector.html/suffix?key=value#fragment -->
  • prependPath
  • appendPath
    ${'path/page.selector.html/suffix?key=value#fragment' @ appendPath='appended'} <!-- outputs: path/page/appended.selector.html/suffix?key=value#fragment -->
  • selectors
  • addSelectors
  • removeSelectors
  • extension
    ${'path/page.json#fragment' @ extension='html'} <!-- outputs: path/page.html#fragment -->
  • suffix
    ${'path/page.html?key=value' @ suffix='my/suffix'} <!-- outputs: path/page.html/my/suffix?key=value -->
  • prependSuffix
  • appendSuffix
  • query
    ${'http://www.example.org/search?s=1&q=htl' @ query} <!-- outputs: http://www.example.org/search -->
  • addQuery
  • removeQuery
  • fragment
    ${'path/page#one' @ fragment='two'} <!-- outputs: path/page#two -->


References:

Monday, August 8, 2016

HTL (Sightly) Chit Notes Part-2

15. Java Use API

Format to call in html file-

<sly  data-sly-use.javaUseClassName="apps.mycomponent.MyComponent @title='Test Title'">${javaUseClassName.someProperty} </sly> 

Here class name is used without extension.  You cannot pass argument to a method. But it is possible to pass argument at the activation of the Java/Javascript class.

16. JavaScript Use API

<sly  data-sly-use.jsUseClassName="${'mycomponent.js' @ fieldValue =resource.valueMap}">${jsUseClassName.jsonVal}</sly>

Sample js file content -

"use strict";

use(function () {

var nodeJson = JSON.parse(this.fieldValue);
var title = currentPage.getTitle();

var description = properties.get("jcr:description", "default desc");

return {
   jsonVal: nodeJson,
   title: title,
   description: description
}
});

17. Template & Call

Template blocks can be used like function calls: in their declaration they can get parameters, which can then be passed when calling them. They also allow recursion. This consist of following steps:

A. Define A Template: data-sly-template

Template can be defined in a static or dynamic way-

<template data-sly-template.templateOne>blah</template> <!--/* Static Template */-->

<template data-sly-template.templateTwo="${ @ title, resource='The resource of parent node'}"><h1>${title}</h1>
<p>Parent: ${resource.name}</p></template> <!--/* Dynamic Template, with parameter- title and resource */-->

Note that the host element and its content are not output by HTL.

B. Call The Template: data-sly-call

Calling a static template defined above-

<div data-sly-call="${templateOne}"></div>

Calling the dynamic template with parameters-

<div data-sly-call="${templateTwo @ title=properties.jcr:title, resource=resource.parent}"></div>

C. Externalizing The Template (Optional Step): data-sly-use

When templates are located in a separate file, they can be loaded with data-sly-use:

<div data-sly-use.lib="templateLib.html" data-sly-call="${lib.templateOne}"></div>
<div data-sly-call="${lib.templateTwo@ title=properties.jcr:title, resource=resource.parent}"></div>

Thursday, August 4, 2016

AEM6 | Integration with Translations.com

Translations.com's GlobalLink Project Director integrates with Adobe Experience Manager, providing users with a powerful solution to initiate, automate, control, track, and complete all facets of the translation process.


Refer the following links for more details-
http://www.translations.com/products/globallink-AEM-adaptor,
http://www.translations.com/globallink/partners/adobe.html

Translations.com provide packages (in Zip farmat) which can be installed through AEM package manager. They provide two packages- 

a.       GlobalLink-Adaptor-4.7.6.zip (Check the latest packages from TDC site)

b.      GlobalLink-Workflows-2.1.zip (Check the latest packages from TDC site)

Please note that this is not an open source product and you need to contact to TDC to get these packages. Once packages installed, required page templates will be available. Look at the screenshot below-



You need to create pages for each template under /content/global-link (Their latest Adaptor package doesn't need this activity. Their configuration is available from /projects.html page of the AEM instance)-


Configuring Translation.com

First add the new Translation vendor to Translation configurations-































  • On the rail, click or tap Tools > Operations > Cloud > Cloud Services.
  • In the Adobe Marketing Cloud/Translation Integration area, click or tap Show Configurations.
  • Click the + link next to Available Configurations.
    file
  • Type a title for your configuration. The title identifies the configuration in the Cloud Services console as well as in page property drop-down lists. The default name is based on the title. Optionally, type a name to use for the repository node that stores the configuration. 
  • Click Create.
  • On the configuration page, click Edit.
  • On the Translation Integration Configuration tab, select the translation provider, and select the category to use for translating the content.  
  • (Optional) On the User Generated Content tab, select the repository node where the original user-generated content and the translations are stored.
  • Click OK.

  • Now, Go to the Adaptor configuration page in AEM- http://localhost:4502/content/global-link/globallink-adaptor-configuration.html and enter required details for TDC web service URL, account user name, password etc. Screen also asks you to define a language key mapping and properties to include for translation.

    Scheduling Translations

    I am taking here an example of Asset's description metadata field. To submit asset's “description” metadata for translation, follow below steps-

    2. Fill in required details.  Click on the “Find Metadata” button; it will show up the result assets available for translation. Only those assets will be listed which have description property set.
    3.       Expand the asset(s), and check the metadata fields need to be send for translation. Next, move to the “Target Languages” drop-down and select the desired languages. Click on the “Start Workflow” button to initiate the translation workflow. Look at the screenshot below-



    4.       After this, go to TDC submission list page to check status- http://localhost:4502/content/global-link/globallink-adaptor-submissions-list.html

    Verifying Translation

    Translation workflow will update node properties sent for translation with translated text automatically once response is received.

    In order to display translation in front end, you can customize AEM UI to show translated data. In this example I will add a new tab named "Alt Text Translation" to show all Alttext translations to the author. 


    Select "Default" (You can pick image, forms etc. depending on your requirement) and Click on pencil icon to edit it. 

    1. Use the "+" icon next to tags in left hand screen to add a new tab- "Alt Text Translation"
    2. Use the "Build Form" in right hand screen to add language fields.

    Look at the below snapshot on how should it look-



    Once you have saved the metadata template, you can go to Asset Properties from Assets section. The properties section will look like this-


    Note: This article is based on integration of an older version of Translations.com Global Link Adaptor. While working with new adapter version, all above steps may not be required.

    Tuesday, August 2, 2016

    Bulk Editor/ Searching pages based on Parameters

    Bulk editor helps you in editing pages in bulk. Based on query parameters, you can search for pages under a root path and then you can edit properties of those pages. It provides you option to add conditions to fetch list of pages. You can also select additional columns to be displayed in reports.

    Bulk Editor URL: http://localhost:4502/etc/importers/bulkeditor.html


    Below is an example to search all pages with title as "Features"-


    Once the result come; you can edit the property values by double clicking them. Once you are done click on "Save" button. Look at the snapshot below-



    Alternatively, you can use "Export" option to download the result list as TSV file. Then you can modify the values in Excel and then Import it from the following URL-

    Bulk Import URL: http://localhost:4502/etc/importers/bulkeditor.html?hib=false



    You can also create a new TSV file in proper format and Import it using the above URL. While doing so you ought to be very careful to not override any unintended value/ property.

    Monday, August 1, 2016

    XSS Protection in AEM6

    XSS (Cross Site Scripting) protection in AEM to  prevent attackers to inject code into web pages viewed by other users, is based on AntiSamy Java library provided by OWASP (Open Web Application Security Project). Due to this sometime you may get following kind of errors:
    org.apache.sling.xss.impl.HtmlToHtmlContentContext AntiSamy warning: The iframe tag contained an attribute that we could not process. The src attribute had a value of "some-non-xss-standard-iframe-url". This value could not be accepted for security reasons. We have chosen to remove this attribute from the tag and leave everything else in place so that we could process the input.

    Most basic configurations for XSS protection is configured out of the box. In case you need to happen to change this, you can override these configurations but do it carefully because these configurations apply globally. The default AntiSamy configuration can be found at following location in AEM- /libs/cq/xssprotection/config.xml. For reference, XSS rules are defined like this:
    <!-- START: Additions for oembed inserts -->
    <regexp name="iframesrc" value="^(http:|https:)?\/\/(www\.)?(((youtube|youtube-nocookie|vimeo|player\.vimeo|dailymotion|instagram|tumblr|twitter|wordpress|facebook|wikipedia|stackoverflow)(\.com))|(flickr\.com|flic\.kr))\/([A-Za-z0-9]).*"/>
    <!-- END: Additions for oembed inserts -->

    This article categorizes the protection mechanism into two parts-

    1. Code Level Protection

    A. Use the features/ methods provided by XSS API in you AEM application JSP, Servlets, Services etc. while processing user inputs, page selectors etc. XSS API provides two type of features- encoding and validation. In general, validators are safer than encoders. Encoding only ensures that content within the encoded context cannot break out of said context. It requires that there be a context (for instance, a string context in Javascript), and that damage cannot be done from within the context (for instance, a javascript: URL within a href attribute.

    In Java code-
    import com.adobe.granite.xss.XSSAPI;
    import org.apache.sling.api.resource.ResourceResolver;
    
    public class UserInput {
      public String getFilteredURL(ResourceResolver resolver, String userInputText) {
        XSSAPI xssAPI = resolver.adaptTo(XSSAPI.Class);
        return xssAPI.getValidHref(userInputText);
      }
    }
    

    In JSP Code-
    <%@ include file="/libs/foundation/global.jsp" %><%
    %><%
        String siteTitle = request.getParameter("siteTitle");
        String websiteLink = request.getParameter("websiteLink");
    %>
    <html>
        <head>
            <title>
                <%= xssAPI.encodeForHTML(siteTitle); %>
            </title>
        </head>
        <body>
            <a href="<%= xssAPI.getValidHref(websiteLink); %>">Website Link</a>
        </body>
    </html>
    

    B.
    Sightly takes care of XSS prevention itself by virtue of it's framework architecture. This means that all HTML values and attributes are subject to XSS check before they are rendered by server. If you have to explicitly bypass this restriction then you need to use context="unsafe". But be very careful when you decide to do that beacause it disables escaping and XSS protection completely for the applied element which can cause security issues.

    2. Server Level Protection

    A web application firewall, such as mod_security for Apache should be used/ configured on dispatcher to make it more reliable.

    Following rules may come handy to you in security.conf at your dispatcher-

    # Disable cross site scripting

    RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} ^.*(<|%3C).*script.*(>|%3E).*
    RewriteRule .* /errors/404.html
    RewriteRule .* - [F]
    

    # Disable SQL Injection

    RewriteCond %{QUERY_STRING} ^.*(localhost|loopback|127\.0\.0\.1).*    [NC,OR]
    RewriteCond %{QUERY_STRING} ^.*(\*|;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|).* [NC,OR]
    RewriteCond %{QUERY_STRING} ^.*(;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|).*(/\*|
    union|select|insert|cast|set|declare|drop|update|md5|benchmark).* [NC]
    RewriteRule ^(.*)$ - [F,L]
    

    # Disable Clickjacking

    Header always append X-Frame-Options SAMEORIGIN

    # Disable unwanted HTTP Methods

    RewriteEngine on
    RewriteCond %{REQUEST_METHOD} ^TRACE [NC]
    RewriteRule .* - [F]
    RewriteCond %{REQUEST_METHOD} ^TRACK [NC]
    RewriteRule .* - [F]
    RewriteCond %{REQUEST_METHOD} ^DELETE [NC]
    RewriteRule .* - [F]
    RewriteCond %{REQUEST_METHOD} ^OPTIONS [NC]
    RewriteRule .* - [F]
    RewriteCond %{REQUEST_METHOD} ^PUT [NC]
    RewriteRule .* - [F]
    
    Sources:
    1. https://docs.adobe.com/docs/en/aem/6-0/administer/security/security-checklist.html
    2. http://tostring.me/270/how-to-prevent-cross-site-scripting-xss-attack-on-your-adobe-cq-based-web-application/

    CDN | Clearing Cloudflare cache

    In order to clear Cloudflare cache automatically via code, follow below steps: 1. Develop Custom TransportHandler Develop a custom Trans...