Expand my Community achievements bar.

Best practices for making AJAX request in AEM and not exposing whole content structure

Avatar

Level 4

Hi All,

In our project we are implementing GET AJAX request to hit servlet and pull down some search result on the basis of user selection. Problem which we are facing is that to my servlet I wish to pass on a search root path (Path under which I would like my query to search and as not providing any path predicate would make search very inefficient). Author should be able to provide the search root path from the edit dialog.

To achieve this I have come up with 2 solution, even though both of them work functionally still I am not sure if this correct way of implementing it, so looking forward to suggestion from you guys :) .

Approach 1 - I am using data attribute to set and pass currentNode path to my JS file which would hit a GET servlet to pull down results along with currentNode path as query parameter along with some more parameter necessary for filtering search result on the basis of end user selection. In my servlet I do request.getParameter("currentNodePath"); and get the resource of this path and later adapt it to a node and read the search root path from the node which author provided.

(Problem with this code is any body looking at page source would be able to see our full content path which we feel is not correct from security point of view, is it a valid concern? As we are using etc/mapping in production we dont want to show the end user path of our content structure above language node (en node).

JSP code

<div class="events-calendar-container"
    data-current-node-path="${currentNodePath}" data-tags="${datatags}">

</div>

JS code

 {
    return $.ajax({
      type: "GET",
      url: $(".events-calendar-container").attr("data-current-node-path")+".events.json",
      data: { 
          startDate: .eventsCalendar.convertDate(new Date(currentYear, currentMonth, 1)), 
        endDate: .eventsCalendar.convertDate(new Date(currentYear, currentMonth + 1, 0)), 
        tags: $('.events-calendar-container').attr('data-tags') 
      }
    });

Approach 2: Rather than passing the currentNode path as data attribute to my JS file, I am directly passing search root path as data attribute to my js file. Again to solve problem faced in first approach to hide the full exposed path. I created a custom tag which using I would be able to get the mapped path from etc mapping rather than exposing the whole path. Now when I make AJAX get request with JS it hits the servlet, but the problem is that it by default only takes ".html" as extension for this request as this path actually map to real html page in CQ and I guess resourceResolver does that. See the below new ajax request.

eventsCalendar.fetchEvents = function (currentYear, currentMonth) {
    return $.ajax({
      type: "GET",
      url: $(".events-calendar-container").attr("data-events-root-path")+".events.json",
      data: { 
          startDate: eventsCalendar.convertDate(new Date(currentYear, currentMonth, 1)), 
        endDate: eventsCalendar.convertDate(new Date(currentYear, currentMonth + 1, 0)), 
        tags: $('.events-calendar-container').attr('data-tags') 
      }
    });

Problem with above ajax request is it take whole 'events.json' as a selector while actually I wanted to sepcify events as selector while json as extension. So in my servlet properties while should ideally have json as extension as it returns json as response. But my Ajax request cannot resolve to my servlet as extension by default sent when I used resourceResolver mapping is .html and not .json.

@Properties({ @Property(
        name = "sling.servlet.resourceTypes", value = "sling/servlet/default", propertyPrivate = true), @Property(
        name = "sling.servlet.selectors", value = "events", propertyPrivate = true), @Property(
        name = "sling.servlet.extensions", value = "json", propertyPrivate = true)
, @Property(
        name = "sling.servlet.methods", value = "GET", propertyPrivate = true) })

Even though I have work around to remove the extension property from servlet  something like below after which my AJAX request finds my servlet. But still I am not comfortable with this approach as actually it is .html extension and I am just hacking to to return a JSON respose. Sorry for long question but any suggestion would be really appreciated.  Thank you :)

@Properties({ @Property(
        name = "sling.servlet.resourceTypes", value = "sling/servlet/default", propertyPrivate = true), @Property(
        name = "sling.servlet.selectors", value = "events", propertyPrivate = true), @Property(
        name = "sling.servlet.methods", value = "GET", propertyPrivate = true) })

 

Java function to be mapped path rather than showing whole content path

public static String getMappedPath(final Resource resource, final String absolutePath)
    {
        if (null != resource && null != absolutePath)
        {
            final ResourceResolver resourceResolver = resource.getResourceResolver();
            
            return (resourceResolver.map(absolutePath));
        }
        
        return null;
    }

1 Reply

Avatar

Employee Advisor

Hi,

that sounds a bit strange. Can you post these informations:

Thanks!

Jörg