Full authentication exception in spring boot - spring

Hello I have following Security config file.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
.authorizeRequests()
.antMatchers("/myservices/**/**").permitAll()
.antMatchers("/knowndata").permitAll()
.antMatchers("/guidata/**").permitAll()
.antMatchers("/textdata/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
http.csrf().disable();
}
and the following CORSFilter
#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", "x-auth-token,authorization, content-type, xsrf-token");
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(request, response);
}
}
}
Still I get Full authentication required exception when accessing the myservices.

Related

How to setup CORS on user login

I'm getting Not injecting HSTS header error but still have no idea after googling this message.
o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#30cc5ff
What I have done is below.
API request http://localhost:8083/api/v1/users/login
Web config
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL)
.permitAll();
http.csrf().disable().addFilterBefore(corsFilter, AuthorizationFilter.class)
.authorizeRequests()
.antMatchers("/api/v1/**").authenticated();
protected AuthenticationFilter getAuthenticationFilter() throws Exception {
final AuthenticationFilter filter = new AuthenticationFilter(authenticationManager());
filter.setFilterProcessesUrl("/api/v1/users/login");
return filter;
}
CorsFilter
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
// 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) servletRequest;
if (!request.getMethod().equals("OPTIONS")) {
filterChain.doFilter(request, response);
} else {
// do not continue with filter chain for options requests
}
}
#Override
public void destroy() {
}
}
HSTS stands for Http Strict Transport Security and is one of the default headers being included when using Spring Security.
If you have your own security configuration set up and are sure you can disable the HSTS security header, use:
http.headers().httpStrictTransportSecurity().disable();

Spring boot security x-auth-token not found in header

I have a spring boot application having REST services secured with spring security. Redis is used for storing sessions. I have deployed the application in Glassfish 4.1.2. When trying to login using basic auth, x-auth-token is not returned in response header. What could be the issue ?
Below are my configuration classes:
ApplicationSecurityConfig
#Configuration
#EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
private CustomAuthenticationDetailsSource source;
#Autowired
private HttpLogoutSuccessHandler logoutSuccessHandler;
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/crr/**").access("hasRole('CRR')")
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.httpBasic().authenticationDetailsSource(source).authenticationEntryPoint(authenticationEntryPoint);
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.csrf().disable();
}
}
CORSCustomFilter
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSCustomFilter implements Filter {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"X-Requested-With,content-type, Authorization");
chain.doFilter(servletRequest, servletResponse);
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
Note: When I deploy the application in Tomcat,x-auth-token is successfully generated in response header.
To retrieve it from response headers, Add x-auth-token to Access-Control-Allow-Credentials and Access-Control-Expose-Headers
response.setHeader("Access-Control-Expose-Headers", "x-auth-token");
response.setHeader("Access-Control-Allow-Credentials", "x-auth-token");
This worked for me.

CSRF Token not accepted (Spring)

I run into a problem when adding CSRF to my existing and working CORS configuration.
Everytime a POST, PUT or DELETE is triggered I get the error that the current token I have is not the right one (nvalid CSRF Token 'edff86dc-093a-4df9-8218-e5343506bdf9' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.).
But when I compare them it can't be caused by the tokens. Also if i trigger a GET after that (e.g. PUT) the token before is sent again and accepted.
So I assume there might be a problem with my security config but I don't see what I'm missing.
security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/*/**").permitAll()
.antMatchers("/logout", "/admin/**").authenticated();
http.csrf().ignoringAntMatchers("/guestbook/**");
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().successHandler(authenticationSuccessHandler);
http.logout().logoutSuccessHandler(logoutSuccessHandler);
http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
}
token filter:
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
System.out.println(token.getToken());
if (token != null) {
response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
response.setHeader(RESPONSE_TOKEN_NAME , token.getToken());
}
filterChain.doFilter(request, response);
}
}
and for instance the cors filter:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String origin = request.getHeader("Origin");
response.addHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Max-Age", "10");
response.addHeader("Access-Control-Expose-Headers", "X-CSRF-TOKEN");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
String headers = request.getHeader("Access-Control-Request-Headers");
if (!StringUtils.isEmpty(headers )) {
response.addHeader("Access-Control-Allow-Headers", headers );
}
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
} else{
chain.doFilter(request, response);
}
}
The problem not only occurs when I'm logged in. If i would not disable csrf on the guestbook path there would also be no POST possible.
I hope anybody can give me a hint.
Greetings
So I finally solved my problem. After a lot of seach and error I discovered the CsrfProtectionMatcher which can be used to enable CSRF on different paths.
Anyways this was very confusing to me, because I thought CSRF would be a always enabled on every request by default. So as soon as I applied the CsrfProtectionMatcher on my "/admin" path (allowing all possible methods, which is specified as null) it worked. requireCsrfProtectionMatcher on docs.spring.io , detailed article
Also it's now possible for me, to work with a more simple configuration but despite that my old one works too.
old one with CsrfProtectionMatcher :
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher csrfRequestMatcher = new RequestMatcher() {
private RegexRequestMatcher requestMatcher =
new RegexRequestMatcher("/admin", null);
public boolean matches(HttpServletRequest request) {
if(requestMatcher.matches(request))
return true;
return false;
}
};
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher);
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/*/**").permitAll()
.antMatchers("/login", "/**/**/**").permitAll()
.antMatchers("/logout", "/admin/**").authenticated();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().successHandler(authenticationSuccessHandler);
http.logout().logoutSuccessHandler(logoutSuccessHandler);
http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
}
more simple configuration:
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
.authorizeRequests()
.antMatchers("/**/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.permitAll();
http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
I have to admit I still don't know why CSRF has to be explicit enabled. If anyone has an answer to that please tell me.

