Spring Security Oauth - Custom format for OAuth2Exceptions - spring

The error format of spring security oauth conforms with the OAuth spec and looks like this.
{
"error":"insufficient_scope",
"error_description":"Insufficient scope for this resource",
"scope":"do.something"
}
Especially on a resource server I find it a bit strange to get a different error format for authentication issues. So I would like to change the way this exception is rendered.
The documentation says
Error handling in an Authorization Server uses standard Spring MVC
features, namely #ExceptionHandler methods
So I tried something like this to customize the format of the error:
#ControllerAdvice
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyErrorHandler {
#ExceptionHandler(value = {InsufficientScopeException.class})
ResponseEntity<MyErrorRepresentation> handle(RuntimeException ex, HttpServletRequest request) {
return errorResponse(HttpStatus.FORBIDDEN,
MyErrorRepresentation.builder()
.errorId("insufficient.scope")
.build(),
request);
}
}
But this does not work.
Looking at the code, all the error rendering seems to be done in DefaultWebResponseExceptionTranslator#handleOAuth2Exception. But implementing a custom WebResponseExceptionTranslator would not allow changing the format.
Any hints?

First of all,some knowledge for Spring Security OAuth2.
OAuth2 has two main parts
AuthorizationServer : /oauth/token, get token
ResourceServer : url resource priviledge management
Spring Security add filter to the filter chains of server container, so the exception of Spring Security will not reach #ControllerAdvice
Then, custom OAuth2Exceptions should consider for AuthorizationServer and ResourceServer.
This is configuration
#Configuration
#EnableAuthorizationServer
public class OAuthSecurityConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//for custom
endpoints.exceptionTranslator(new MyWebResponseExceptionTranslator());
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
// format message
resources.authenticationEntryPoint(new MyAuthenticationEntryPoint());
resources.accessDeniedHandler(new MyAccessDeniedHandler());
}
}
MyWebResponseExceptionTranslator is translate the exception to ourOAuthException and we custom ourOAuthException serializer by jackson, which way is same by default the OAuth2 use.
#JsonSerialize(using = OAuth2ExceptionJackson1Serializer.class)
public class OAuth2Exception extends RuntimeException {
other custom handle class stuff
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
/**
* #author qianggetaba
* #date 2019/6/21
*/
public class MyWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
#Override
public ResponseEntity<OAuth2Exception> translate(Exception exception) throws Exception {
if (exception instanceof OAuth2Exception) {
OAuth2Exception oAuth2Exception = (OAuth2Exception) exception;
return ResponseEntity
.status(oAuth2Exception.getHttpErrorCode())
.body(new CustomOauthException(oAuth2Exception.getMessage()));
}else if(exception instanceof AuthenticationException){
AuthenticationException authenticationException = (AuthenticationException) exception;
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(new CustomOauthException(authenticationException.getMessage()));
}
return ResponseEntity
.status(HttpStatus.OK)
.body(new CustomOauthException(exception.getMessage()));
}
}
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
/**
* #author qianggetaba
* #date 2019/6/21
*/
#JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {
public CustomOauthException(String msg) {
super(msg);
}
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
/**
* #author qianggetaba
* #date 2019/6/21
*/
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
public CustomOauthExceptionSerializer() {
super(CustomOauthException.class);
}
#Override
public void serialize(CustomOauthException value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("code4444", value.getHttpErrorCode());
jsonGenerator.writeBooleanField("status", false);
jsonGenerator.writeObjectField("data", null);
jsonGenerator.writeObjectField("errors", Arrays.asList(value.getOAuth2ErrorCode(),value.getMessage()));
if (value.getAdditionalInformation()!=null) {
for (Map.Entry<String, String> entry : value.getAdditionalInformation().entrySet()) {
String key = entry.getKey();
String add = entry.getValue();
jsonGenerator.writeStringField(key, add);
}
}
jsonGenerator.writeEndObject();
}
}
for custom ResourceServer exception
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* #author qianggetaba
* #date 2019/6/21
*/
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException)
throws ServletException {
Map map = new HashMap();
map.put("errorentry", "401");
map.put("message", authException.getMessage());
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(new Date().getTime()));
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), map);
} catch (Exception e) {
throw new ServletException();
}
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* #author qianggetaba
* #date 2019/6/21
*/
public class MyAccessDeniedHandler implements AccessDeniedHandler{
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
Map map = new HashMap();
map.put("errorauth", "400");
map.put("message", accessDeniedException.getMessage());
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(new Date().getTime()));
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), map);
} catch (Exception e) {
throw new ServletException();
}
}
}

