Set response headers in CQ5/AEM - aem

We need to set below response headers in CQ5/AEM based application.
Http Header: Frame options Set X-Frame-Options: SAME ORIGIN
Http Header: Strict Transport Security Strict-Transport-Security: max-age=10886400; includeSubDomains; preload
I have done like these changes in my prior application using servlet filter to intercept the request. Similarly I tried to use the SlingFilter for this application. However it seems to be called many times for each request (when it download js,css,json files etc). Please see below code snippet,
#SlingFilter(scope = SlingFilterScope.COMPONENT, order = Integer.MIN_VALUE)
#Properties({
#Property(name="pattern",value="/soni/template/", propertyPrivate=false)
})
public class ResponseHeaderFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
try {
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.setHeader("Strict-Transport-Security", "max-age=10886400; includeSubDomains");
filterChain.doFilter(request, httpResponse);
httpResponse.setHeader("X-Frame-Options", "SAMEORIGIN");
} catch (Exception e) {
e.printStackTrace();
}
}
Is this the right way to do it in CQ5/AEM? How do I restrict this to once per page request?
or is there better way to do it like configuration at dispatcher etc?

Because you are using the Component scope, this filter is called every time you include a component, which is not your intention.
Please use request scope:
scope = SlingFilterScope.REQUEST
Refer to this page:
https://sling.apache.org/documentation/the-sling-engine/filters.html

Related

How to removing response header with a RestFilter

Is it possible to remove response headers with a RestFilter? Looking at this cookbook you would say it should be possible. However, the filter is only called when the request is incoming, before the call to the resource class. I was expecting to have a hook where I can modify the response headers before sending it back to the client.
i had a look at CORSFilter as an example, but it only sets headers, not remove them.
To be more specific, I want to remove the WWW-Authenticate header that is set by the Auth provider when the session has expired. This header causes a popup in the browser (chrome) that is undesirable.
what you need is a javax.ws.rs.container.ContainerRequestFilter. In jax-rs such filters can be registered in a javax.ws.rs.core.Application. The application used in ICM is com.intershop.component.rest.internal.application.DefaultRestApplication which can be adapted using an com.intershop.component.rest.internal.application.ApplicationClassesProvider that can be registered using a Set-Binding.
So you could create a Guice-Module and your filter:
public class MyRestModule extends AbstractModule
{
#Override
protected void configure()
{
Multibinder<ApplicationClassesProvider> binder = Multibinder.newSetBinder(binder(),
ApplicationClassesProvider.class);
binder.addBinding().toInstance(c->c.accept(MyResponseFilter.class));
}
}
public class MyResponseFilter extends ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
{
response.getHeaders().remove("WWW-Authenticate");
}
}
Please note that this filter will be applied to all requests, so please make sure you remove headers only for requests you really care about.

rest service works when deployed in Eclipse but not in Tomcat

