Ionic / Angular App http requests fail to connect to Spring REST API using an Android emulator / real Android device when targeting the host ip - spring

I am unable to perform any http requests from my Ionic App to my Spring API when I am targeting the actual host adress (192.168...). Using the localhost in my Chrome Browser works fine, aswell as using the Android emulator gateway (10.0.2.2) in my virtual device. However, as soon as i use my host ip, only the Chrome Browser is able to send requests. I also made sure that my real device is in the same network as my host and it actually is able to reach the Spring API through its Browser. Unfortunately, if I then try to send a http request in the App, I get a really vacuous error message:
{
"headers":{
"normalizedNames":{},
"lazyUpdate":null,
"headers":{}
},
"status":0,
"statusText":"Unknown Error",
"url":"http://hostip:8080/authentication",
"ok":false,
"name":"HttpErrorResponse",
"message":"Http failure response for http://hostip:8080/authentication: 0 Unknown Error",
"error":{
"isTrusted":true
}
}
This is what my login method looks like:
login(email: string, password: string) {
const httpOptions = {
headers: new HttpHeaders({
'Authorization': 'Basic ' + base64string
}),
observe: 'response' as 'body',
withCredentials: true
};
return this.http.get(
'http://hostip:8080/authentication', httpOptions
);
}
At any other point in my App I am just calling the http.get method with the url and withCredentials: true as an argument.
I also made sure that these lines are included in my config.xml:
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
I also added a CORS Filter to my Spring API since I am sending an authorization header and want to set
Access-Control-Allow-Origin: * but combining these two things is forbidden by CORS-policy which is why my filter takes the request´s origin and returns it in the Access-Control-Allow-Origin-Header. Therefore every origin is allowed without using the wildcard *.
#Component
public class SimpleCORSFilter implements Filter {
public SimpleCORSFilter() {}
#Override
public void init(FilterConfig filterConfig) {}
#Override
public void destroy() {}
#Order(Ordered.HIGHEST_PRECEDENCE)
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
System.out.println("Origin: " + request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
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", "X-Requested-With, Authorization, Origin, Content-Type, Version");
response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, Authorization, Origin, Content-Type");
chain.doFilter(req, res);
}
}
My Spring Security Config is as simple as this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers(HttpMethod.GET).permitAll()
.antMatchers("/logout").permitAll()
.anyRequest().hasAnyRole("USER")
.and()
.httpBasic()
.and()
.logout();
}
}
I really appreciate all the help i can get and I am looking forward for your answers.

Android changed its http architecture from version 9.
to make it working on Android go to your project root folder.
yourAppFolder > resources > android > xml >
network_security_config.xml
Change your network security config to blow code.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>

Related

Spring boot app return Access to XMLHttpRequest at "myURL" has been blocked by CORS policy

i'm stuck with this issue: i use a spring boot app in backend and angular app for the front, the issue is when i call a specific rest url in the backend that uses a jar dependency that i have added to the backend as maven system scope dependency i get a cors error. All other backend urls are working fine
here is how i included the jar dependency for the backend:
<dependency>
<groupId>com.ex</groupId>
<artifactId>lib</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/Utils.jar</systemPath>
</dependency>
note also that i'm using a Zuul dispatcher between the front and the backend
and that i did this config in the backend
#Component
public class CorsFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token, Content-Range, Content-Disposition, Content-Description, GAuth");
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(request, response);
}
}
}
any help will be highly appreciated, thanks
Firstly, you need add #CrossOrigin annotation in your controller.
Than here is correct configuration from documentation:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
You can configure it your own way.
Secondly, if you are using SpringSecurity you need add .cors() to your configuration.
Example:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll()
.and().httpBasic();
}

How to add CORS to outh2/resource server in Spring Boot 2.x?

I have an oauth server and a resource server that I have created with JWT.
I also created an angular front end with 2 buttons:
The first button calls the auth server and gets the JWT token and adds it to the input box.
The second button calls the rest server with the JWT token as a bearer Authorisation http header.
Calling the 2 services from PostMan works perfectly but I cannot get the CORS setup correctly configured for the back end services.
Both buttons are giving me the below error:
Access to XMLHttpRequest at 'http://localhost:8085/oauth/token' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
I added all 3 of these projects to my public github repo.
I have tried to add CORS with several ways:
The config on the resource rest service is smaller so I will outline that here
I tried adding the default .cors() on the HttpSecurity as well as setting it manually in the corsConfigurationSource() method.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable()
.cors()
.and().authorizeRequests().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
//I tried manually configured the cors as well
/*http.csrf().disable()
.cors().configurationSource(corsConfigurationSource())
.and().authorizeRequests().anyRequest().authenticated();
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);*/
}
/* #Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
configuration.setAllowCredentials(true);
//the below three lines will add the relevant CORS response headers
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
*/
}
I also tried adding a servlet filter
#Component #Order(Ordered.HIGHEST_PRECEDENCE) public class
SimpleCorsFilter implements Filter {
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws
IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpServletRequest request = (HttpServletRequest) servletRequest;
response.addHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "content-type, x-requested-with, authorisation");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
#Override
public void destroy() {
} }
Just can't get it to work. Can anyone please give me some guidelines here?
Silly mistake on my end as in both my SimpleCorsFilter.java files I specified that authorisation header tags are allowed but it is not authorisation with an S but with a Z.
Changing both the files in my config server
response.setHeader("Access-Control-Allow-Headers", "content-type,
x-requested-with, Authorization");
Extends your class with withWebMvcConfigurer rather than WebSecurityConfigurerAdapter. The override the following method:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE").allowedHeaders("*");
}
It should add the origin. You can play with '*' and make many combination. I have given you idean now it is your turn to play with this API.