spring securty SimpleUrlAuthenticationFailureHandler

#Component
public class TrackerAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler{
#Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if(exception.getClass().isAssignableFrom(DisabledException.class)){
super.setDefaultFailureUrl("/accountRecovery");
}
super.onAuthenticationFailure(request, response, exception);
}
}
SpringSecurity.java
#Autowired
private TrackerAuthFailureHandler trackerAuthFailureHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.failureHandler(trackerAuthFailureHandler);
}
Is there anything wrong with my code. After authentication failure, Page is not redirect to "/accountRecovery" url.

CORS error in Spring Oauth2

I'm using Spring security and Oauth2. But I'm new to Spring Oauth2, I Got the CORS error when front-end attends to access resource.
I'm using the below filter to allow other domains to access the resource:
#Component
#Order(Integer.MAX_VALUE)
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Credentials", "True");
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", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
I wrote the below code to allow public resource in my SecurityConfiguration.java.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/social/facebook/**","/register/**","/public/**").permitAll().and()
.authorizeRequests().antMatchers("/user/**").hasRole("USER").and()
.exceptionHandling()
.accessDeniedPage("/login.jsp?authorization_error=true")
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable();
}
For Oauth2, the below codes is for protecting user's resource in my OAuth2ServerConfig.java.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/user/**")
.and()
.authorizeRequests()
.antMatchers("/user/**").access("#oauth2.hasScope('read')")
.regexMatchers(HttpMethod.DELETE, "/oauth/users/([^/].*?)/tokens/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('write')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/([^/].*?)/users/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('read')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.isClient() and #oauth2.hasScope('read')");
}
When I open the index.html file in the browser, like following:(Sorry I don't have at least 10 reputation to post images, so I paste links here)
http://i.stack.imgur.com/yQKJM.png
it successfully get the public data, that means other domains are allowed to access "/public/**" data.
But it failed to get "/user/**" data (protected by Oauth2). It gives me below error says "Cross-Origin Request Blocked".
http://i.stack.imgur.com/XIVx1.png
When I move the front-end files to the same domain of the Spring server. It works fine to get both "public" and "user" data as below:
http://i.stack.imgur.com/Q2n7F.png
The front-end and Back-end should be separated. But the CORS is blocked to access projected data. Can anyone give me some suggestions? Thanks very much. I'm guessing the filter is not working on Oauth2? still spend a lot of time on looking for solutions.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
#Override
public void init(FilterConfig fc) throws ServletException {
}
#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", "PATCH,POST,GET,OPTIONS,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
#Override
public void destroy() {
}
}
I added the headers to the endpoints
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.addInterceptor(new HandlerInterceptorAdapter() {
#Override
public boolean preHandle(HttpServletRequest hsr, HttpServletResponse rs, Object o) throws Exception {
rs.setHeader("Access-Control-Allow-Origin", "*");
rs.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
rs.setHeader("Access-Control-Max-Age", "3600");
rs.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
return true;
}
});
}
The OAuth filter was called first and throw an Exception which has been prevented from running your CORS filter.
you must add this annotation
#Order(Ordered.HIGHEST_PRECEDENCE)
to your CORS filter.

Resources