Handle CORS in java server side - java

We have some protected resources which we need to CORS enable. These resources can be fetched/created by get and post.
To handle CORS we have put the handling for preflighted options request in server side. We have a special header to be sent from clients which enables it to be a preflighted request as per https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
On receiving the options request with an origin header we allow the origin using "Access-Control-Allow-Origin" and make Access-Control-Allow-Credentials", "true".
My question is there anything else i need to do or can be there cases where browser does not send the preflighted options request ?
Best Regards,
Saurav

Source: https://howtodoinjava.com/servlets/java-cors-filter-example/
public class CORSFilter implements Filter {
public CORSFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println("CORSFilter HTTP Request: " + request.getMethod());
// Authorize (allow) all domains to consume the content
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*");
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods","GET, OPTIONS, HEAD, PUT, POST");
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// For HTTP OPTIONS verb/method reply with ACCEPTED status code -- per CORS handshake
if (request.getMethod().equals("OPTIONS")) {
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
return;
}
// pass the request along the filter chain
chain.doFilter(request, servletResponse);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}

Related

Custom header param - Spring Boot

I'm having trouble trying to send a custom header param from my frontend to the controller.
I've set the endpoint to get the header param:
public ResponseEntity<DashboardBean> atualizarDadosDashboard(#RequestHeader(name = "idEmpresa") Long idEmpresa){
But when I try to consume this endpoint, I get failed response and the application doesn't log any error.
Here I have the browser console showing the failed request:
The second dashboard request is a OPTIONS type. The first is the GET request.
Here you can see the failed request headers with the custom header "idEmpresa":
I'm using Angular on the frontend. As you can see below, I'm adding the header to the request:
....
protected httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': this.token,
'idEmpresa': String(this.idEmpresa)
})
};
atualizarDashboard(): Observable<DashboardModel> {
return this.httpClient.get<DashboardModel>(this.baseUrl, this.httpOptions);
}
....
On my spring boot application there is nothing on the logs about this request!!
Problem solved.
I have a CORS Filter in my application. I had to add my custom header param to the
Access-Control-Allow-Headers
list to allow it. After that, the endpoint was consumed and worked as expected.
This is how my Filter is now:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
private final Log logger = LogFactory.getLog(this.getClass());
#Override
public void init(FilterConfig fc) throws ServletException {
logger.info("SimpleCORSFilter loaded");
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"x-requested-with, authorization, Content-Type, " +
"Authorization, credential, X-XSRF-TOKEN, idEmpresa");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
#Override
public void destroy() {
}
}

Jwt authentication with Angular and spring

I am building the authentication for my angular app using JWT token.
For any request to the rest api, I want that spring MVC check for the token in the header of the http request except when the http request is /login (to create a new token).
I am having an issue with my cors filter. It is sending a 401 status after the user is logged in successfully. The token sent in the "authorization" header is not taken into account.
angular service
getListe(): Promise<any> {
let header = new Headers();
header.append("authorization", localStorage.getItem("token"))
return this.http.get(URL_API_REST + 'liste', header)
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
Spring Cors Filter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request= (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
response.setHeader("Access-Control-Expose-Headers", "x-requested-with");
if(!request.getRequestURI().equals("/rest/rest/login")) {
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
response.setStatus(HttpServletResponse.SC_OK);
}
/*if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
*/
chain.doFilter(req, res);
}
Spring Authentication Filter
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request= (HttpServletRequest) servletRequest;
String token = request.getHeader("token");
if(token != null){
System.out.println("Présence d'un token");
}
else{
if(!request.getRequestURI().equals("/rest/rest/login"))
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
filterChain.doFilter(request, response);
}
Is there something am I missing ?
I don't have time to try to analyze code now, but I recommend you this project in GitHub that show a simple login system using JWT and Java. I've used it as an example to implement JWT in some of my systems and it worked perfectly. Hope it helps.
I had a hard time dealing with this issue, but I hope the answers will spare the time for some.
Actually, I figured out that my angular wasn't sending the header authorization in the request headers. To solve that issue, I used the RequestOptions in my service Angular.
service Angular
getListe(): Promise<any> {
let header = new Headers();
header.append("authorization", localStorage.getItem("token"))
let options = new RequestOptions({headers: header})
return this.http.get(URL_API_REST + 'liste', options)
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}

CORS: origin not found in access-control-allow-origin header (IE11)

i have a web page that do a POST to another page in other subdomain (subdomain1.domain.com -> subdomain2.domain.com) and i understand that i need configure cors to allow that situation. I did all the configs and it works in CHROME, FIREFOX AND IE11 ..
but there is an exception, only in IE11 ON MY CLIENT NETWORK the request doesnt work returning "origin not found in access-control-allow-origin header"
i find out that it occurs because in my client network the request does not return SECURITY header. The images below can explain it better:
IE11 OUTSIDE MY CLIENT NETWORK (In red the CORS return from server)
IE11 INSIDE MY CLIENT NETWORK (There is no security header return from server)
JAVA CODE SERVER CORS FILTER (There is no security header return from server)
public class CorsFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
resp.addHeader("Access-Control-Allow-Origin", "https://intranet2.culturainglesa.net");
resp.addHeader("Access-Control-Allow-Credentials", "true");
resp.addHeader("Access-Control-Allow-Methods", "GET,POST");
resp.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// Just ACCEPT and REPLY OK if OPTIONS
if (request.getMethod().equals("OPTIONS")) {
resp.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, servletResponse);
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
}
The problem was not in server side or CORS, but in IE11 that don't send credentials in this particular situation through AJAX:
INTERNET ZONE SITE -> INTRANET ZONE SITE
after change those two subdomains to be on TRUSTED ZONE, the problem was solved.
this is the question that help me to solve:
Access denied in IE 10 and 11 when ajax target is localhost