I found a similar question with answers that really helped my solving this - Handle spring security authentication exceptions with #ExceptionHandler
But my question is specifically about spring-security-oauth2 - so I think it is still worth stating the answer specific to spring-security-oauth2. My solution was picked from different answers to the question mentioned above.
My samples work for spring-security-oauth2 2.0.13
So the solution for me to achieve a different custom error structure for oauth2 errors on resource server resources was to register a custom OAuth2AuthenticationEntryPoint and OAuth2AccessDeniedHandler that I register using a ResourceServerConfigurerAdapter. It is worth mentioning that this is only changing the format for ResourceServer endpoints - and not the AuthorizationServer endpoints like the TokenEndpoint.
class MyCustomOauthErrorConversionConfigurerAdapter extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer configurer) throws Exception {
configurer.authenticationEntryPoint(new MyCustomOauthErrorOAuth2AuthenticationEntryPoint());
configurer.accessDeniedHandler(new MyCustomOauthErrorOAuth2AccessDeniedHandler());
}
}
I could not reuse the functionality in OAuth2AuthenticationEntryPoint and OAuth2AccessDeniedHandler because the relevant methods translate the exception and flush it in the same method. So I needed to copy some code:
public class MyCustomOauthErrorOAuth2AccessDeniedHandler extends OAuth2AccessDeniedHandler {
private final MyCustomOauthErrorOAuth2SecurityExceptionHandler oAuth2SecurityExceptionHandler = new MyCustomOauthErrorOAuth2SecurityExceptionHandler();
/**
* Does exactly what OAuth2AccessDeniedHandler does only that the body is transformed to {#link MyCustomOauthError} before rendering the exception
*/
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, org.springframework.security.access.AccessDeniedException authException)
throws IOException, ServletException {
oAuth2SecurityExceptionHandler.handle(request, response, authException, this::enhanceResponse);
}
}
public class ExceptionMessageOAuth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {
private final MyCustomOauthErrorOAuth2SecurityExceptionHandler oAuth2SecurityExceptionHandler = new MyCustomOauthErrorOAuth2SecurityExceptionHandler();
/**
* Does exactly what OAuth2AuthenticationEntryPoint does only that the body is transformed to {#link MyCustomOauthError} before rendering the exception
*/
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
oAuth2SecurityExceptionHandler.handle(request, response, authException, this::enhanceResponse);
}
}
#RequiredArgsConstructor
public class MyCustomOauthErrorOAuth2SecurityExceptionHandler {
private final WebResponseExceptionTranslator exceptionTranslator = new DefaultWebResponseExceptionTranslator();
private final OAuth2ExceptionRenderer exceptionRenderer = new DefaultOAuth2ExceptionRenderer();
private final HandlerExceptionResolver handlerExceptionResolver = new DefaultHandlerExceptionResolver();
/**
* This is basically what {#link org.springframework.security.oauth2.provider.error.AbstractOAuth2SecurityExceptionHandler#doHandle(HttpServletRequest, HttpServletResponse, Exception)} does.
*/
public void handle(HttpServletRequest request, HttpServletResponse response, RuntimeException authException,
BiFunction<ResponseEntity<OAuth2Exception>, Exception, ResponseEntity<OAuth2Exception>> oauthExceptionEnhancer)
throws IOException, ServletException {
try {
ResponseEntity<OAuth2Exception> defaultErrorResponse = exceptionTranslator.translate(authException);
defaultErrorResponse = oauthExceptionEnhancer.apply(defaultErrorResponse, authException);
//this is the actual translation of the error
final MyCustomOauthError customErrorPayload =
MyCustomOauthError.builder()
.errorId(defaultErrorResponse.getBody().getOAuth2ErrorCode())
.message(defaultErrorResponse.getBody().getMessage())
.details(defaultErrorResponse.getBody().getAdditionalInformation() == null ? emptyMap() : defaultErrorResponse.getBody().getAdditionalInformation())
.build();
final ResponseEntity<MyCustomOauthError> responseEntity = new ResponseEntity<>(customErrorPayload, defaultErrorResponse.getHeaders(), defaultErrorResponse.getStatusCode());
exceptionRenderer.handleHttpEntityResponse(responseEntity, new ServletWebRequest(request, response));
response.flushBuffer();
} catch (ServletException e) {
// Re-use some of the default Spring dispatcher behaviour - the exception came from the filter chain and
// not from an MVC handler so it won't be caught by the dispatcher (even if there is one)
if (handlerExceptionResolver.resolveException(request, response, this, e) == null) {
throw e;
}
} catch (IOException | RuntimeException e) {
throw e;
} catch (Exception e) {
// Wrap other Exceptions. These are not expected to happen
throw new RuntimeException(e);
}
}
}

