Spring Boot - External Tomcat Server Ajax Authentication Failure Message - ajax

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();
}
}

Related

How to handle OAuth2AuthenticationException: Client authentication failed: client_id in Spring Security

I'm implementing new Spring Authorization server (spring-security-oauth2-authorization-server version 1.0.0). I have created following two classes to handle exceptions:
public class RestExceptionTranslationFilter implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// Code to handle the exception
}
}
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
// Code to handle the exception
}
}
I have registered both of them like this:
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
...
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
authorizationServerConfigurer.tokenEndpoint(tokenEndpoint ->
((OAuth2TokenEndpointConfigurer)tokenEndpoint).errorResponseHandler(new RestExceptionTranslationFilter())
);
...
http.exceptionHandling(exceptions ->
exceptions.authenticationEntryPoint(new RestAuthenticationEntryPoint()));
}
Now I'm able to handle the OAuth2AuthenticationException exceptions and other exceptions and to return the response that my implementation requires. For example, this exception is handled correctly:
org.springframework.security.oauth2.core.OAuth2AuthenticationException: OAuth 2.0 Parameter: grant_type
at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter.throwError(OAuth2TokenEndpointFilter.java:260) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter.doFilterInternal(OAuth2TokenEndpointFilter.java:159) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
But, what's confusing me, and I cant solve it, why the same OAuth2AuthenticationException exception is not handled by this configuration in case when its thrown like this from ClientSecretAuthenticationProvider:
org.springframework.security.oauth2.core.OAuth2AuthenticationException: Client authentication failed: client_id
at org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider.throwInvalidClient(ClientSecretAuthenticationProvider.java:151) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider.authenticate(ClientSecretAuthenticationProvider.java:99) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
Is it possible to handle this exception and how as I would really like not to disclose the message "error": "invalid_client" to the possible attackers?

How to send custom request or response headers to APM from Keycloak Integration Spring Boot

I'm working on springboot project and we are using openId keycloak for authentication. I'm delaing with Multitenancy concept too. I want to sent custom header as request or either response and the same should be captured in APM as metadata. My current approach is as follows:
public class PreAuthFilter extends KeycloakPreAuthActionsFilter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
((HttpServletResponse) response).addHeader("X-Realm",realm);
super.doFilter(request, response, chain);
}
But with above code i'm getting multiple response metatdata in APM
http.response.headers.X-Realm.0
http.response.headers.X-Realm.1
http.response.headers.X-Realm.2
http.response.headers.X-Realm.3
My expectation was single realm in APM Metadata
http.response.headers.X-Realm = "value"
I think SimpleHttpFacade is getting intialized during resolving deployment multiple times hence adding the response.
Need Suggestion
Thanx.
It appears this could be that the issue is more likely related to your application context spring and filters.
Since it's spring could you try OncePerRequestFilter ?
import org.springframework.web.filter.OncePerRequestFilter;
#Named
public class ApmFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// do apm things
filterChain.doFilter(request, response);
}
#Override
public void destroy() {
}
}

AuthenticationFailureHandler HttpServletResponse.sendError url

I have developed single page web application using Spring Boot and Spring MVC. I am using Spring Security and JWT to authenticate users. I have written a custom AuthenticationFailureHandler which works but I want to know how I can control the url that a user gets redirect to when an exception is thrown. My AuthenticationFailureHandler looks like this:
public class JwtAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.sendError(HttpStatus.UNAUTHORIZED.value(), exception.getMessage());
}
}
When the JWT expires the application throws an AccountExpiredException, the AuthenticationFailureHandler.onAuthenticationFailure method gets executed and the user gets redirected to the login page:
http://localhost:8080/login?sessionExpired=true
This is all good, but I have no idea how the sessionExpired=true query string is generated and I want to have some control over it. In the past I have used ExceptionMappingAuthenticationFailureHandlers like this:
Map<String, String> mappings = new HashMap<>();
mappings.put(BadCredentialsException.class.getCanonicalName(), BAD_CREDENTIALS_EXCEPTION_URL);
mappings.put(AccountExpiredException.class.getCanonicalName(), ACCOUNT_EXPIRED_EXCEPTION_URL);
mappings.put(CredentialsExpiredException.class.getCanonicalName(), CREDENTIALS_EXPIRED_EXCEPTION_URL);
mappings.put(DisabledException.class.getCanonicalName(), ACCOUNT_INACTIVE_EXCEPTION_URL);
mappings.put(LockedException.class.getCanonicalName(), ACCOUNT_LOCKED_EXCEPTION_URL);
mappings.put(ValidationException.class.getCanonicalName(), VALIDATION_EXCEPTION_URL);
ExceptionMappingAuthenticationFailureHandler exceptionMappingAuthenticationFailureHandler = new ExceptionMappingAuthenticationFailureHandler();
exceptionMappingAuthenticationFailureHandler.setExceptionMappings(mappings);
So based on the various exceptions above I would like to be able to redirect to the following URLs:
http://localhost:8080/login?error
http://localhost:8080/login?accountexpired
http://localhost:8080/login?credentialsexpired
http://localhost:8080/login?accountlocked
http://localhost:8080/login?accountinactive
http://localhost:8080/login?validationerror
I'm not sure who to do this with response.sendError and I don't know how the sessionExpired=true query string is being generated. I have tried throwing different exceptions but the url never changes.
I have a couple of questions. Is it possible to control the URL when using HttpServletResponse.sendError and if not is it possible ot set the HttpStatus code when using ExceptionMappingAuthenticationFailureHandler.sendRedirect?
Why don't you try to use the response.sendRedirect:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
final HttpSession session = request.getSession(false);
if (session != null) {
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
}
//here the logic to get the error type of the exception
String errorMessage = ????
redirectStrategy.sendRedirect(request, response,
"http://localhost:8080/login?" + errorMessage);
}

Not able to handler InternalAuthenticationServiceException in Spring Security

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
}

Spring Security - Access Exception saved by Authentication Failure Handler

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)

Resources