Monday, November 23, 2020

Beginners Tutorial: What is Cloud Manager for Adobe Experience Manager(AEM)?


What is Cloud Manager for AEM?

  • Cloud Manager is a Cloud service that allows customers to build, test, and deploy AEM applications hosted by Adobe Managed Services. 
  • Enables customers to manage their custom code deployments on their AEM-managed cloud environments with manageable pipeline automation and complete flexibility for their deployment timing or frequency.
  • Each customer gets its own Git Repository and their code is secure and not shared with any other Organizations.
  • Cloud Manager is only available to Adobe Managed Services customers using AEM 6.4 or above
  • Restructure the code with the latest arch type to support the Dispatcher deployment
  • Address the quality issues and adhere to the best practices for onboarding into Cloud Manager
  • Define application-specific Key Performance Indicators (KPIs)


Key Features

Self Service interface:

  • Enables customers to easily access and manage the cloud environment and CI/CD pipeline for their Experience Manager applications. 
  • Helps to define application-specific KPI's like peak page views per minute and expected response time for a page load,
  • Helps to define Roles and permissions for different team members.

CI/CD pipeline:

  • Setup optimized CI/CD pipeline to speed the delivery of custom code or updates such as adding new components on the website. 
  • Allows AEM project teams to quickly, safely, and consistently deploy code to all AEM environments hosted in AMS 
  • A thorough code scan is executed to ensure that only high-quality applications pass through to the production environment.
  • Quality checks include, code inspection, security testing, and performance testing are always performed as part of the CI/CD pipeline execution

Flexible Deployment Modes:

  • Cloud Manager offers customers flexible and configurable deployment modes so they can deliver experiences according to changing business demands
  • In automatic trigger mode, the code is automatically deployed to an environment based on specific events such as code commit. 
  • You can also schedule code deployments during specified time frames, even outside business hours.
  • Manual – trigger the deployment manually

Auto Scaling:

Cloud Manager detects the need for additional capacity when the production environment is subject to unusually high load and automatically brings additional capacity online via autoscaling feature.

The autoscaling feature will apply only to the Dispatcher/Publish tier, and will always be executed using a horizontal scaling method, with a minimum of one additional segment of a Dispatcher/Publish pair, and up to a maximum of ten segments.



Cloud Manager Benefits:

  • Enables organizations to self-manage Experience Manager in the cloud
  • Continuous Integration / Continuous Delivery of code to reduce time to market from months/weeks to days/hours
  • Cloud Manager provides continuous delivery and continuous integration for updates with zero downtime.
  • Code Inspection, performance testing, and security validation based on best practices before pushing to production to minimize production disruptions.
  • Automatic, scheduled or manual deployment even outside of business hours for maximum flexibility and control.
  • Autoscaling feature intelligently detects the need for increased capacity and automatically brings online additional Dispatcher/Publish segment(s).
  • Reduce the dependency with Adobe CSE for production deployment
  • Configure a set of content paths which will either be invalidated or flushed from the AEM Dispatcher cache for publish instances
  • Development on your local git repositories ate integrate with CM Git repository
  • API/Events/Webhooks for external tool integration through Adobe I/O


CI/CD Pipeline:

Define a set of deployment steps which are executed in sequence, the Cloud manager provides the below two major pipelines


  • Non-Prod Pipeline
  • Production Pipeline
Two types of Non-Prod pipeline
  • Code Quality Pipeline
  • Deployment Pipeline

Non-Prod - Code Quality Pipeline

  • Code Quality pipelines execute a series of steps on a code from a Git branch to build and be evaluated against Cloud Manager’s code quality scan
  • Helps to identify and fix the quality issues before planning for production deployment.
  • Code quality pipeline can be used before provisioning the environments
  • Quality report for review


Non-Prod - Deployment Pipeline


Deployment pipelines support the automated deployment of code from the Git repository to any Non-production environment, meaning any provisioned AEM environment that is not Stage or Production.



Production Pipeline


The CI/CD Production Pipeline is used to build and deploy code through Stage to the Production environment, decreasing time to value.


Build Triggers:
  • manually, 
  • with a Git commit 
  • based on a recurring schedule

