Friday, November 6, 2020

Access JCR programatically code

Access JCR programatically


package com.aem.assets;


import java.io.BufferedWriter;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import javax.jcr.Node;

import javax.jcr.NodeIterator;

import javax.jcr.Property;

import javax.jcr.PropertyIterator;

import javax.jcr.Repository;

import javax.jcr.Session;

import javax.jcr.SimpleCredentials;

import javax.jcr.Value;

import javax.jcr.query.Query;

import javax.jcr.query.QueryManager;

import javax.jcr.query.QueryResult;

import org.apache.jackrabbit.commons.JcrUtils;


public class ExtractMetadata {


public static void main(String[] args) throws Exception {


// Create a connection to the CQ repository running on local host

Repository repository = JcrUtils.getRepository("http://localhost:4502/crx/server");


// Create a Session

Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));


// Create a node that represents the root node

Node root = session.getRootNode();


// Obtain the query manager for the session ...

QueryManager queryManager = session.getWorkspace().getQueryManager();



//readAssetMetadata(root, "/content/dam/demo", queryManager);

//readPageData(root, "/content/we-retail/language-masters/en/about-us", queryManager);

//insertNode(root, "apps", "folder");

//deleteNode(root, "apps/folder");

//readProperties(root, "content/dam/demo/dog.jpg");

//addProperties(root, "apps/folder");

//readProperty(root, "apps/folder");

//readChildNodes(root, "content/dam/demo/");

//readFileData("c:/temp/samplefile2.html");

//readStylesData(root, "/apps/wknd", queryManager);

//readcomponentsData(root, "/apps/aem65", queryManager);


}