I implemented rest web services with Spring. When I deployed it in Eclipse as a Spring Boot Application, it works. However when I deployed it in Tomcat 7 on the same machine, it does not work. The error message is as follows:
XMLHttpRequest cannot load http://localhost:8080/ristoreService/oauth/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8081' is therefore not allowed access.
My CORS filter looks like this:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8081");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, "
+ "Origin,Access-Control-Request-Method, Access-Control-Request-Headers, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
If I comment out response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8081");, I still get the same error. It wouldn't work without this line even if I deploy in Eclipse. Why does it act differently being deployed under different environment on the same ip?
EDIT:
I tested the url http://localhost:8080/ristoreService/oauth/tokenwith rest client tester "CocoaRestClient" and got 404. So I made up a url which apparently does not exist http://localhost:8080/xxxxx and run it in UI (angularjs) and again got the CORS error. I think the error is kind of misleading, it is after all a 404. But why does it complain not found when the war was deployed successfully with the name ristoreService.war under webapps in Tomcat?
Try using a FilterRegistrationBean. Looks like this in Java Config:
#Bean
public FilterRegistrationBean authorizationFilter(){
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(authorizationFilter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/v1/*");
filterRegBean.setUrlPatterns(urlPatterns);
return filterRegBean;
}
Any reason why you're not using Spring Boot's CORS capabilities? It's already supported out of the box, you just gotta configure it. You can enable it globally like this:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
According to How to deploy Spring Boot application, I have to make main application to extend SpringBootServletInitializer. Once I added that, it works.
To solve CORS issue I used #CrossOrigin. And I did not implement my own CORS filter. Any way spring already have provided few addition solutions for CORS issue.
If you need only your filter you could use it in this way:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(yourFilter);
...
}

Rest Client with RestyGWT and custom headers

I would try to create an API Rest client for a code that I have in a GWT project.
In order to arrive to the server and obtain a response I need to attach some custom headers in my request.
I saw, there were some bugs some years ago when write headers in the request.
Actually, I have this code, and I don't know exactly where and when put my custom header in the request.
final Map<String, String> headers = new HashMap<String, String>();
headers.put("X-USER", "super_admin_key");
Resource resource = new Resource("http://localhost:9998/api/v1/", headers);
ServicesAPI service = GWT.create(ServicesAPI.class);
((RestServiceProxy)service).setResource(resource);
REST.withCallback(new MethodCallback<String>(){
#Override
public void onFailure(org.fusesource.restygwt.client.Method method, Throwable exception) {
domainsCombo.addItem("ERROR");
}
#Override
public void onSuccess(org.fusesource.restygwt.client.Method method, String response) {
domainsCombo.addItem("ok");
}
}).call(service).getServices();
Add headers to the resource object creation is one of the options, but it doesn't work.
Any sugestion?
Thanks.

GWT RPC possible in window closing handler?

I'm listening for a window close event:
closeHandlerReg = Window.addCloseHandler(new CloseHandler<Window>() {
#Override
public void onClose(CloseEvent<Window> event) {
// ...
}
});
The documentation says that no UI can be shown in that callback. What about GWT RPC calls? I'm trying to make one, but it isn't showing up on the server (either in breakpoints or log statements).
Problem is that GWT RPC is asynchronous and the calls to RPC services return immediately. In this case the window is closed before the browser has a chance to send the underlying XMLHTTPRequest.
If it's absolutely necessary you should be able to hand-craft calling some sort of servlet (not GWT RPC) with a "synchronous" XMLHTTPRequest. Have a look here for an example: http://weblogs.asp.net/bleroy/archive/2005/12/15/433278.aspx
But really you shouldn't be doing anything of this sort in the window.onunload or window.onbeforeunload (these are the underlying DOM events for CloseEvent and ClosingEvent for the Window. Perhaps there is a better way to do what you are trying to do.
The use case you have should be possible. When you make the RPC call in the closeHandler it should arrive at the server, because while it returns directly, it has started sending the data, and set a callback to wait for the result. However the callback will fail because the connection is lost because the window is closed. But that is no problem as you only want to notify the server. So the question might be what are you sending? and does it work at all, when you send it at some other point in the code, not in the closeHandler?
Old question, but still - maybe someone faces the same issue.
RPCs won't work in the closing handler as already discussed. This workaround worked for me:
In the onClose method, do something like:
Window.Location.replace(GWT.getModuleBaseURL() + "rpcCall?param1=" + param1 + "&param2=" + param2);
whereas "rpcCall" is the name of the rpc url you have set in your web.xml file. Of course, a random number of parameters may be passed within the URL.
Then, in your server-side implementation of your rpc interface, you can override the doGet method:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String param1 = URLDecoder.decode(request.getParameter("param1"), "UTF-8");
String param2 = URLDecoder.decode(request.getParameter("param2"), "UTF-8");
// do something
}
And another solution: Don't do an rpc call on window closing, but a regular http call that can then be handled by a custom servlet on the server side.
In your GWT module, do something like this:
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
sendWindowClosed(GWT.getModuleBaseURL() + "teardownservice");
}
});
private native void sendWindowClosed(String url)
/*-{
var Http = new XMLHttpRequest();
Http.open("GET", url);
Http.send();
}-*/;
}
In the server-side servlet, you can then handle this call:
public class TearDownServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.... whatever you want ....
}
}

Async REST calls with JAX-RS

I need to create a RESTful service which should support async calls in follwing way. When user calls some method he got the http '202' code and url to poll where he can see the status of his request. Currently I use JAX-RS and its annoations:
#Path("")
public interface MyService {
#POST
#Path("/myService/{name}")
#Consumes({APPLICATION_XML, APPLICATION_JSON})
void postSomething(#PathParam("name") String name, MyObject data);
}
Such mapping would expose MyService's postSomething() method by url /myService/{name} which serves POST requests, get 'name' parameter from url and 'data' from request body.
I want that after making this PUT request client get 202 http code and some callback url to poll to get the result once method will be executed.
So the question is:
1. How to make JAX-RS return 202 code?
2. How to pass callback url to the client?
Have the postSomething method return a Response object:
public Response postSomething(#PathParam("name") String name, MyObject data) {
return Response.status(Status.ACCEPTED).build();
}
If you want the callback URI as plain-text in the HTTP Body you could do something like this:
public Response postSomething(#PathParam("name") String name, MyObject data) {
return Response.status(Status.ACCEPTED).entity("http://google.com").build();
}
For generating URIs by resource classes, have a look at UriBuilder
Use #Context HttpServletResponse servletResponse to get direct control over the servlet's response mechanism.
#PUT
#Path("/myService/{name}")
#Consumes({APPLICATION_XML, APPLICATION_JSON})
void postSomething(#PathParam("name") String name, #Context HttpServletResponse response, MyObject data) {
// ...
response.setStatus(HttpServletResponse.SC_ACCEPTED);
response.setHeader("Location", myURL);
// ...
}