The Production Deployment:
  • Application for Approval (if enabled)
  • Schedule Production Deployment (if enabled)
  • CSE Support (if enabled)


Cloud Manager Quality:

Quality checks including code inspection, performance testing, and security validation are conducted as part of the pipeline.

Code quality testing:


Cloud Manager uses SonarQube and OakPAL Content Rules to statically analyze the code and the content. It tests security, reliability, maintainability, coverage, skipped unit tests, open issues, and duplicated lines of code. Unfortunately, there is no way to add your custom rule, but you can mark some of the detected issues as false-positives.

Security testing:


Cloud Manager runs the existing AEM Security Heath Checks on stage following the deployment and reports the status through the UI. The results are aggregated from all AEM instances in the environment. If any of the Instances report a failure for a given health check, the entire Environment fails that health check.

Performance testing:


It tests both: page rendering and asset performance. After 30 minutes, it provides a report outlining i.e., CPU utilization, Disk IO Wait Time, and Page Error Rate. 

For each of the above mentioned Quality Gates, Adobe introduced the concept of the three-tier result:

Critical – these are issues identified by the gate which cause an immediate failure of the pipeline
Important – these are issues identified by the gate which cause the pipeline to enter a paused state. A deployment manager, project manager, or business owner can either override the issues, in which case the pipeline proceeds or they can accept the issues, in which case the pipeline stops with a failure
Info – these are issues identified by the gate which are provided purely for informational purposes and have no impact on the pipeline execution.

The performance and security testing are minimal you should execute some external performance and security tests if required.

Cloud Manager Roles

Business Owner - Primary user who completes the initial Cloud Manager setup. Responsible for defining KPIs, approving production deployments, and overriding important 3-tier failures.

Program Manager - Uses Cloud Manager to perform team setup, review status, and view KPIs. May approve important 3-tier failures.

Deployment Manager - Manages the deployment operations. Uses Cloud Manager to execute stage and production deployments. May approve important 3-tier failures. Has access to Git repository.



Cloud Manager API


  • The Cloud Manager API enables Cloud Manager customers to interact with the same underlying capabilities exposed through the web UI in a fully programmatic fashion
  • This allows for the integration of the Cloud Manager Continuous Integration / Continuous Delivery pipeline with other systems.
  • The API’s are managed through Adobe I/O 
  • By using Adobe I/O Events, Cloud Manager can send external applications notifications when key events occur

Sample Use Cases

  • Starting the Cloud Manager CI/CD pipeline from an external system.
  • Executing additional tests between the standard Cloud Manager performance tests and the ultimate production deployment.
  • Triggering additional activities after the pipeline execution is complete or a specific step has been completed, for example
  • CDN cache invalidation once the production deployment is finished.
  • Deploying related applications to non-managed Services systems.
  • Notifying on other channels (e.g. Slack, Microsoft Teams).
  • Creating issue reports in bug tracking systems (e.g. Atlassian JIRA) on pipeline failures

Reference - https://www.adobe.io/apis/experiencecloud/cloud-manager/api-reference.html#!AdobeDocs/cloudmanager-api-docs/master/swagger-specs/api.yaml

Cloud Manager Notifications

Cloud Manager allows the user to receive notifications when the production pipeline starts and completes (successfully or unsuccessfully), at the start of a production deployment, as well as when the Go-Live Approval and Scheduled steps are reached.

The notifications appear in a sidebar in Cloud Manager UI

Email Notifications:

By default, notifications are available in the web user interface across Adobe Experience Cloud solutions. Individual users can also opt for these notifications to be sent through email, either on an immediate or digest basis.

External Tool Notification:

Notifying on other channels (e.g. Slack, Microsoft Teams) though CM API and Events

Cloud Manager Environment Flow




Environment specific Cloud Manager Git branches for non-stage and prod environments i.e. Dev and UAT

Non-Prod Deployment pipeline for  non-stage and prod environments i.e. Dev and UAT

Production pipeline for stage and Prod deployment through master branch

The development will happen in the customer-specific git repository and merged with the Cloud Manager git repository whenever required.