Spring Boot version: 2.2.5
You really don't have to write that much code. All you need to do create a custom AuthenticationEntryPoint by extending OAuth2AuthenticationEntryPoint, override enhanceResponse method of it and register it via Resource Server configuration.
First part:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer config) {
config.authenticationEntryPoint(new CustomOauth2AuthenticationEntryPoint());
}
}
Second part:
public class CustomOauth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {
#Override
protected ResponseEntity<String> enhanceResponse(ResponseEntity<?> response, Exception exception) {
return ResponseEntity.status(response.getStatusCode()).body("My custom response body.");
}
}
Keep in mind that according to spec 401 response must send WWW-Authenticate header. The enhanceResponse that we override sends that header. Take a look at the implementation and send that header if you return 401.

You have to setAuthenticationEntryPoint in TokenEndpointAuthenticationFilter Bean if you config by AuthorizationServer
#Bean
public TokenEndpointAuthenticationFilter tokenEndpointAuthenticationFilter() {
CustomOauth2AuthenticationEntryPoint entryPoint = new CustomOauth2AuthenticationEntryPoint();
TokenEndpointAuthenticationFilter filter = new TokenEndpointAuthenticationFilter(authenticationManager, requestFactory());
filter.setAuthenticationEntryPoint(entryPoint);
return filter;
}

Related

