A Spring Boot app uses Spring Security to protect elements of its API from unauthorized users. But the app has public url patterns that need to be callable from un-authenticated users, as long as those users are from certain apps. What specific changes need to be made to the code below so that the /some-test-service
end point can be successfully called from an un-authenticated user from a specific calling location?
I will know, for example, that the terminal commands are being run from the same localhost that runs the Spring Boot app. I will also know that the front end AngularJS/Node.js calling app is running on a specific port, like port 9000
.
Here is what happens when I type in the following POST
test from the CentOS terminal in the devbox that runs the Spring Boot app:
[user@localhost controllers]$ curl -i -X POST -H "Content-Type:application/json" -d '{ "wleadid" : "1" }' http://localhost:8001/some-test-service
HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=530A75F962CCFB95EEDF43051BC71573; Path=/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Apr 2016 09:11:09 GMT
{"timestamp":1459933869769,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/some-test-service"}
[user@localhost controllers]$
And here is the Spring Security config, in the complete UiApplication.java
that that is the main class of the Spring Boot app:
@SpringBootApplication
@Controller
@EnableJpaRepositories(basePackages = "demo", considerNestedRepositories = true)
public class UiApplication extends WebMvcConfigurerAdapter {
@Autowired
private Users users;
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private Users users;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
@SuppressWarnings("deprecation")
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(new MyAuthenticationSuccessHandler())
.and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/some-test-service").permitAll()
.antMatchers("/", "/url1", "/url2", "/url3*", "/url4*", "/url5*").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println("----- INSIDE new OncePerRequestFilter().doFilterInternal(...) ");
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
System.out.println("csrf.getToken() is: "+csrf.getToken());
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
System.out.println("repository.toString() is: "+repository.toString());
return repository;
}
}
@Repository
interface UserRepository extends CrudRepository<User, Long> {
User findByName(String name);
}
}