I am using Java configuration and know I can add a custom filter like this:
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain");
filter.setServletContext(servletContext);
filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
servletContext.addFilter("corsFilter", CorsFilter.class).addMappingForUrlPatterns(null, false, "/*");
servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, true, "/*");
}
This works fine, but feels like I am hacking around the edges of Spring.
What I would like to do is add my CORS filter to the DelegationFilterProxy.
In my root config I added:
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public Filter CorsFilter() {
return new CorsFilter();
}
and removed the adding of the custom filter in onStartup. Now it does not work at all.
How do I add a bean to my filter chain and make sure it is called first?
You can add it same way as you are adding springSecurityFilteChain in your onStartUp() method like...
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
DelegatingFilterProxy filter1 = new DelegatingFilterProxy("springSecurityFilterChain");
filter1.setServletContext(servletContext);
filter1.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
DelegatingFilterProxy filter2 = new DelegatingFilterProxy("corsFilter");
servletContext.addFilter("springSecurityFilterChain", filter1).addMappingForUrlPatterns(null, true, "/*");
servletContext.addFilter("corsFilter",filter2).addMappingForUrlPatterns(null, false, "/*");
}
To simply globally enable the CORS filter using Java config, try this: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#javaconfig
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
Related
Several days ago I migrated from xml config to Java config and suddenly got that Spring security does not protecting any url, filters not working at all!
I implemented WebApplicationInitializer interface to configure Dispatcher servlet, and my config looks this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.test.project");
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher",
new DispatcherServlet(context));
servlet.setLoadOnStartup(1);
servlet.addMapping("/rest/*");
}
Security config looks like this:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public AutheProvider authProvider() {
return new AuthProvider();
}
#Bean
public AuthenticationFilter authenticationFilter() {
return new AuthenticationFilter();
}
#Bean
public UnauthorizedEntryPoint unauthorizedEntryPoint() {
return new UnauthorizedEntryPoint();
}
#Bean
#Override
public AuthenticationManager authenticationManager() {
ProviderManager providerManager = new ProviderManager(
Arrays.asList(authProvider()));
providerManager.setEraseCredentialsAfterAuthentication(false);
return providerManager;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint())
.and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/rest/**").authenticated();
}
}
What I have missed?
SecurityConfiguration class is located in com.test.project package.
After project starts I can access any URL, there is no authenticationobject in SecurityContext and filters are never called, neiter mine, nor Spring Security filters.
I have simple Spring MVC application where I want to hande 404 Not found exceptions in my Advice Controller class
Configuration:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class, SecurityConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new SessionListener());
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
encodingFilter.setInitParameter("encoding", "UTF-8");
encodingFilter.setInitParameter("forceEncoding", "true");
encodingFilter.addMappingForUrlPatterns(null, true, "/*");
}
}
Controller:
#Controller
#RequestMapping("/")
public class HomeController {
#RequestMapping(value = "/error/", method = RequestMethod.GET)
public String error(){return "error";}
}
ControllerAdvice:
#ControllerAdvice
public class AdviceController {
#ExceptionHandler(MyOwnException.class)
#ResponseStatus(value= HttpStatus.BAD_REQUEST)
public String checkoutException(CheckoutException e, HttpServletRequest httpServletRequest) {
return "error";
}
}
I can catch my own exceptions when I manually throw MyOwnException but I can't get how to catch NoHandlerFound exception. I need to send 404 error code and appropriate error.jsp page when there is no controller method to handle request
If your webapp is using web.xml it's very simple - just add the following (assuming usage of InternalResourceViewResolver with prefix pointing at your WEB-INF view folder and suffix .jsp). You can have multiple error-page elements of other error codes too.
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
If you are not using web.xml it's more complicated and you'll have to define and register your own ExceptionResolver. Take a look at this spring.io blog article for details on how to do this.
(Edit after comment)
If you want to catch the NoHandlerFound exception you first have to tell Spring to throw it via setting a flag in the DispatcherServlet directly. To do so, in your AppInitializer class add the DispatcherServlet definition on top of what you are currently doing to add the flag:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new SessionListener());
//BEGIN OF NEW CODE
WebApplicationContext context = getContext();
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
//we did all this to set the below flag
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",dispatcherServlet );
//END OF NEW CODE
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
encodingFilter.setInitParameter("encoding", "UTF-8");
encodingFilter.setInitParameter("forceEncoding", "true");
encodingFilter.addMappingForUrlPatterns(null, true, "/*");
}
Then you can catch the NoHandlerFound exception directly in your AdviceController:
#ControllerAdvice
public class AdviceController {
//..
#ExceptionHandler(NoHandlerFoundException.class)
public String dealWithNoHandlerFoundException(CheckoutException e, HttpServletRequest httpServletRequest) {
return "error";
}
}
I want to handle 404 page not found exception in my Spring MVC web app, I'm using SPRING 4.2.5.RELEASE, I had read several question regarding this topic but the similar questions are using a different spring java configuration.
I have a Global Exception Handler Controller class that have all my Exceptions, this class works fine but I can't handle a 404 page not found exception.
This is the approach that I take following a tutorial
1) I created a class named ResourceNotFoundException that extends from RuntimeException and I putted this annotation over the class definition #ResponseStatus(HttpStatus.NOT_FOUND)
like this:
#ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
2) I created this method in my exception's controller class
#ExceptionHandler(ResourceNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {
return "notFoundJSPPage";
}
But still when I put a URL that doesn't exist I get this error "No mapping found for HTTP request with URI"
The questions that I had read said that I need to enable to true an option for the Dispatcher but since my configuration it's different from the other questions and I don't have a Web.xml I couldn't apply that.
Here it's my Config.java
#EnableWebMvc
#Configuration
#ComponentScan({"config", "controllers"})
public class ConfigMVC extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
Here is my WebInitializer
public class WebInicializar implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigMVC.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
Here is my Global Exception Handler Controller
#ControllerAdvice
public class GlobalExceptionHandlerController {
#ExceptionHandler(value = NullPointerException.class)
public String handleNullPointerException(Exception e) {
System.out.println("A null pointer exception ocurred " + e);
return "nullpointerExceptionPage";
}
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleAllException(Exception e) {
System.out.println("A unknow Exception Ocurred: " + e);
return "unknowExceptionPage";
}
#ExceptionHandler(ResourceNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {
return "notFoundJSPPage";
}
}
And the class I created that extends Runtime Exception
#ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{
}
I solved the problem by putting this line in my onStartup method in the WebApplicationInitializer.class
this it's the line I add servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
this is how it looks the complete method with the new line I added
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigMVC.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
Then I created this controller method in my GlobalExceptionHandlerController.class
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handle(NoHandlerFoundException ex) {
return "my404Page";
}
and that solved my problem I deleted the handleResourceNotFoundException controller method in my GlobalExceptionHandlerController.class since it wasn't necessary and also I deleted the exception class ResourceNotFoundException.class that I created
You can also extend AbstractAnnotationConfigDispatcherServletInitializer and override this method:
#Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
OR this one:
#Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
And finally in your ControlerAdvice use this:
#ExceptionHandler(NoHandlerFoundException.class)
public String error404(Exception ex) {
return new ModelAndView("404");
}
Add following code in any controller and create a 404 page
#GetMapping("/*")
public String handle() {
return "404";
}
I found that the answer by zygimantus didnt work for some reason, so if you also have the same problem , then instead of declaring an "#ExceptionHandler", add one of these to a "#Configuration" class instead. I put mine in my WebMvcConfigurerAdapter
#Bean
public HandlerExceptionResolver handlerExceptionResolver(){
HandlerExceptionResolver myResolver = new HandlerExceptionResolver(){
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
//return your 404 page
ModelAndView mav = new ModelAndView("404page");
mav.addObject("error", exception);
return mav;
}
};
return myResolver;
}
But make sure you also follow the rest of zygimantus ie
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
I am trying to authenticate user by token, But when i try to auto wire one my services inside the AuthenticationTokenProcessingFilter i get null pointer exception. because autowired service is null , how can i fix this issue ?
My AuthenticationTokenProcessingFilter class
#ComponentScan(basePackages = {"com.marketplace"})
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
#Autowired
#Qualifier("myServices")
private MyServices service;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
#SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap();
if (parms.containsKey("token")) {
try {
String strToken = parms.get("token")[0]; // grab the first "token" parameter
User user = service.getUserByToken(strToken);
System.out.println("Token: " + strToken);
DateTime dt = new DateTime();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime createdDate = fmt.parseDateTime(strToken);
Minutes mins = Minutes.minutesBetween(createdDate, dt);
if (user != null && mins.getMinutes() <= 30) {
System.out.println("valid token found");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword());
token.setDetails(new WebAuthenticationDetails((HttpServletRequest) request));
Authentication authentication = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword(), authorities); //this.authenticationProvider.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}else{
System.out.println("invalid token");
}
} catch(Exception e) {
e.printStackTrace();
}
} else {
System.out.println("no token found");
}
// continue thru the filter chain
chain.doFilter(request, response);
}
}
I Tried adding follwing in my AppConfig
#Bean(name="myServices")
public MyServices stockService() {
return new MyServiceImpl();
}
My AppConfig Annotations are
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {
You cannot use dependency injection from a filter out of the box. Although you are using GenericFilterBean your Servlet Filter is not managed by spring. As noted by the javadocs
This generic filter base class has no dependency on the Spring
org.springframework.context.ApplicationContext concept. Filters
usually don't load their own context but rather access service beans
from the Spring root application context, accessible via the filter's
ServletContext (see
org.springframework.web.context.support.WebApplicationContextUtils).
In plain English we cannot expect spring to inject the service, but we can lazy set it on the first call.
E.g.
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private MyServices service;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(service==null){
ServletContext servletContext = request.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
service = webApplicationContext.getBean(MyServices.class);
}
your code ...
}
}
It's an old enough question, but I'll add my answer for those who like me google this issue.
You must inherit your filter from GenericFilterBean and mark it as a Spring #Component
#Component
public class MyFilter extends GenericFilterBean {
#Autowired
private MyComponent myComponent;
//implementation
}
And then register it in Spring context:
#Configuration
public class MyFilterConfigurerAdapter extends WebMvcConfigurerAdapter {
#Autowired
private MyFilter myFilter;
#Bean
public FilterRegistrationBean myFilterRegistrationBean() {
FilterRegistrationBean regBean = new FilterRegistrationBean();
regBean.setFilter(myFilter);
regBean.setOrder(1);
regBean.addUrlPatterns("/myFilteredURLPattern");
return regBean;
}
}
This properly autowires your components in the filter.
I just made it work by adding
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
I am unsure why we should do this even when i tried adding explicit qualifier. and now the code looks like
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
#SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap();
if (parms.containsKey("token")) {
If your filter class extends GenericFilterBean you can get a reference to a bean in your app context this way:
public void initFilterBean() throws ServletException {
#Override
public void initFilterBean() throws ServletException {
WebApplicationContext webApplicationContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
//reference to bean from app context
yourBeanToInject = webApplicationContext.getBean(yourBeanToInject.class);
//do something with your bean
propertyValue = yourBeanToInject.getValue("propertyName");
}
And here is less explicit way for those who doesn't like hardcoding bean names or need to inject more than one bean reference into the filter:
#Autowired
private YourBeanToInject yourBeanToInject;
#Override
public void initFilterBean() throws ServletException{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
//do something with your bean
propertyValue = yourBeanToInject.getValue("propertyName");
}
You can configure your bean filter and pass as a parameter whatever you need. I know out of Spring context where the filter it is, you cannot get the dependency injection that the auto-scan of spring does. But not 100% sure if thereĀ“s a fancy annotation that you can put in your filter to do some magic stuff
<filter>
<filter-name>YourFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>YourFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
and then inject bean in the spring.xml
<bean id="YourFilter" class="com.YourFilter">
<property name="param">
<value>values</value>
</property>
</bean>
I am late to the party but this solution worked for me.
Add a ContextLoaderListener in web.xml. applicationContext can have dependency beans.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
Then add in MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContext which will add the webapplicationcontext into the filter which will add all the dependencies.
#Component
public class MyFilter implements Filter {
#Autowired
#Qualifier("userSessionServiceImpl")
private UserSessionService userSessionServiceImpl;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain
chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) req;
if (userSessionServiceImpl == null) {
ServletContext context = httpRequest.getSession().getServletContext();
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, context);
}
.... (for brevity)
}
}
I am creating a REST-based web application with AngularJS as front end and REST-based backend (with Spring 4). I am following the code-based configuration approach found here: WebApplicationInitializer
When I run the project on the server, I get a null value in the line:
FilterRegistration.Dynamic filter = container.addFilter("prerender", seoFilter);
What am I missing? I am a bit new to creating web-apps from scratch using annotations.
Here is the class in question:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("classpath:MyContext.xml");
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/api/*");
com.github.greengerong.PreRenderSEOFilter seoFilter = new com.github.greengerong.PreRenderSEOFilter();
FilterRegistration.Dynamic filter = container.addFilter("prerender", seoFilter);
filter.setInitParameter("prerenderToken", "123456789123456789");
filter.addMappingForUrlPatterns(null , true, "/*");
ServletRegistration.Dynamic initSysConfiguration
= container.addServlet("initSysConfiguration", new InitSystemConfigurations());
initSysConfiguration.setLoadOnStartup(1);
initSysConfiguration.addMapping("/InitSystemConfigurations");
}
This line is give me null
com.github.greengerong.PreRenderSEOFilter seoFilter = new com.github.greengerong.PreRenderSEOFilter();
I tried this,but same result
FilterRegistration.Dynamic filter1 = container.addFilter("prerender", com.github.greengerong.PreRenderSEOFilter.class);
When the method addFilter returns null it means there is already a filter registered for that name.
Returns:
a FilterRegistration object that may be used to further configure the given filter, or null if this ServletContext already contains a complete FilterRegistration for a filter with the given filterName or if the same filter instance has already been registered with this or another ServletContext in the same container
Make sure that you don't have a web.ml which already registers this filter.
Another tip instead of implementing WebApplicationInitializer yourself extend the AbstractDispatcherServletInitializer and implement the needed methods.
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
super.onStartup(container);
com.github.greengerong.PreRenderSEOFilter seoFilter = new com.github.greengerong.PreRenderSEOFilter();
FilterRegistration.Dynamic filter = container.addFilter("prerender", seoFilter);
filter.setInitParameter("prerenderToken", "123456789123456789");
filter.addMappingForUrlPatterns(null , true, "/*");
ServletRegistration.Dynamic initSysConfiguration
= container.addServlet("initSysConfiguration", new InitSystemConfigurations());
initSysConfiguration.setLoadOnStartup(1);
initSysConfiguration.addMapping("/InitSystemConfigurations");
}
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("classpath:MyContext.xml");
return appContext;
}
protected String[] getServletMappings() {
return new String[] {"/api/*"};
}
}
I solved it by running maven command mvn clean, I dont know some thing was wrong somewhere and giving me strange behaviour. I m not sure what i learn from this problem :(
Thanks for your help.