Cloud Manager now supports building customer projects with both Java 8 and Java 11. By default, projects are built using Java 8. Customers who intend to use Java 11 in their projects can do so using the Apache Maven Toolchains plugin.

You can build the End to End CI/CD pipeline with your local git repository and if required external Ci?CD tools e.g. Jenkins and the CM APIs.


Thursday, November 12, 2020

Aspect-Oriented Programming (AOP) with Adobe Experience Manager(AEM)

What is AOP?



Aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to the existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a “pointcut” specification, such as “log all function calls when the function’s name begins with ‘set’”. This allows behaviors that are not central to the business logic (such as logging) to be added to a program without cluttering the code, core to the functionality.

Aspect-Oriented Programming provides a solution to implement Cross-Cutting Concerns.
Implement the cross-cutting concern as an aspect.
Define pointcuts to indicate where the aspect has to be applied.

This ensures that the cross-cutting concerns are defined in a centralized component and can be applied as needed.

This enables some of the below benefits
  • Reusable code
  • Cleaner code
  • Write less code
  • Less boilerplate code
  • Easy to maintain

Let us quickly see some of the definitions

  • Advice — Define what needs to be applied and when
  • Jointpoint — Where the Advice is applied
  • Pointcut — a combination of different Jointpoints where the advice needs to be applied.
  • Aspect — applying the advice at the pointcuts

Types of Advice:


  • Before Advice — the advice runs before the method execution
  • After Advice — the advice runs after the method execution
  • After Returning Advice — the advice runs after the method executes successfully
  • Around Advice — the advice can run before and after the method execution
  • Throws Advice — ensures the advice runs if the method throws an exception

AspectJ


AspectJ is an aspect-oriented extension to the Java programming language. AspectJ AOP implementation provides many annotations to support AOP programming in Java.

  • @Aspect — declares the class as an aspect.
  • @Pointcut — declares the pointcut expression.

The annotations used to create advices are given below:
  • @Before declares the before advice. It is applied before calling the actual method.
  • @After declares the after advice.
  • @AfterReturning declares the after returning advice.
  • @Around declares the around advice.
  • @AfterThrowing declares the throws advice.

AspectJ offers different required dependencies in the Maven Central repository under group org.aspectj.

AspectJ with AEM


Let us now see how to enable the AspectJ with AEM

As a first step enables the below plugin in core module pom.xml(the plugins and dependency versions are added based on Java 1.8, change based on your Java version )

<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>aspectj-maven-plugin</artifactId>
   <version>1.11</version>
   <configuration>
      <complianceLevel>1.8</complianceLevel>
      <source>1.8</source>
      <target>1.8</target>
      <encoding>UTF-8</encoding>
   </configuration>
   <executions>
      <execution>
         <goals>
            <goal>compile</goal>
         </goals>
      </execution>
   </executions>
</plugin>


Enable the AspectJ dependencies to the Core module Pom.xml

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.13</version>
</dependency>


Embed the AspectJ runtime dependency to Core bundle — enable the below configuration changes to core module pom.xml

<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-maven-plugin</artifactId>
<executions>
<execution>
<id>bnd-process</id>
<goals>
<goal>bnd-process</goal>
</goals>
<configuration>
<bnd><![CDATA[
Import-Package: javax.annotation;version=0.0.0,*
-includeresource: aspectjrt-1.8.13.jar;lib:=true
]]></bnd>
</configuration>
</execution>
</executions>
</plugin>


Now define the Aspect — the aspect is going to execute After, Before, and Around advice.





execution(* com.aspectj.core.servlets.*.doGet(..)) — Defines the PointCut, the advice will be run for the doGet method on the servlets under com.aspectj.core.servlets package

  • The first wildcard — matches any return value
  • com.aspectj.core.servlets.*.doGet — doGet method on the servlets under com.aspectj.core.servlets package
  • (…) — any number of parameters (zero or more)

logExecutionTime — Around advice, log the method execution time for all Servlet “GET” requests

logRequestHeader — Before advice, log the HTTP request headers for all Servlet “GET ”requests. Mapping the input variable req(the variable should be defined in the same order as the actual method signature) for using inside the Advice , args(req,…) — req as a first parameter followed by zero or more parameter