private static void readAssetMetadata(Node root, String nodePath, QueryManager queryManager) {

try {

String title = "dc:title", description = "dc:description", tags="cq:tags", jcrTitle= "jcr:title", jcrDesc = "jcr:description";

int flag;

//Create a object of BufferedWriter class and defining file path 

BufferedWriter writer = new BufferedWriter(new FileWriter("c:/temp/AssetMetadata.csv"));


// Using AEM Query Manager API to query Nodes

String sqlStatement = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE([" + nodePath + "])";

Query query = queryManager.createQuery(sqlStatement, "JCR-SQL2");


// Execute the query and get the results ...

QueryResult result = query.execute();


// Iterate over the nodes in the results ...

NodeIterator nodeIter = result.getNodes();


writer.append("absTargetPath" + "," + "relSrcPath" + "," + "dc:title {{ String : multi }}" + "," + "dc:description {{ String : multi }}" + "," + "cq:tags {{ String : multi }}");

writer.newLine();

while (nodeIter.hasNext()) {

flag=1;

Node node1 = nodeIter.nextNode();

NodeIterator iter1 = node1.getNodes();

while (iter1.hasNext()) {

Node nextNode = iter1.nextNode();

String absPath = nextNode.getPath();

String modifiedPath = absPath.substring(1);

int index=absPath.lastIndexOf('/');     

String targetPath = absPath.substring(0,index-12);

String sourcePath = targetPath.substring(targetPath.lastIndexOf("/") + 1);


// Code to read node properties

if (root.hasNode(modifiedPath)) {

Node node = root.getNode(modifiedPath);

PropertyIterator iter = node.getProperties();

while (iter.hasNext()) {

Property nextProp = iter.nextProperty();

String propertyName = nextProp.getName();


if(propertyName.equals(title) || propertyName.equals(jcrTitle) || propertyName.equals(jcrDesc) || propertyName.equals(description) || propertyName.equals(tags)) {

Property property = node.getProperty(propertyName);

if(flag == 1) {

writer.append(targetPath+","+"Assets/"+sourcePath+",");

flag=0;

}

if (!property.isMultiple()) {

String propertyValue = node.getProperty(propertyName).getString();

writer.append(propertyValue + ",");

} else {

Value[] value = nextProp.getValues();

for (int i = 0; i < value.length; i++) {

writer.append(value[i].getString() + ",");

}

}

}

} writer.newLine();

} else {

System.out.println("Warning! Can't READ properties as path doesn't exists");

}

}

}

System.out.println("csv file with assets metadata created successfully");

writer.close();

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readPageData(Node root, String nodePath, QueryManager queryManager) {

try {

String fileReference = "fileReference", pageTitle = "jcr:title", panelTitle = "cq:panelTitle", elementNames = "elementNames", text = "text", description = "jcr:description", tags = "cq:tags";


//Create a object of BufferedWriter class and defining file path

BufferedWriter writer = new BufferedWriter(new FileWriter("c:/temp/siteProperties.csv"));


// Using AEM Query Manager API to query Nodes

String sqlStatement = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE([" + nodePath + "])";

Query query = queryManager.createQuery(sqlStatement, "JCR-SQL2");


// Execute the query and get the results ...

QueryResult result = query.execute();


// Iterate over the nodes in the results ...

NodeIterator nodeIter = result.getNodes();


while (nodeIter.hasNext()) {

Node node1 = nodeIter.nextNode();

NodeIterator iter1 = node1.getNodes();

while (iter1.hasNext()) {

Node nextNode = iter1.nextNode();

String absPath = nextNode.getPath();

String modifiedPath = absPath.substring(1);


String checkIfpagePath = modifiedPath.substring(modifiedPath.lastIndexOf("/")+1); 

if(checkIfpagePath.equals("jcr:content")) {

writer.newLine();

writer.append(absPath);

writer.newLine();

writer.newLine();

}

// Code to read node properties

if (root.hasNode(modifiedPath)) {

Node node = root.getNode(modifiedPath);

PropertyIterator iter = node.getProperties();

while (iter.hasNext()) {

Property nextProp = iter.nextProperty();

String propertyName = nextProp.getName();


if (propertyName.equals(fileReference) || propertyName.equals(pageTitle) || propertyName.equals(panelTitle) || propertyName.equals(elementNames) || propertyName.equals(text) || propertyName.equals(description) || propertyName.equals(tags)){

writer.append(propertyName + ",");

Property property = node.getProperty(propertyName);

if (!property.isMultiple()) {

String propertyValue = node.getProperty(propertyName).getString();

if (propertyName.equals(fileReference)) {

String imgUrl = "http://localhost:4502" + propertyValue;

writer.append(imgUrl + ",");

writer.newLine();

} else {

writer.append(propertyValue + ",");

writer.newLine();

}

} else {

Value[] value = nextProp.getValues();

for (int i = 0; i < value.length; i++) {

writer.append(value[i].getString() + ",");

}

writer.newLine();

}

}

} else {

System.out.println("Warning! Can't READ properties as path doesn't exists");

}

}

}

System.out.print("Site content successfully extracted");

writer.close();

} catch (Exception e) {

e.printStackTrace();

}

}


public static void insertNode(Node root, String existingNodePath, String newNodeName) {

try {

if (root.hasNode(existingNodePath)) {

if (root.hasNode(existingNodePath + "/" + newNodeName)) {

System.out.println("Warning! Can't ADD new node as node with same name already exists");

} else {

Node node = root.getNode(existingNodePath);

node.addNode(newNodeName);

System.out.println("New Node Inserted as " + existingNodePath + "/" + newNodeName);

}

} else {

System.out.println("Warning! Can't ADD new node as node doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void deleteNode(Node root, String deleteNodePath) {

try {

if (root.hasNode(deleteNodePath)) {

Node node = root.getNode(deleteNodePath);

node.remove();

System.out.println("Node " + deleteNodePath + " removed");

} else {

System.out.println("Warning! Can't DELETE as node doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readProperties(Node root, String nodePath) {

try {

if (root.hasNode(nodePath)) {

Node node = root.getNode(nodePath);

PropertyIterator iter = node.getProperties();

while (iter.hasNext()) {

Property nextProp = iter.nextProperty();

String propertyName = nextProp.getName();

System.out.print(propertyName + " : ");

Property property = node.getProperty(propertyName);

if (!property.isMultiple()) {

String propertyValue = node.getProperty(propertyName).getString();

System.out.println(propertyValue);

} else {

Value[] value = property.getValues();

int len = value.length;

for (int i = 0; i < len; i++)

System.out.println(value[i].getString());

}

}

} else {

System.out.println("Warning! Can't READ properties as path doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void addProperties(Node root, String addPropNodePath) {

try {

if (root.hasNode(addPropNodePath)) {

Node node = root.getNode(addPropNodePath);

node.setProperty("jcr:data", 6269);

node.setProperty("jcr:mimeType", "image/png");

System.out.println("Properties added for node: " + addPropNodePath);

} else {

System.out.println("Warning! Can't ADD Properties as node doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readProperty(Node root, String readPropNodePath) {

try {

if (root.hasNode(readPropNodePath)) {

Node node = root.getNode(readPropNodePath);

System.out.println("jcr:created:::" + node.getProperty("jcr:created").getString());

} else {

System.out.println("Warning! Can't READ Properties as node doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readChildNodes(Node root, String nodePath) {

try {

if (root.hasNode(nodePath)) {

Node node = root.getNode(nodePath);

NodeIterator iter = node.getNodes();

while (iter.hasNext()) {

Node nextNode = iter.nextNode();

String absPath = nextNode.getPath();

System.out.println(absPath);

}

} else {

System.out.println("Warning! Can't READ child nodes as path doesn't exists");

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void checkResSupertype(Node root, String filePath, QueryManager queryManager) {

Node savedRootValue = root;

try {

String resSuperType = "sling:resourceSuperType";

PropertyIterator filePropIter;

String modifiedFilePath = filePath.substring(1);

if (root.hasNode(modifiedFilePath)) {

Node FilePathnode = root.getNode(modifiedFilePath);

filePropIter = FilePathnode.getProperties();

while (filePropIter.hasNext()) {

Property nextProp = filePropIter.nextProperty();

String propertyName = nextProp.getName();

if (propertyName.equals(resSuperType)) {

String propertyValue = FilePathnode.getProperty(propertyName).getString();

System.out.println(propertyValue);

String modifiedvalue = "/apps/" + propertyValue;

// read styles for component

readStylesData(savedRootValue, modifiedvalue, queryManager);

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readFileData(String fileName) throws IOException {

int ch;

FileReader fr = null;

try {

fr = new FileReader(fileName);

} catch (FileNotFoundException fe) {

System.out.println("File not found");

}

while ((ch = fr.read()) != -1)

System.out.print((char) ch);

fr.close();

}

// Reads clientLibs folder from CRX and store in css and js file at given path

private static void readStylesData(Node root, String filePath, QueryManager queryManager) {

try {

String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);


// Creating a object of FileWriter class and defining file path

FileWriter cssFileWriter = new FileWriter("c:/temp/" + fileName + ".css");

FileWriter jsFileWriter = new FileWriter("c:/temp/" + fileName + ".js");


String sqlStatement = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE([" + filePath + "])";

Query query = queryManager.createQuery(sqlStatement, "JCR-SQL2");


// Execute the query and get the results ...

QueryResult result = query.execute();


// Iterate over the nodes in the results ...

NodeIterator nodeIter = result.getNodes();

String dataNode = "jcr:data";

while (nodeIter.hasNext()) {

Node node = nodeIter.nextNode();

NodeIterator iter = node.getNodes();

PropertyIterator propIter;

while (iter.hasNext()) {

Node nextNode = iter.nextNode();

String absPath = nextNode.getPath();

String modifiedPath = absPath.substring(1);


// Code to read node properties

if (root.hasNode(modifiedPath)) {

if (modifiedPath.contains(".css") || modifiedPath.contains(".less")) {

Node node1 = root.getNode(modifiedPath);

propIter = node1.getProperties();

while (propIter.hasNext()) {

Property nextProp = propIter.nextProperty();

String propertyName = nextProp.getName();

if (propertyName.equals(dataNode)) {

String propertyValue = node1.getProperty(propertyName).getString();

cssFileWriter.append(propertyValue);

// System.out.println(propertyValue);

}

}

}

if (modifiedPath.contains(".js")) {

Node node1 = root.getNode(modifiedPath);

propIter = node1.getProperties();

while (propIter.hasNext()) {

Property nextProp = propIter.nextProperty();

String propertyName = nextProp.getName();

if (propertyName.equals(dataNode)) {

String propertyValue = node1.getProperty(propertyName).getString();

jsFileWriter.append(propertyValue);

// System.out.println(propertyValue);

}

}

}

} else {

System.out.println("Warning! Can't READ properties as path doesn't exists");

}

}

}

cssFileWriter.close();

jsFileWriter.close();

} catch (Exception e) {

e.printStackTrace();

}

}


private static void readcomponentsData(Node root, String filePath, QueryManager queryManager) {

try {

String sqlStatement = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE([" + filePath + "])";

Query query = queryManager.createQuery(sqlStatement, "JCR-SQL2");


// Creating a object of FileWriter class and defining file path

FileWriter FileWriter = new FileWriter("c:/temp/comp.txt");

// Execute the query and get the results ...

QueryResult result = query.execute();

// Iterate over the nodes in the results ...

NodeIterator nodeIter = result.getNodes();


String resSuperType = "sling:resourceSuperType";

String primType = "jcr:primaryType";

int j = 1;

while (nodeIter.hasNext()) {

Node node = nodeIter.nextNode();

NodeIterator iter = node.getNodes();

PropertyIterator propIter;

while (iter.hasNext()) {

Node nextNode = iter.nextNode();

String absPath = nextNode.getPath();

String modifiedPath = absPath.substring(1);

// Code to read node properties

if (root.hasNode(modifiedPath)) {

Node node1 = root.getNode(modifiedPath);

propIter = node1.getProperties();

while (propIter.hasNext()) {

Property nextProp = propIter.nextProperty();

String propertyName = nextProp.getName();

if (propertyName.equals(primType)) {

String propertyValue = node1.getProperty(propertyName).getString();

if (propertyValue.equals("cq:Component")) {

j++;

}

} else if (propertyName.equals(resSuperType)) {

String propertyValue = "/apps/" + node1.getProperty(propertyName).getString();

System.out.println(propertyValue);

readStylesData(root, propertyValue, queryManager);

}

}

} else {

System.out.println("Warning! Can't READ properties as path doesn't exists");

}

}

}

System.out.println("Total components" + j);

FileWriter.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

Handling AEM Security

 

Handling AEM Security

 

There are various steps that you should take to ensure that your AEM installation is secure when deployed.

 

Ensure following Security guidelines:

 

1.     Run AEM In Production ready mode


With AEM 6.1, Adobe introduces the new "nosamplecontent" runmode aimed at automating the steps required to prepare an AEM instance for deployment in a production environment.

The new runmode will not only automatically configure the instance to adhere to the security best practices described in the security checklist, but will also remove all the sample project(wknd) and configurations in the process.



Note:  Running AEM in Production Ready Mode will effectively disable access to CRXDE Lite. If you need it for debugging purposes you have to enable it.

2.      Enabling the HTTPS transport layer

Enabling the HTTPS transport layer on both author and publish instances is mandatory for having a secure instance.

 

3.     Install security Hotfixes

Ensure that you have installed the latest Security Hotfixes provided by Adobe.

 

4.      Change default password for AEM Instance and OSGI Console

Adobe strongly recommends that after installation you change the password for the privileged AEM (on all instances) including below accounts:

 

·        The AEM admin account

 

Once you have changed the password for the AEM admin account, you will need to use the new password when accessing CRX.

 

·        The admin password for the OSGi Web console

 

This change will also be applied to the admin account used for accessing the Web console, so you will need to use the same password when accessing that.

 

Note:

 

·        These two accounts use separate credentials and having distinct, strong password for each is vital to a secure deployment.

 

·        Changing the admin account also changes the OSGi web console account. After changing the admin account, you should then change the OSGi account to something different.

 

How to Change AEM Password

 Navigate to:

·        http://localhost:4502/security/users.html (Touch UI) or

·        http://localhost:4502/useradmin (Classic UI)

 

Here you can edit the admin account and change the password and other information.

 

Note: Changing the admin account also changes the OSGi web console account. After changing the admin account, you should then change the OSGi account to something different.

 

Importance of Changing the OSGi Web Console Password:

 

·        Exposure of the server with a default password during startup and shutdown (that can take minutes for large servers);

 

·        Exposure of the server when the repository is down/restarting bundle - and OSGI is running.

 

How to Change OSGI console password

 

You must also change the password used for accessing the Web console.

 

This is done by configuring the following properties of the Apache Felix OSGi Management Console:

`

The password must be changed after the initial installation to ensure the security of your instance.

 

To do this:

 

·        Navigate to the web console at localhost:4502/system/console/configMgr .

 

·        Search for Apache Felix OSGi Management Console and change the user name and password.

 


·        Click save.


5.     Implement Custom Error handler

 

Adobe recommends to define custom error handler pages, especially for 404 and 500 HTTP Response codes in order to prevent information disclosure.

 

6.     Complete Dispatcher security checklist

 

AEM Dispatcher is a critical piece of your infrastructure. Adobe strongly recommend that you complete the dispatcher security checklist.

 

7.     Complete replication and transport user

 

The replication user is used to collect the content to be replicated on the author system before it is sent to the publisher.

 

The transport user should not be the admin user. Rather, set up a user on the publish system that has only access rights to the relevant portions of the publish system and use that user's credentials for the transport.


8.     Check the operations Dashboard security health checks

 

AEM 6 introduces the new Operations Dashboard, aimed at aiding system operators troubleshoot problems and monitor the health of an instance.

 

It can be viewed at:

 

http://localhost:4502/libs/granite/operations/content/healthreports/healthreportlist.html

 

The dashboard also comes with a collection of security health checks.

 

 It is recommended you check the status of all the security health checks before going live with your production instance. 

 

More information to manage health check dashboard can be checked at:

 

https://docs.adobe.com/content/help/en/experience-manager-64/administering/operations/operations-dashboard.html

 

9.     Delete any sample content

 

All example content and users (e.g. the Geometrixx project and its components) should

be uninstalled and deleted completely on a productive system before making it publicly accessible.

 

10.  Check and uninstall if Sling development bundle is there

 

The AEM Developer Tools for Eclipse deployes the Apache Sling Tooling Support Install (org.apache.sling.tooling.support.install).

 

This OSGi bundle should be uninstalled on both author and publish productive systems before making them accessible.

 

11.  CSRF protection framework

 

AEM 6.1 ships with a mechanism that helps protect agains Cross-Site Request Forgery attacks, called the CSRF Protection Framework, check and configure it in OSGI Configuratons.

 


12.  Configure sling referral filter

 

To address known security issues withCross-Site Request Forgery (CSRF) in CRX WebDAV and Apache Sling you need to add configurations for the Referrer filter in order to use it.

 

The referrer filter service is an OSGi service that allows you to configure:

 

·        Which http methods should be filtered.

 

·        Whether an empty referrer header is allowed.

 

·        and a white list of servers to be allowed in addition to the server host.

 

By default, all variations of localhost and the current host names the server is bound to are in the white list.

 

Steps to configure the referrer filter service:

 

1.     Open the Apache Felix console ( Configurations ) at:

 

https://localhost:4502/system/console/configMgr

 

2.     Login as admin.

 

In the Configurations menu, select:

 

Apache Sling Referrer Filter

 



 

In the Allow Hosts field, enter all hosts that are allowed as a referrer. Each entry needs to be of the form

 

<protocol>://<server>:<port>

 

For example:

 

https://allowed.server:80 (allows all requests from this server with the given port.)

 

If you also want to allow https requests, you have to enter a second line.

 

If you allow all ports from that server you can use 0 as the port number.

 

3.     Check the Allow Empty field, if you want to allow empty/missing referrer headers.

 

4.     Edit the methods this filter should use for checks with the Filter Methods field.

 

5.     Click Save to save your changes.

  

13.  Need to change some OSGI Settings

 

Some OSGI settings are set by default to allow easier debugging of the application. These need to be changed on your publish and author productive instances to avoid internal information leaking to the public.

 

For each of the following services the specified settings need to be changed:

 

So, Navigate to http://localhost:4502/system/console/configMgr and search for following configurations to make changes.

 

·         Adobe Granite HTML Library Manager :

 

o    enable Minify (to remove CRLF and whitespace characters).

 

o    enable Gzip (to allow files to be gzipped and accessed with one request).

 

o    disable Debug

 

o    disable Timing

 

·         Day CQ WCM Debug Filter :

 

o    uncheck Enable

 

·         Day CQ WCM Filter :

 

o    on publish only, set WCM Mode to "disabled"

 

·         Apache Sling Java Script Handler :

 

o    disable Generate Debug Info

 

·         Apache Sling JSP Script Handler :

 

o    disable Generate Debug Info

 

o    disable Mapped Content

  

14. Mitigate DOS (Denial of service) Attack


A denial of service (DoS) attack is an attempt to make a computer resource unavailable to its intended users.

 

This is often done by overloading the resource; for example:

 

·         With a flood of requests from an external source.

·         With a request for more information than the system can successfully deliver.

For example, a JSON representation of the entire repository.

·         By requesting a content page with an unlimited number of URLs, The URL can include a handle, some selectors, an extension, and a suffix - any of which can be modified.

For example, .../en.html can also be requested as:

 

o    .../en.ExtensionDosAttack

 

o    .../en.SelectorDosAttack.html

 

o    .../en.html/SuffixDosAttack

 

All valid variations (e.g. return a 200 response and are configured to be cached) will be cached by the dispatcher, eventually leading to a full file system and no service for further requests.

 

Configuring Sling to Prevent DoS

 

Sling is content-centric. This means that processing is focused on the content as each (HTTP) request is mapped onto content in the form of a JCR resource (a repository node):

 

·         The first target is the resource (JCR node) holding the content.

·         Secondly, the renderer, or script, is located from the resource properties in combination with certain parts of the request (e.g. selectors and/or the extension).

 

15.  Use Firewall to filter access to instance

 

The use of an operating system level firewall is necessary in order to filter access to points of your instance that might lead to denial of service attacks if left unprotected.

 

16.  Disabling WebDAV Access


WebDAV should be disabled on both the author and publish environments. This can be done by stopping the appropriate OSGi bundles.

 

1.     Open to the Felix Management Console running on:

 

http://localhost:4503/system/console/bundles.

 

2.     In the list of bundles, find the bundle named:

Apache Sling Simple WebDAV Access to repositories (org.apache.sling.jcr.webdav)

 

3.     Click the stop button (in the Actions column) to stop this bundle.

4.     Again in the list of bundles, find the bundle named:

Apache Sling DavEx Access to repositories

(org.apache.sling.jcr.davex)

 

5.     Click the stop button to stop this bundle.

 

17.  Perform a Penetration Test

 

Adobe strongly recommends to perform a penetration test of your AEM infrastructure before going on production