How to set http status code when responding to servlet client from Filter class-method in tomcat

I am writing a webservice with spring (this question is not about spring...) that implements a (hopefully) restful api. From my understanding all response should be in xml or json format. This is not really a big deal in most cases. But in one situation this seems not possible. I am using a facility from tomcat where a servlet is involved. I have to use a filter for some reason (and this reason is authentication). As I am new to servlets my understanding is eventually not so well, but to me it looks like this
My filter-class derives from javax.servlet.filter and I am writing my code within the doFilter method:
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { // ... }
And at some point i realize i have to respond to the client with http status code 401 and also want to give him a xml or json information about what happened. Now to me it looks as if i can either
1) Use the ServletResponse: This allows me to get an OutputStream and write my xml/json out. However I cannot set the http status code at all. The final response arriving at the client does contain some http headers.
2) Cast ServletResponse to HttpServletResponse: This allows me to set status code, but I don't seem to be able to set the response body, but let response body be handled from tomcat.
Either way seems incomplete. If i use ServletResponse to write to the OutputStream and then cast to HttpServletResponse and then call sendError(401) - hoping that whatever I wrote to OutputStream reaches the client - my response does not contain an http "status line". However http headers are present like "Server: Apache-Coyote/1.1"
any help welcome...
I've implemented a filter for authentication shortly. I've coded something similar to this:
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain)
{
HttpServletResponse response=(HttpServletResponse) resp;
boolean authenticated=false;
// perform authentication
if (authenticated)
{
chain.doFilter(req, response);
}
else
{
// don't continue the chain
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setHeader("WWW-Authenticate", "BASIC realm=\"Your realm\"");
response.setContentType("what you need");
PrintWriter writer=response.getWriter();
// don't set content length , don't close
}
}
This works for me:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
response.resetBuffer();
response.getOutputStream().write("Your content".getBytes());
HttpServletResponse hsr = (HttpServletResponse) response;
hsr.setStatus(401);
chain.doFilter(request, response);
}
Method HttpServletResponse::sendError is working for me to return from filter in SpringBoot 2.0 application:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (authenticated)
{
chain.doFilter(req, response);
}
else
{
((HttpServletResponse) response).sendError(HttpStatus.FORBIDDEN.value(), "Authorization shall be provided");
}
chain.doFilter(request, response);
}

Disable filter based on response

I have a client caching disabling filter which is mapped to all URLs.
Now I have to specifically disable the filter and allow caching when the response has anything other than html.
My current filter code is as follows:
public class NoCacheFilter implements Filter{
#Override
public void destroy() {}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Pragma", "no-cache");
httpResponse.setHeader("Cache-Control","no-cache,no-store,max-age=0,s-maxage=0,must-revalidate,proxy-revalidate,private,max-stale=0,post-check=0");
httpResponse.setDateHeader("Expires", 0L);
filterChain.doFilter(request, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {}
}
NOTE: Just for people who want to know why I am doing this - We have some paged which generate PDF. We take this PDF File and flush to the output stream. In IE8, the flush code doesn't work and logs show that the client closed the connetion immaturely...Cannot write to committed response.... When caching is enabled, PDF get written to client normally; without any issue. A separate requirement of the existing app is to not allow caching of any page on the client.
Did you try something as simple as this:
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
filterChain.doFilter(request, response);
if(response.getContentType().indexOf("text/html")>-1){
httpResponse.setHeader("Pragma", "no-cache");
httpResponse.setHeader("Cache-Control","no-cache,no-store,max-age=0,s-maxage=0,must-revalidate,proxy-revalidate,private,max-stale=0,post-check=0");
httpResponse.setDateHeader("Expires", 0L);
}
}
It don't really disable the filter, but at least the filter don't do anything when the response is not html.
Simple, just check in the doFilter() method whether the resource is cacheable or not. You can use the request URI, content-type or MIME type for that.

Categories

Resources