addCustomHeader — Before advice, add custom HTTP headers for all Servlet “GET ”responses. Mapping the input variable resp(the variable should be defined in the same order as the actual method signature) for using inside the Advice, args(…,resp) — resp as the last parameter

Now while invoking the servlets under com.aspectj.core.servlets through the “GET” method, the logExecutionTime, logRequestHeader and addCustomHeader Advice run and perform the appropriate operations.

The AOP will help us to address the cross-cut concerns in Java e.g. logging in all methods, this helps us to write clean code with better maintainability. The common concerns across the project can be maintained separately as an Advice and executed runtime based on the PointCut configuration.

Demo Project —https://github.com/techforum-repo/youttubedata/tree/master/aspectj


Thanks for reading, feel free to add your comments



Sunday, October 25, 2020

Adobe Experience Manager(AEM): HTTP Security Headers for Websites

  • In this tutorial, let us discuss the different HTTP security headers and how to enable those headers for the AEM platform.

    Headers are part of the HTTP specification, defining the metadata of the message in both the HTTP request and response.

    Security headers are HTTP response headers that define whether a set of security precautions should be activated or deactivated on the web browser.

    Let us see some of the most important security headers and how to enable those in the AEM platform.

    Image for post

    Strict-Transport-Security

    The HTTP Strict-Transport-Security response header lets a web site tell browsers that it should only be accessed using HTTPS, instead of using HTTP.

    Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

    max-age=<expire-time> — The time, in seconds, that the browser should remember that a site is only to be accessed using HTTPS.

    includeSubDomains — If this parameter is specified, this rule applies to all of the site’s subdomains as well.

    preload — this parameter indicates that the site is present on a global list of HTTPS-only sites

    This would inform the visiting web browser that the current site (including subdomains) is HTTPS-only and the browser should access it over HTTPS for the next 2 years(63072000 seconds).

    Before implementing this header, you must ensure all your website pages (including sub-domain pages) are accessible over HTTPS else they will be blocked by the browser.

    The header should be enabled from the webserver(Dispatcher), to enable the header in Apache, use mod_header module and set the header as below in the virtual host file

    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;preload"

    X-Frame-Options

    The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe>, <embed>, or <object>. Sites can use this to avoid click-jacking attacks, by ensuring that their content is not embedded into other sites.

    X-Frame-Options: DENY
    X-Frame-Options: SAMEORIGIN

    DENY — The page cannot be displayed in a frame, regardless of the site attempting to do so.

    SAMEORIGIN
    The page can only be displayed in a frame on the same origin as the page itself.

    The header should be enabled from the webserver(Dispatcher), to enable the header in Apache, use mod_header module and set the header as below in the virtual host file

    Header always append X-Frame-Options SAMEORIGIN

    The Content-Security-Policy(CSP) HTTP header has a frame-ancestors directive which overrides X-Frame-Options in modern browsers.

    Refer to the below video for more details on X-Frame-Options and CSP frame-ancestors.

    Content Security Policy (CSP)

    Content-Security-Policy is the name of an HTTP response header that modern browsers use to enhance the security of the document. The Content-Security-Policy header allows you to restrict how resources such as JavaScript, CSS, or pretty much anything that the browser loads.

    Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks.

    The header should be enabled from the webserver(Dispatcher), to enable the header in Apache, use mod_header module and set the header as below in the virtual host file

    Header always set Content-Security-Policy "default-src 'self';script-src 'self' https://sub.mydomain.com; img-src 'self' https://www.example.com;frame-ancestors 'self' http://mydomain.com:8000"

    The above header enables the browser to

    load the scripts(script-src) only from the same domain and https://sub.mydomain.com

    load the images(img-src) from the same domain and https://www.example.com

    allows only the webpages from the current domain to iframe this page

    Refer to the below URL for more details on CSP

    X-Content-Type-Options

    The X-Content-Type-Options header prevents “MIME sniffing” which is really a feature in Internet Explorer and Google Chrome. It allows the browser to scan or “sniff” the content and respond away from what the header may instruct.

    The X-Content-Type-Options headers instruct browsers to set the content type as instructed(ensure you’ve set the content types correctly) and never detect the type of their own.

    The header should be enabled from the webserver(Dispatcher), to enable the header in Apache, use mod_header module and set the header as below in the virtual host file

    Header always set X-Content-Type-Options nosniff

    Feature-Policy

    Feature Policy HTTP Security Header tells the modern browsers which browser features are allowed or denied. Feature Policy allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. Feature Policy allows you to control which origins can use which features, both in the top-level page and in embedded frames.

    The header should be enabled from the webserver(Dispatcher), to enable the header in Apache, use mod_header module and set the header as below in the virtual host file

    Disable the geolocation and camera API’s for all the contexts

    Header always set Feature-Policy "geolocation 'none'; camera 'none'"

    Enable the geolocation and camera API’s only for the pages from the current domain and the pages from myexample1.com

    Header always set Feature-Policy "geolocation 'self' https://myexample1.com; camera 'self' https://myexample1.com"

    Refer to the below URL for more details on Feature-Policy

    These are some of the critical HTTP security headers that can be enabled to protect the AEM platform from security attacks.

    Feel Free to provide your comments.