How to disable security filter for particular URL in spring boot [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Hi I added rest web service for my project..When I call to the rest service without login to my account, my rest services redirect to login page... How can I remove this feature for only web service URL.... Other URLs need to this security....
This is my security configuration
package lk.slsi.security.configuration;
import lk.slsi.security.services.AuthenticationService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
/**
* Created by ignotus on 1/26/2017.
*/
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final Logger logger = LogManager.getLogger(SecurityConfiguration.class);
#Autowired
private AuthenticationService authenticationService;
private RequestMatcher requestMatcher = new RequestMatcher() {
private AntPathRequestMatcher[] disableCsrfMatcher = {
new AntPathRequestMatcher("*/**")
};
#Override
public boolean matches(HttpServletRequest httpServletRequest) {
for (AntPathRequestMatcher match : disableCsrfMatcher) {
if (match.matches(httpServletRequest)) {
return false;
}
}
return true;
}
};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/restservice/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/view/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and().logout().invalidateHttpSession(true)
.permitAll().logoutSuccessUrl("/");
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
ShaPasswordEncoder encoder = new ShaPasswordEncoder(224);
try {
auth.userDetailsService(authenticationService).passwordEncoder(encoder);
} catch (Exception e) {
logger.error("Error Occurred while authentication. [{}]", e);
}
}
}
This is my rest service config class(JAX-RS)
#ApplicationPath("TransferPermit/SlsitoCustoms/")
public class restConfig extends Application{
}
This is my rest service controller
#Path("getby")
public class webServiceforCustoms {
#Autowired
private permitServices permitServices;
/**
* Creates a new instance of GenericResource
*/
public webServiceforCustoms() {
}
/**
* Retrieves representation of an instance of lk.slsi.GenericResource
*
* #param id
* #return an instance of java.lang.String
*/
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/date/{dtIssue}")
public List<CustomsPermit> getXmlbyDate(#PathParam("dtIssue") String dtIssue) {
List<CustomsPermit> permitRelease = permitServices.getPermitByDate(dtIssue);
return permitRelease;
}
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/id/{SNumber}")
public CustomsPermit getXmlbyEntryNo(#PathParam("SNumber") String SNumber) {
CustomsPermit permitRelease = permitServices.getPermitBySNumber(SNumber);
return permitRelease;
}
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/vatno/{importerVAT}")
public List<CustomsPermit> getXmlbyVATNo(#PathParam("importerVAT") String importerVAT) {
List<CustomsPermit> permitRelease = permitServices.getPermitByImporterVAT(importerVAT);
return permitRelease;
}
/**
* PUT method for updating or creating an instance of GenericResourcer
*
* #param content representation for the resource
*/
#PUT
#Consumes(MediaType.APPLICATION_XML)
public void putXml(String content) {
}
}
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/restservice/**");
}
Remove this from configure and add this
.antMatchers("/restservice/**"").permitAll()

spring boot RestController get HttpServletResponse content

I use spring boot build project, RestController return string data.
I want get response content in Filter.
But cant get, please help me.
controller:
#RestController
#RequestMapping(value = "/service/example")
public class ExampleController {
#RequestMapping(value = "/get/test", method = RequestMethod.POST)
public String message(#RequestBody String data) {
return "test";
}
#RequestMapping(value = "/get/test1", method = RequestMethod.POST)
public void message(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter writer = response.getWriter();
writer.write("dfsfd");
writer.flush();
}
}
filter:
#WebFilter(filterName="myFilter",urlPatterns="/service/*")
public class MyFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
MyHttpServletResponseWrapper responseWrapper = new MyHttpServletResponseWrapper(response);
filterChain.doFilter(request, responseWrapper);
String responseContent = responseWrapper.getContent();
System.out.println("response="+responseContent);
}
}
MyHttpServletResponseWrapper :
public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
private PrintWriter cachedWriter;
private CharArrayWriter bufferedWriter;
/**
* Constructs a response adaptor wrapping the given response.
*
* #param response The response to be wrapped
* #throws IllegalArgumentException if the response is null
*/
public MyHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
bufferedWriter = new CharArrayWriter();
cachedWriter = new PrintWriter(bufferedWriter);
}
#Override
public PrintWriter getWriter() throws IOException {
return cachedWriter;
}
/**
* 获取原始HTML
*
* #return
*/
public String getContent() {
byte[] bytes = bufferedWriter.toString().getBytes();
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
}
}
post to /service/example/get/test cant get content.
but post to /service/example/get/test1 can get content.
why?
My project has many rest like /service/example/get/test, I dont want to change each one.
how to get response content in filter, please help, Thanks!!!
I created one simple spring boot project, in this project you can control which url you want to filter:
Rest service class (3 services, we will filter 2 only)
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.GenericFilterBean;
#SpringBootApplication
#RestController
#RequestMapping(value = "/service/example")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#RequestMapping(value = "/get/test", method = RequestMethod.POST)
public String message(#RequestBody String data) {
return "test";
}
#RequestMapping(value = "/get/test1", method = RequestMethod.POST)
public void message(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter writer = response.getWriter();
writer.write("dfsfd");
writer.flush();
}
#RequestMapping(value = "/api", method = RequestMethod.POST)
public void messages(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter writer = response.getWriter();
writer.write("dfsfd");
writer.flush();
}
#Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(myFilter());
registration.addUrlPatterns("/service/example/get/*");
registration.setOrder(1);
return registration;
}
#Bean(name = "someFilter")
public GenericFilterBean myFilter() {
return new MyFilter();
}
}
MyFilter class:
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.web.filter.GenericFilterBean;
public class MyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("Filter called");
filterChain.doFilter(servletRequest, servletResponse);
}
}
try to call 3 services:
http://localhost:8080/service/example/get/test
http://localhost:8080/service/example/get/test1
http://localhost:8080/service/example/api
and check the printed log.
you can control the url patter using this line
registration.addUrlPatterns("/service/example/get/*");
I hope this sample help you, thanks