Spring boot 2 adding cache response headers without using Spring security

I am using Spring boot 2 and in application.properties file, I have specified the cache values as below :
spring.resources.cache.cachecontrol.max-age=0
spring.resources.cache.cachecontrol.no-cache=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.no-store=true
Except for max-age, none of the headers is visible in the chrome developer tools network tab.
In my application I am making a Get request and getting ResponseEntity<Long> as response back.
Is there something else needs to be done to add these cache-headers in the response ?
I used filter for setting HttpHeader. It can give you fine grained control over setting value and validate your request before passing to controller.
public class CORSFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers",
"X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
res.setHeader("Cache-Control","no-cache,no-store,must-revalidate,private,max-age=0");
res.setHeader("Pragma","no-cache");
res.setDateHeader("Expires",0);
if(!res.containsHeader("X-FRAME-OPTIONS"))
res.addHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}

Angular 2 CSRF cookie not set in POST response header in Spring Security

I have an Angular2 application that works with Spring. The backend (spring) runs on a other port so i configured the CORS as follow.
public GlobalCorsfilter() {
super();
}
#Override
public final void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
// without this header jquery.ajax calls returns 401 even after successful login and SSESSIONID being succesfully stored.
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, Origin, Content-Type, Version");
response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, Authorization, Origin, Content-Type");
final HttpServletRequest request = (HttpServletRequest) req;
if (request.getMethod() != "OPTIONS") {
chain.doFilter(req, res);
} else {
//
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
This code works fine i guess because i don't get any errors.
The problem occurs when i try to POST something, but it works fine with a GET method. I have CSRF enabled in my spring configuration and i want it to keep it that way. I get a '403' code when i try to POST. This is my CookieFilter class for configuring CSRF.
public class CsrfCookieGeneratorFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// Spring put the CSRF token in session attribute "_csrf"
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
// Send the cookie only if the token has changed
String actualToken = request.getHeader("X-CSRF-TOKEN");
if (actualToken == null || !actualToken.equals(csrfToken.getToken())) {
// Session cookie that will be used by AngularJS
CookieGenerator cookieGenerator = new CookieGenerator();
cookieGenerator.setCookieName("CSRF-TOKEN");
cookieGenerator.setCookieHttpOnly(false);
cookieGenerator.setCookieMaxAge(-1);
cookieGenerator.setCookiePath("/");
cookieGenerator.addCookie(response, csrfToken.getToken());
}
filterChain.doFilter(request, response);
}
And here is my Spring Configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new GlobalCorsfilter(), ChannelProcessingFilter.class)
.addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.........
I already added this line of code in Angular 2:
{provide: XSRFStrategy, useValue: new CookieXSRFStrategy('CSRF-TOKEN', 'X-CSRF-TOKEN')}
I get this message in the Response:
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
According to Angular2 documentation if you use http method it takes care of CSRF by default, so you do not need to add any provider unless you want to have a custom XSRFstrategy.
Angular's http has built-in support for the client-side half of this technique in its XSRFStrategy. The default CookieXSRFStrategy is turned on automatically. Before sending an HTTP request, the CookieXSRFStrategy looks for a cookie called XSRF-TOKEN and sets a header named X-XSRF-TOKEN with the value of that cookie.
https://angular.io/docs/ts/latest/guide/security.html#!#http
But as you can see in the link below you need to have a special configuration in spring in order to to allow JavaScript (i.e. AngularJS) to read it. In the documentation they named AngularJS but is the same for Angular 2+.
http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-cookie

Invalid CORS request in Spring

I am trying to enable certain IPs to access a particular method.
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/updateDetail")
.allowedOrigins("127.0.0.1", "10.96.33.45")
.allowedMethods("GET", "POST");
}
But when I am trying to call the same method I am getting invalid CORS request. Can anyone help me with this?
"Invalid CORS request" is returned by org.springframework.web.cors.DefaultCorsProcessor when
Spring is configured to use CORS and
browser sends "Origin" header with the request and it does not match with your server domain/port/scheme and
response does not have "Access-Control-Allow-Origin" header and
the request is not a preflight request.
If you don't need CORS, call cors().disable() in your implementation of WebSecurityConfigurerAdapter#configure(HttpSecurity http) (there might be other ways to do this, for example if you use Spring Boot).
Or you could add "Access-Control-Allow-Origin" header to your reponses using e.g. org.springframework.web.cors.CorsConfiguration or addCorsMappings (like you did, but maybe you should add more methods or url or IP doesn't match?).
This class is what are you looking for:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
#Override
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-Max-Age", "12000");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
response.setHeader("Access-Control-Expose-Headers", "*");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
This filter will resolve all your cors issues
I was debugging problem like this for few days. The actual problem was that I had typo in my service uri name /data vs. /daba etc. This cause SpringBoot to fail to retrieve CORS configuration (even when I had /** mapping) so CORS-preflight got status 403, which caused browser not to make the actual request at all - if browser would have fired the request, Spring would have returned "Resource not found" and then I would have noticed the typo much faster.
if you started your application at localhost, the browser formulates the origin as null, so application will not get the origin localhost:8080 or 127.0.0.1, it will get null
I think changing 127.0.0.1 with null will fix your problem
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/updateDetail")
.allowedOrigins("null", "10.96.33.45")
.allowedMethods("GET", "POST");
}

Resources