Friday, September 11, 2020

Adobe Experience Manager: Reporting on User’s Last Login Date

 In this tutorial let us see the details on how to build a custom user report in AEM to get the user profile data along with last login details.

AEM won’t provide any OOTB feature to track the last login details of the users — timestamp of the user’s login.

Sometimes we may have the requirement to report the last login timestamp of the users for auditing purposes e.g identify the users who are not login to the system for the last 1 month, identify the inactive users, etc

This can be achieved by enabling a Custom AuthenticationInfoPostProcessor to capture the last login timestamp and building a custom ACS AEM Commons report to fetch the required user profile data along with the last login timestamp.

As a first step define a custom AuthenticationInfoPostProcessor component to update the last login timestamp to the user profile.

AuthenticationInfoPostProcessor

AuthenticationInfoPostProcessor allows bundles to modify the AuthenticationInfo object after authentication has been performed.

AuthenticationHandler#extractCredentials invokes AuthenticationInfoPostProcessor#postProcess with AuthenticationInfo on successful authentication. The “postProcess” can modify the AuthenticationInfo or perform other operations based on the requirement in our case updating the user profile with login timestamp.

Let us enable a custom AuthenticationInfoPostProcessor that will update the user profile with the last login timestamp.


Enable a service user with the name “custom-user-manager” and provide the jcr:read/jcr:write access to /home/users also enable the user service mapping

Image for post
Image for post

Now the user profile will be updated with the login timestamp on every login to the custom property “lastloggedin”.

Image for post

Let us now build a custom ACS AEM Commons report to fetch the basic user data

Tools →ACS AEM Commons →Reports

Add a new Report with the name “user-report” (I am generating this in AEM as Cloud Author instance with the latest — 4.8.0 ACS AEM Commons package)

Image for post

Edit the report and add the “JCR Query Report configuration” component in the Configuration section.

Query — this excludes the system-specific users, modify the query based on your requirement to fetch the report for different scenarios.

SELECT * FROM [rep:User] AS user WHERE ISDESCENDANTNODE([/home/users]) AND NOT ISDESCENDANTNODE([/home/users/system/cq:services/internal]) AND NOT ISDESCENDANTNODE([/home/users/system/acs-commons]) AND NOT ISDESCENDANTNODE([/home/users/system]) AND NOT ISDESCENDANTNODE([/home/users/system/translation])

Query Language — JCR SQL2

Page Size -50

Image for post

Now configure the required fields including “lastloggedin” under Result Columns with component Type “ACS Commons Report Builder Text Column”

Image for post

Now open the report and click on “Execute Report”, the report can be downloaded as a CSV file if required — the report now includes the last login timestamp of the users.

Image for post

The same report can also be generated through Tools →ACS AEM Commons →User to CSV Exporter, this report includes the additional details like “group names” but includes all the users in the system, the report can be downloaded as a CSV file.

Image for post

Even the query builder can be used to identify the user’s login to the system within a specific time( the parameters can be modified to fetch the data for different scenarios)

