Spring Security - ant matcher permit all not working - spring

I have a problem with antMatchers. This is not working as I expected.
I try to permit for All endpoint /tokens/**, but when this endpoint is called, my filters are called too(JwtTokenVerifier)
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/tokens/**").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors()
.and()
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), this.jwtProperties, objectMapper))
.addFilterAfter(new JwtTokenVerifier(this.jwtProperties), JwtUsernameAndPasswordAuthenticationFilter.class);
}
Every time when I try to access for example /tokens/refresh-access-token JwtTokenVerifier is called.
#PostMapping("/tokens/refresh-access-token")
#ResponseStatus(HttpStatus.OK)
public Map<String,String> refreshAccessToken(#RequestBody String refreshToken)
Token verifier:
public class JwtTokenVerifier extends OncePerRequestFilter {
private final JwtProperties jwtProperties;
public JwtTokenVerifier(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

If possible, you could try and exclude the URL completely from Spring Security processing, by overriding the WebSecurity method. I don't know, though, if you want to completely ignore the FilterChain for that path.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/tokens/**");
}

Related

Spring security AuthenticationServiceException converted to InsufficientAuthenticationException

I've a problem with exception handling during authentication using Spring Security.
This is my AuthenticationProvider where on every exception an AuthenticationServiceException is thrown.
#Component
public class MyAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
// ...
} catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage(), e);
}
}
}
Below my custom AuthenticationProvider.
#Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
log.debug(e.toString());
}
}
This is the security config
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint);
}
}
Everything is triggered as expected. The problem is that in the AuthenticationProvider the AuthenticationException is an instance of InsufficientAuthenticationException and not AuthenticationServiceException as thrown by the AuthenticationProvider.
What I want instead in MyAuthenticationEntryPoint is the exception thrown with the cause set, which is a custom exception.
How can I solve this?
Why Spring replace an AuthenticationServiceException with an InsufficientAuthenticationException?
Thanks in advance.
SOLUTION
I found the solution! The problem is in SecurityConfig class. .authenticationEntryPoint(authenticationEntryPoint) must be under .httpBasic() and not set globally.
The right configuration is the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf().disable();
}

spring security oauth2 manipulate request url before redirect

I have a Vaadin application that is secured using spring security OAuth2. This works fine except for the occasional PUSH or HEARTBEAT endpoint being used to request first and thus triggering the auth process and the user ends up on the wrong page (These endpoints should not be visited directly by the user).
A simple but unsecure fix is to permitAll() on these endpoints. However as this poses a threat I need to close this hole up.
To do this I would like to parse and potentially edit the request url before redirecting to it at successfull auth. How would I go about doing this?
I would guess I need to add a filter somewhere in the chain to intercept the request and edit it. But I'm not sure where.
Here is my client:
#Configuration
#EnableOAuth2Sso
public class OAuthConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/vaadinServlet/PUSH/**").permitAll() //todo fix this hole
.antMatchers("/vaadinServlet/HEARTBEAT/**").permitAll() //todo fix this hole
.anyRequest().authenticated()
.and()
.logout()
.logoutSuccessUrl("/")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
#Override
public void configure(WebSecurity web) throws Exception
{
web.ignoring().antMatchers("/css/*").antMatchers("/VAADIN/**"); // Static resources are ignored
}
}
And the server:
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter
{
//jwt token stuff & my own client/auth providers. Should not be important.
...
}
server login form:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private RestAuthenticationProvider authenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/forgetPassword*").permitAll()
.antMatchers(HttpMethod.POST,"/user/resetPassword*").permitAll()
.antMatchers(HttpMethod.GET,"/user/changePassword*").permitAll()
.antMatchers("/user/updatePassword*", "/user/savePassword*", "/updatePassword*")
.hasAnyAuthority("CHANGE_PASSWORD_PRIVILEGE","ROLE_USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository());
}
private CsrfTokenRepository csrfTokenRepository()
{
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
Just add some implementation with your project
1: create Authentication Failure handler
#Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
System.out.print("here failure");
String s=request.getParameter("username");
setDefaultFailureUrl("/login?error&username="+s);
super.onAuthenticationFailure(request,response,exception);
}
}
2: Authentication Success Handler
#Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request , HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
/* custom Block
Do any thing here
*/
setDefaultTargetUrl("/home/");
super.onAuthenticationSuccess(request,response,authentication);
}
}
3: access request entry point
#Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
System.out.print("Unauthorized Access");
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
Implement the components as per your requirement.

How to disable the 'Authentification required popup' in Spring server configuration?

The route /gateways needs authentication.
When /gateways is accessed in the browser I am redirected to /login and the following form appears:
If /gateways is accessed from an angular2 app the following popup appears:
My spring security configuration is the following:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static String REALM="Authentication";
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("cris").password("123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("felix").password("felix123").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.formLogin()
.and()
.authorizeRequests()
.antMatchers("/user", "/vehicles", "/signin", "/isautheticated").permitAll().anyRequest()
.authenticated();
}
// Access-Control-Allow-Origin header to be present
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
/* To allow Pre-flight [OPTIONS] request from browser */
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
So how can the popup be disabled?
You should specify formLogin() instead of httpBasic() in your configuration. your configure method should look like this.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login");
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.formLogin()
.and()
.authorizeRequests()
.antMatchers("/user", "/vehicles", "/signin", "/isautheticated").permitAll().anyRequest()
.authenticated();
}
I think your request from angular2 is taking an invalid Authorization Basic header, it was handled by BasicAuthenticationFilter, and it threw a AuthenticationException, and start to entry point.
You can implement your own entry point that implements AuthenticationEntryPoint, and then inject to BasicFilter, the default entry point is BasicAuthenticationEntryPoint. As you can see, it will return a WWW-Authenticate response header.
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\"");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
authException.getMessage());
}

Spring LogoutSuccessHandler not invoked

I'm using spring-boot (1.3.5) + oauth2 (spring-cloud-starter-oauth2). I would like to test some LogoutSuccessHandler but I'm unable to invoke it.
This is my security configuration:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private LogoutHandler logoutHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/index.html", "/", "/resources/**", "/css/**").permitAll()
.anyRequest().authenticated();
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessHandler(logoutHandler);
//.invalidateHttpSession(true).deleteCookies("JSESSIONID", "SESSION");
}
}
This is my logoutHandler
#Component
public class LogoutHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
setDefaultTargetUrl("/");
super.handle(request, response, authentication);
}
}
When I debug the application and put the breakpoint to the logoutHandler it's never invoked. Am I missing something in this configuration?
Thanks
Update your configure method a little bit. You don't have to use AntPathRequestMatcher to match logout url.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/index.html", "/", "/resources/**", "/css/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutHandler)
//.deleteCookies("JSESSIONID", "JSESSIONID")
//.invalidateHttpSession(true)
.permitAll();
}

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.

Resources