March 30, 2021
Estimated Post Reading Time ~

Send a CSRF Token to an AEM 6.1 Servlet without using jQuery or granite.csrf.standalone clientlib

Introduction
AEM 6.1 introduced new CSRF protections for Servlets. If you're using OOTB AEM jQuery, this is mostly handled for you. I want to cover the use case for not using jquery or the granite.csrf.standalone ClientLib.

Why
I've been making it a point to reduce my dependency on jQuery. With an AEM author, you'll never get 100% away from it, but it's possible to do on publish if you're doing typical WCM type sites. Also, with my current project, we are keeping the site as dependency free as humanly possible.

How
The trick is to send an async XHR request to the token endpoint (/libs/granite/csrf/token.json), pass that token on to your servlet as a header property called "CSRF-Token".

Below you see a fairly basic Sightly Component. Comments are inline.

<form method="POST" id="registerForm">
<input name="email" value="emily.andrews@mailinator.com" id="email"/>
<input type="submit" name="submit" id="submit"/>
</form>

<script type="text/javascript">
"use strict";

// Get our registration form
var registerForm = document.querySelector("#registerForm");

// Add the listener
registerForm.addEventListener("submit", function(event){

// Stop the form from submitting
event.preventDefault();

// Grab the email address
var email = document.querySelector("#email").value;

// Build a new XHR
var xhr = new XMLHttpRequest();

// On XHR state change and 200, parse the json to get the token
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var msg = JSON.parse(xhr.responseText);
// Send the request to our POST Servlet
sendRequest(msg.token, email);
}
};
// Open the request to the token endpoint and send the GET
xhr.open("GET", "/libs/granite/csrf/token.json", true);
xhr.send();
});

function sendRequest(token, email) {

// Create a form data object and stick email inside it.
var formData = new FormData();
formData.append("email", email);

// Build a new XHR request
var xhr = new XMLHttpRequest();

// On XHR state change and 200, parse the json to get the email address
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var msg = JSON.parse(xhr.responseText);
console.log(msg.email);
}
};
// Open the POST request to our servlet, set the CSRF Token in the header
xhr.open("POST", "/bin/registerUser", true);
xhr.setRequestHeader("CSRF-Token", token);
xhr.send(formData);
}

</script>


And a simple servlet to return the information back...

package org.millr.core.servlets;

import java.io.IOException;
import java.rmi.ServerException;

import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A simple servlet to receive a POSTed email address and return it as a JSON object.
*/
@SlingServlet(paths="/bin/registerUser", methods="POST", metatype=false)
public class UserRegistrationServlet extends SlingAllMethodsServlet {

/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(UserRegistrationServlet.class);

/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;

@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServerException, IOException {
LOGGER.info(">>>>>> In doPost");

try
{
String email = request.getParameter("email");
LOGGER.info("Email Adress: " + email);

JSONObject json = new JSONObject();
json.put("email", email);
response.setContentType("");
response.getWriter().write(json.toString());
}
catch(Exception e)
{
e.printStackTrace();
}
LOGGER.info(">>>>>> Leaving doPost");
}
}



By aem4beginner

1 comment:

If you have any doubts or questions, please let us know.