p.hits=selective
p.limit=-1
path=/home/users
type=rep:User
1_relativedaterange.property=profile/lastloggedin
1__relativedaterange.lowerBound=-1M
orderby=@profile/lastloggedin
p.properties=profile/lastloggedin profile/givenName profile/familyName profile/email rep:authorizableId

The 1__relativedaterange.lowerBound value can be changed based on your requirement to 1s 2m 3h 4d 5w 1M 1y

http://localhost:4502/bin/querybuilder.json?1_relativedaterange.lowerBound=-1M&1_relativedaterange.property=profile%2flastloggedin&orderby=%40profile%2flastloggedin&p.hits=selective&p.limit=-1&p.properties=profile%2flastloggedin%20profile%2fgivenName%20profile%2ffamilyName%20profile%2femail%20rep%3aauthorizableId&path=%2fhome%2fusers&type=rep%3aUser

This will provide the JSON with user details who log in to the system for the last one month.

{
"success": true,
"results": 2,
"total": 2,
"more": false,
"offset": 0,
"hits": [
{
"rep:authorizableId": "albin",
"profile": {
"lastloggedin": "2020-09-10T22:15:41.807+05:30",
"givenName": "Albin",
"familyName": "Issac",
"email": "[email protected]"
}
},
{
"rep:authorizableId": "admin",
"profile": {
"lastloggedin": "2020-09-11T01:52:56.358+05:30",
"familyName": "Administrator"
}
}
]
}

The Custom AuthenticationInfoPostProcessor can be modified even to add other scenarios e.g capturing the number of times the user login to the system.




Saturday, August 22, 2020

Content Preview/Review Solution in AEM/AMS

 This tutorial explains the approach to define a preview solution for AEM(Adobe Experience Manager)/AMS(Adobe Managed Server) platform to preview the content through Author instance before activating the content to publishers.

Some of the options to enable the preview options are

  1. Share the author URL with wcmmode=disabled, this requires the reviewer should be on-boarded into the Author environment to carry the review
  2. Enable an additional preview(publish) instance, establish the workflow to send the content to the preview server for review/approval before publishing the content to live, the reviewer can use the dedicated review URL to review the content. This approach needs an additional server license to review the content.
  3. Move the content to stage servers for review, the workflow can be established to move the content to a Stage environment for review, this approach has some restriction from AMS to move the content from Production to Stage servers through the workflow. This approach can be used for on-premise setup, refer the following URL for more details — https://www.albinsblog.com/2018/02/approach-to-implement-content-preview-in-adobe-experience-manager.html#.X0FhqOhKjb0

Let us now see an alternative simple approach to enable the content review solution in AEM

Content in an AEM Author instance is accessible with a special query string parameter that disables the AEM authoring user interface — ?wcmmode=disabled.

Additionally, by configuring a read-only user account within AEM with an explicit password set, the default single sign-on (“SSO”) behavior that redirects regular users to SAML for authentication is bypassed when sending those credentials via a standard HTTP Authorization header.

Combining these facts, a reverse proxy configuration using CloudFront can be set up within an AWS account to provide a lightweight, scalable review
solution with affordable CloudFront data transfer costs.

Image for post

Cloudfront Configuration

As a first step, let us create the required configurations for CloudFront — the AMS managed CloudFront instance can’t be used to enable these configurations, the custom CloudFront should be used.

Create two distinct AWS [email protected] functions(Node JS) to be fired on the viewer request and origin request events

AEM-Preview-Solution

config.js

"use strict";module.exports = {
authUser: "reviewuser",
authPass: "reviewuser!",
aemUser: "reviewaemuser",
aemPass: "reviewaemuser!",
aemAuthorDisableParam: "wcmmode=disabled"
};

origin-request-handler

When a request hits this CloudFront request, the origin request Lambda script to append the ?wcmmode=disabled query string parameter to the end of the URL (merging with any existing parameters) before forwarding to the origin(AEM Author).

Additionally, ensures the HTTP Authorization header with AEM preview user is added before the origin request;