SpringBoot - Filters exception handler

I have a spring-boot application. I have a class that is ControllerAdvice to handle the exceptions thrown by the app.
I created a filter that I want to use it to validate a header for all my requests. When I throw the custom exception from that filter, it does not go through my exception handler, it uses the default Spring error control.
Is there any way to handle the errors from filters in my own way?
If you catch the exception in a Filter, then handle with HandlerExceptionResolver, the #ControllerAdvice will start to work
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#Component
public class HystrixRequestContextServletFilter extends OncePerRequestFilter {
private static final String API_KEY = "apiKey";
private final HandlerExceptionResolver handlerExceptionResolver;
#Autowired
public HystrixRequestContextServletFilter(HandlerExceptionResolver handlerExceptionResolver) {
this.handlerExceptionResolver = handlerExceptionResolver;
}
#Override
public void doFilterInternal(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain filterChain) {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
String apiKey = httpRequest.getHeader(API_KEY);
if (apiKey == null) {
throw new AuthenticationException("no apikey in request, path [" + httpRequest.getRequestURI() + "]");
}
ApiKeyHystrixRequestVariable.set(apiKey);
filterChain.doFilter(httpRequest, httpResponse);
} catch (Exception e) {
handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, e);
} finally {
context.shutdown();
}
}
#Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return request.getRequestURI().startsWith("/internal");
}
}
You can write a controller that extends BasicErrorController and write a method that has a #GetMapping annotation like this:
#RestController
public class FilterExceptionController extends BasicErrorController {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterExceptionController.class);
public FilterExceptionController(){
super(new DefaultErrorAttributes(),new ErrorProperties());
}
#GetMapping
private <T> ResponseResult<T> serviceExceptionHandler(HttpServletRequest request) {
Map<String,Object> body= getErrorAttributes(request,isIncludeStackTrace(request,MediaType.ALL));
String message = String.valueOf(body.get("message"));
body.forEach((k,v)->LOGGER.info("{} ==> {}",k,v));
return RestResultGenerator.genError(500,"Filter Error Occurred, Message: [ "+message+" ]");
}
#Override
public String getErrorPath() {
return "/error";
}
}
There is my test filter:
#WebFilter(filterName = "ipFilter",urlPatterns = "/*")
public class IpFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if(!Arrays.asList(new String[]{"127.0.0.1"}).contains(servletRequest.getRemoteAddr())){
throw new ServiceException(403,"ip forbid");
}
}
#Override
public void destroy() {
}
}
This is result(but only get exception message not code):
enter image description here

Unable to inject a session bean into a servlet on my bluemix app

I created a simple Java EE app in bluemix and deployed it. Then I created session bean and a servlet. I am unable to access the session bean method from Servlet.
Anybody has done this on bluemix?
here is my servlet code...
package nags.test.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nags.test.ejb.NagseSessionBean;
/**
* Servlet implementation class TestServlet
*/
#WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
NagseSessionBean nagsBean;
/**
* #see HttpServlet#HttpServlet()
*/
public TestServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doService(request, response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doService(request, response);
}
public void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("TestServlet doService Begin");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>Nags HTML from Servlet</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h1> This is Nags HTML5 PAge </h1>");
if (nagsBean == null){
System.out.println("TestServlet doService Unable to inject EJB");
}else{
System.out.println("TestServlet doService Able to inject EJB");
String helloString = nagsBean.sayHello("Nagarjun");
if (helloString == null){
out.println("<h1> No Response from Session Bean </h1>");
}else {
out.println("<h1> helloString </h1>");
}
}
out.println("</body>");
out.println("</html>");
System.out.println("TestServlet doService End");
//out.flush();
//out.close();
}
}
Your code has no errors, and trying on Bluemix works fine. I tried it using both a Stateless and a Stateful enterprise bean.
So probably there is an error with your Bean code.
To investigate the possible problem, retrieve the Bluemix logs using the "cf logs --recent" command and analyse the exception thrown.

