I am developing a rest api using Spring Boot. I have a class that extends UsernamePasswordAuthenticationFilter, where I override the attemptAuthentication method. In the process of authentication, Spring internally uses my CustomUserDetailsService that throws an exception in case no user is found. Spring internally handler that exception and throws InternalAuthenticationServiceException. The issue is, I am not able to catch that exception in my central place where I customize the response in case of errors. I am using #ControllerAdvice for that, but it seems Spring just ignore and always send default "Internal Server Error".
in order to capture a "failed authentication" just override the method unsuccessfulAuthentication in your filter
#Override
protected void unsuccessfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException failed)
throws IOException, ServletException {
//handle errors
}
Related
I have a legacy application that is in spring 4 with UI as JSP. Need move the presentation layer from spring to react app. When I call /login with parameters it gives me an HTML, How do I change my existing spring security logic so that it returns a json response.
Here is the code snippet
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().maximumSessions(1).and().invalidSessionUrl(URLConstants.LOGIN_URL);
http.csrf().disable();
http.anonymous().disable()
.authorizeRequests().antMatchers("/")
.access("hasRole('USER') or hasRole('ADMIN') or hasRole('DC MANAGER')")
.and().formLogin() .loginProcessingUrl(URLConstants.LOGIN_URL).usernameParameter("ssoId").passwordParameter("password").and()
.rememberMe().rememberMeParameter("remember-me").tokenRepository(tokenRepository) .tokenValiditySeconds(18400).and().exceptionHandling().accessDeniedPage("/Access_Denied");
}
Write a custom AuthenticationSuccessHandler that writes your JSON and plug it into your formLogin().
.formLogin().successHandler(yourSucessHandlerBean);
Your handler could roughly look like this:
#Component
public class Securityhandler implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
// write your JSON here, directly to the HttpServletResponse
}
}
I am required to perform some pre-task whenever few specific endpoints are hit in my spring based web app. I came across the interceptor component provided by the spring-security framework. I searched various forums but didn't find relevant answers for configuring and adding interceptor.
Consider a situation where I am required to set some key=value in a database by sending POST request in the database whenever the user hits following endpoints.
/endpoint1
/endpoint2
/endpoint3
/endpoint4
After completion of the pre-task user should be redirected to the origin endpoint.
How can this be achieved using an interceptor in the spring-security framework?
Spring Security is for security stuff related to Authentification and Authorization. You can trigger some action if somebody logged in, but if you just need to trigger action for each request than Spring Security is not a good place for that (according to business logic), better add just filter. Anyway answering to your question:
The best way is to add custom filter to Spring Security Filter Chain:
You have to overwrite:
#Configuration
public class CustomWebSecurityConfigurerAdapter
extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(
new CustomFilter(), BasicAuthenticationFilter.class);
}
}
and create your custom filter:
public class CustomFilter extends GenericFilterBean {
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//your logic here
chain.doFilter(request, response); //it's needed to pass your request father
}
}
Code taken from baeldung.com see for more information
I implemented Spring Security, and a custom Authentication Failure Handler, which I use the inherited method saveException which the Documentation says
Caches the AuthenticationException for use in view rendering.
Which would be perfect for me. This is what I want, I want to access the Exception saved by the Authentication Failure Handler in the frontEnd, i.e. I want to access in the bean that made the call to Spring Security.
My ControllerBean has this piece of code:
public void login() throws ServletException, IOException {
final ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
final RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher("/login");
dispatcher.forward((ServletRequest) context.getRequest(), (ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
}
Which it makes the call to my CustomAuthenticationProvider, and then if it throws an exception, my CustomAuthenticationFailureHandler catches it and has the following code:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception instanceof FirstExternalLoginException) {
setAllowSessionCreation(true);
saveException(request, exception);
getRedirectStrategy().sendRedirect(request, response, "/externalRegister.jsf");
}
}
So when this piece of code finishes, it comes back to the line:
FacesContext.getCurrentInstance().responseComplete();
Of the controller bean. How can I access the saved exception? I have been digging around the ExternalContext but have never found any AuthenticationException (or my custom exception, which extends the AuthenticationException)
I have 2 different types of login errors:
Incorrect user/pw
IP blocked for too many attempts
Right now Spring is forwarding the user to www.site.com/login?error in both cases. How can I customize login behavior so that it forwards the user to error1 or error2 depending on the case? This forward behavior doesn't seem to be explicitly declared anywhere and I couldn't find any documentation on this.
You have to implement your custom AuthenticationFailureHandler, see :
Spring security authenticate exceptions handling
If you just want to redirect the user to error1 or error2, your implementation can be just a simple redirect method :
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
super.onAuthenticationFailure(request, response, exception);
if(exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
response.sendRedirect("error1")
} else if (exception.getClass().isAssignableFrom(LockedException.class)) {
response.sendRedirect("error2")
}
}
}
I am using Spring Boot to deploy a .war file to an external Tomcat Server.
I am using Ajax/Restful authentication and I have the following class that handles authentication failure:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, exception.getMessage());
}
When I'm using the embedded Tomcat server, all goes well and upon authentication failure I get the following JSON:
{
"timestamp" : "2015-12-14T15:39:07.365+0000",
"status" : 401,
"error" : "Unauthorized",
"message" : "You have provided wrong credentials",
"path" : "/api/authentication"
}
However, when using an External Tomcat Server I get an HTML response which brings the usual Tomcat failed authentication page. Is there any way to bypass this for the External Server?
Solution was simply to not use sendError() and to provide a status code and to provide a custom exception serialization:
#Service
public class AjaxAuthenticationFailureHandler
extends SimpleUrlAuthenticationFailureHandler {
#Autowired
private ObjectMapper objectMapper;
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(objectMapper.writeValueAsString(exception));
response.getWriter().flush();
}
}