"use strict";const config = require("./config.js");exports.handler = (event, context, callback) => {
const cfRequest = event.Records[0].cf.request;
// Reject root requests
if (cfRequest.uri === "/") {
callback(null, {
status: "400",
body: "Invalid preview URL."
});
return;
}
// Disable authoring mode
cfRequest.querystring += (cfRequest.querystring === "" ? "" : "&") + config.aemAuthorDisableParam;
// Set authorization header
cfRequest.headers["authorization"] = [
{
key: "Authorization",
value:
`Basic ${new Buffer(`${config.aemUser}:${config.aemPass}`).toString("base64")}`
}
];
// Send back
callback(null, cfRequest);
};
AEM-Preview-Solution

viewer-request-handler

Sets an Authorization header when the viewer request event is fired, ensuring the content at this preview hostname is protected by a standard HTTP Basic Authentication prompt — users prompted with basic authentication to access the preview domain.

"use strict";const config = require("./config.js");exports.handler = (event, context, callback) => {
const cfRequest = event.Records[0].cf.request;
// Construct the auth string
const authString =
`Basic ${new Buffer(`${config.authUser}:${config.authPass}`).toString("base64")}`;
// Add auth header
if (
typeof cfRequest.headers.authorization === "undefined" ||
cfRequest.headers.authorization[0].value !== authString
) {
const response = {
status: "401",
statusDescription: "Unauthorized",
body: "Unauthorized",
headers: {
"www-authenticate": [{ key: "WWW-Authenticate", value: "Basic" }]
}
};
callback(null, response);
return;
}
// Continue request processing if authentication passed
callback(null, cfRequest);
};
AEM-Preview-Solution

Configure a new CloudFront distribution with the below settings:

General

  • The alternative domain name (CNAMEs): preview-example.com
  • Add a custom SSL certificate corresponding to the above hostname
    Origin

Origin

  • Origin domain name: author-prod-example.com(the author domain name, this domain will be used CloudFront to connect to author server)
  • Origin protocol policy: HTTPS Only

Behavior

  • Origin protocol policy: HTTPS Only
  • Viewer Protocol Policy: Redirect HTTP to HTTPS
  • Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE(enable the minimum required options)
  • Cache based on selected request headers: Whitelist
  • Whitelist: Authorization, Host
  • Minimum TTL, Maximum TTL, Default TTL: all set to 60 — CloudFront caches the request for a configurable duration (60 seconds, currently), to avoid applying an unnecessary load to the Author instance;
  • Forward cookies: None
  • Compress objects automatically: Yes
  • Lambda function associations:
    Origin request: point to the ARN of the origin-request-handler
    Viewer request: point to the ARN of the viewer-request-handler
Image for post

Point a new DNS hostname preview-author.example.com(CNAME) to a new AWS CloudFront distribution through DNS Zone manager(e.g xxxxxxxxx.cloudfront.net).

preview-author.example.com CNAME xxxxxxxxx.cloudfront.net

AEM Configuration

Create a preview user in the Author instance with read-only access to the appropriate content/DAM and an explicit password set- reviewaemuser/reviewaemuser!(Please validate with Adobe before implementing this solution if there is any licensing issue with this common user, my understanding is there should not be any impact)

The Author instance is configured with this preview hostname as an additional VHOST in author-vhosts.any — author-vhosts.any, this file enable the supported vhosts for author-farm.any, also disable the http to https redirect in the default.vhost for the specific domain, even though the preview URL is enabled through https the SSL forward related headers will not be sent to the Dispatcher e.g “X-Forwarded-Proto”

default.vhost

RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} !^preview-author.example.com$
RewriteCond %{REQUEST_URI} !^/dispatcher/invalidate.cache
RewriteRule !/eagle/check https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

author-vhosts.any

"author-prod-example.com"
"preview-author.example.com"

AEM renders the page in the Author instance with the AEM authoring user interface disabled, effectively producing HTML markup identical to the output of the Publish instance once activated

Now the configurations are ready, Web publishers can construct a URL similar to the below, reflecting a page location within AEM, and circulate this to any user needing to preview the currently-authored content before it is activated live to the public-facing website. This URL is accessible with complete content path, but behind the credentials provided(reviewaemuser/reviewaemuser!). https://preview-author.example.com/content/test/us/en/home.html