RESTEASY -Spring Exception mapper for javax.ws.rs.NotFoundException is not getting Involed

Hi I am using Reasteasy 3 along spring 3.
I have defined multiple Exception mappers for my project, and most of them are getting invoked whenever concerned Exceptions are raised.
But I am facing problem with **“javax.ws.rs.NotFoundException” when this exception is raised its handler is not getting invoked.**
All Exception mappers including mapper for “NotFoundException” exception are defined/configured in same manner and they are getting invoked except mapper for NotFoundException.
Is there any different way to configure Exception mappers for JAX-RS exception ..please help I am stuck here .
code for Exception mappers
package com.xyz.exception;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class CCDBNotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
#Override
public Response toResponse(NotFoundException e) {
// Logs and code
}
}
other Exception mapper configured and defined in a Excatly similar way are getting Invoked ... see snap shot for working Exception mapper
package com.xyz.exception;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException;
#Provider
public class CCDBJAXBUnmarshalExceptionMapper implements ExceptionMapper<JAXBUnmarshalException> {
#Override
public Response toResponse(NotFoundException e) {
// Logs and code
}
}
package com.xyz.exception;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class CCDBApplicationExceptionMapper implements ExceptionMapper<CCDBApplicationException>{
#Override
public Response toResponse(NotFoundException e) {
// Logs and code
}
}
Spring Configuration for provider annotation
<!-- Auto Reegistry of RESTEasy providers -->
<context:component-scan base-package="com.xyz">
<context:include-filter type="annotation" expression="javax.ws.rs.ext.Provider"/>
</context:component-scan>
I tried everything but Exception mappers for any "javax.ws.rs.*" exceptions are not getting invokes although they are getting registered .
to overcome this problem i have used servlet filter ... i posting my code to help others whoever is facing same issues
Register below filter in your web.xml file.
filter code :
public class CCDBExceptionFilter implements Filter {
Logger logger = Logger.getLogger(CCDBExceptionFilter.class);
private static final String NOTFOUND_MESSAGE = "{\"ErrorResponse\":{\"errorCode\":1,\"errorMessage\":\"Invalid request, There is no service configured to handle provided request\"}}";
public void init(FilterConfig filterConfig) throws ServletException {
logger.debug("CCDBExceptionFilter got initiated" );
}
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain)throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
logger.debug("Request recived to process " + req.getPathInfo());
DummyResponse dummyResponse = new DummyResponse((HttpServletResponse)response);
filterChain.doFilter(request, dummyResponse);
logger.debug("Request handled for " + req.getPathInfo());
if(404 == dummyResponse.getErrorcode()){
logger.debug("Found 404 error code" );
res.setStatus(400);
PrintWriter out = response.getWriter();
out.println(NOTFOUND_MESSAGE);
out.close();
}
}
public void destroy() {
}
}
Dummy Response class
public class DummyResponse extends HttpServletResponseWrapper {
Logger logger = Logger.getLogger(DummyResponse.class);
private CharArrayWriter buffer; // This can be used as an Writer
int errorcode;
public int getErrorcode() {
return errorcode;
}
public void setErrorcode(int errorcode) {
this.errorcode = errorcode;
}
public DummyResponse(HttpServletResponse response) {
super(response);
buffer = new CharArrayWriter();
}
public String toString() {
return buffer.toString();
}
public PrintWriter getWriter() {
return new PrintWriter(buffer);
}
public void setStatus(int sc) {
if (404 == sc) {
setErrorcode(404);
super.setStatus(400);
} else {
super.setStatus(sc);
}
}
public void sendError(int sc, String msg) throws IOException {
if (404 == sc) {
setErrorcode(404);
super.setStatus(400);
} else {
super.setStatus(sc);
}
}
public void sendError(int sc) throws IOException {
if (404 == sc) {
setErrorcode(404);
super.setStatus(400);
} else {
super.setStatus(sc);
}
}
}

Resources