#WebFilter vs. <Filter> in web.xml - spring

I wonder how I can achieve a behaviour like using this #WebFilter annotation
#WebFilter(
urlPatterns = "/*",
filterName = "AuthenticationFilter",
description = "Filter all URLs"
,
initParams = {
#WebInitParam(name = "unprotectedUrls", value = "/,/login,/authentication,/notification,/sdr")})
public class AuthenticationFilter implements Filter {
...}
(which works well, meaning that I don't have to be logged in only for the listed paths but for all other paths I have to be)...
by using a <filter> element in web.xml.
Using this filter in web.xml:
<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>com.foo.bar.helper.AuthenticationFilter</filter-class>
<init-param>
<param-name>unprotectedUrls</param-name>
<param-value>/,/login,/authentication,/notification,/sdr</param-value>
</init-param>
</filter>
it is not recognized which means that I don't have to be logged in for all paths/URLs. No filtering takes place.
My intention is to make the init-params configurable so that I don't have to edit the code/class whenever a further URL shall be included or so.

You only have defined the filter, you have not mapped the filter. NExt to the filter element you also need a filter-mapping element to map the filter to urls, this is basically the replacement for the urlPatterns attribute of the #WebFilter
<filter-mapping>
<filter-name> AuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Related

open rest endpoint with spring security

I am a mobile developer, and a green horn with Spring Security, but any case it was working fine in my web app. But now I am stuck with an issue.
Lets suppose my app context is x and I want to allow everybody to use a rest service endpoint like
https://localhost:8443/x/12
This endpoint is defined in a Controller in this way:
#Secured("permitAll")
#RequestMapping("/{id}")
public ModelAndView foo(#PathVariable("id") int id, HttpServletRequest request) {
Pet existingPet = petService.getPet(id);
ModelAndView mav = new ModelAndView();
if (null != existingPet) {
mav.addObject("petAttribute", existingPet);
mav.setViewName("b-show-pet");
}else{
mav.setViewName("b-accessdenied");
}
return mav;
}
In my web.xml I have
<servlet-mapping>
<servlet-name>loc-app</servlet-name>
<url-pattern>/auth/**</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>loc-app</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<!-- Enable Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Now, IMO an URI like
https:/localhost:8443/x/15
should be intercepted by spring security, but the annotation #Secured("permitAll") above the service in the controller should be enable access. But it is not working. So, please enlighten me about what is wrong in my code or better, which is best way to do this. Regards,
Secured annotation is used for authorization purposes, for your needs this more suitable (if you wanna use xml config):
<http>
<intercept-url pattern="/yoururl" access="permitAll" />
</http>

Using DispatcherServlet for RestController

I'm currently trying to understand how the Dispatcher Servlet works with the Rest Controller ,but Postman returns 404 on everything I tried thus far.
The rest controller
#RestController
#RequestMapping(value = "/applications")
public class ApplicationController {
private static final Logger logger = LoggerFactory.getLogger(ApplicationController.class);
#Autowired
#Qualifier("ApplDAO")
private ApplDAO applDAO;
#Autowired
ApplicationService objServices;
#RequestMapping(value = "for_user\\{username:\\d+}", method = RequestMethod.GET)
public Application getApp(#PathVariable("username") String username){
Application app = applDAO.getByUsername(username);
return app;
}
}
My web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring4-servlet.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I tried using url-pattern /* but with no results.
This is the url I was trying to access http://localhost:8080/project/applications/for_user/username:acid
Is there something wrong with the URL I'm using or have I used the dispatcher wrong.
Here is the spring error
No mapping found for HTTP request with URI [/project/applications/for_user/username:acid
Answered by JB Nizet
Why do you use backslashes instead of slashes in your RequestMapping?
Why do you use the regex \d+ if you want to send username:acid (or
acid?) as user name. Just use value = "/for_user/{username}", and use
http://localhost:8080/project/applications/for_user/acid.

Spring MVC: calls from JSP not going to the controller

I am trying to pass parameters from JSP to the Spring MVC controller. However the controller doesn't get called. I have read many related posts regarding this and have tried various solutions provided but it's not working for me.
My web.xml looks like this:
<display-name>MyList</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mylist</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mylist</servlet-name>
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/welcome.html</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
My Controller:
#RequestMapping(path = "/subcategory/{id}", method = RequestMethod.GET)
public String findSubcategory(#PathVariable int id,Model model) {
List<Category> subCategoryList = this.myListDao.getSubCategories(id);
model.addAttribute("subcategories", subCategoryList);
return "searchCategory" ;
}
The relevant code from My JSP is as follows
<spring:url value="/subcategory/1" var="formUrl"/>
<c:forEach var="category" varStatus="status" items="${categories}">
<li>${category.description}</li>
</c:forEach>
It works when I have the url as /subcategory.html and have #RequestMapping("/subcategory") in my controller. When I use /subcategory/1 and change the corresponding request mapping, it does not work. I have tried various url patterns such as <url-pattern>/mylist/*</url-pattern><url-pattern>/MyList/*</url-pattern>etc. but nothing is working. I would really appreciate any help in solving this. Thanks a lot in advance.
Your current servlet mapping is overriding the default or root servlet mapping,
<servlet-mapping>
<servlet-name>mylist</servlet-name>
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/welcome.html</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
Your following mapping allows any request with *.html to be accepted hence your invocation to /subcategory.html worked without any issues.
<url-pattern>*.html</url-pattern>
Instead it should be changed to,
<servlet-mapping>
<servlet-name>mylist</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Some points to remember,
<url-pattern>/*</url-pattern>
This pattern is usually recommended with Filter to continue with filter chaining. Using this pattern otherwise will make you to take care of all responsibilities like serving static resources etc to be handled explicitly.
#RequestMapping(path = "/subcategory/{id}", method = RequestMethod.GET)
instead of path, you should use value, like this:
#RequestMapping(value = "/subcategory/{id}", method = RequestMethod.GET)
Your call cannot reach the controller because your request mapping "/subcategory/{id}" does not match any url-patterns defined with your dispatcher servlet. You can try replacing these lines:
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/welcome.html</url-pattern>
<url-pattern>*.html</url-pattern>
with
<url-pattern>/*</url-pattern>

Spring singleton #autowired service and shared state

I have a controller and a filter in which I inject a particular service.
In that service I have a Hashmap where I try to store certain information. The issue that I am running into is that although it appears that that a single instance of that service is created and injected into my controller and my filter it seems that there an two instances of the Map. I'm at a loss as to why. No matter how I tried to instantiate the map (or inject it) the behavior is still the same.
It turns out the issue is that two instances of the service are created and injected one in the controller and one in the filter. It's not clear to me why this is happening and how to resolve it.
Following is an extract of the code:
#Controller
public MyController {
#Autowired
private MyService myService;
someEndpoint() {
....
myService.putData(key, value);
.....
}
}
public class MyFilter extends GenericFilterBean {
#Autowired
private MyService myService;
public void doFilter(...) {
//this is where I have a problem.
// the reference myService.myMap seems to be pointing to a different instance
// than the service.myMap in the controller which doesn't make any sense to me
// the filter obviously intercepts all requests so I would expect that after that particular
// endpoint is accessed the data will be there for subsequent requests
myService.getData(..);
}
.....
}
#Service
public class MyService {
private Map <String,String> myMap = new HashMap <String,String> ();
public String getData(String key) {
return myMap.get(key);
}
public void putData(String key, String value){
myMap.put(key,value);
}
}
Here is an extract of the app-config.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<context:component-scan base-package="com.mycompany.myPackage"/>
<context:annotation-config />
.......
<security:http
........
........
<security:custom-filter ref="myFilter" position="FORM_LOGIN_FILTER" />
....
...........
<bean class="com.mycompany.filters.MyFilter" id="myFilter"/>
and the web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher Servlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Any help is greatly appreciated.
In your web.xml you set:
<servlet>
<servlet-name>Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
which creates one web application context initiated by your servlet.
Then you also have:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
which also creates a parent root web application context, in your case a duplicate one.
This scheme, properly used, favors the cases where you may have more servlets, each one defining its own isolated context but inherit bean definitions from a common root context (services, datasources etc). It also gives a good practice roadmap for creating layered contexts, i.e. prevent your service beans to have dependencies on your mvc layer.
Unless you have more than one configuration files, you should assign an empty value to the contextConfigLocation of your servlet configuration as :
<servlet>
<servlet-name>Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Be careful. Do not omit the parameter. Spring will infer some default configuration file name based on your servlet and will complain if it does not exist.
GenericFilterBean is not in an application context. I would expect java.lang.InstantiationException in the code above. You can get your bean via the filter's ServletContext. Any other instantiation trick will cause map duplication.
Are you sure that there is only one instance of MyService class created? The simplest way to check this is to provide default constructor implementation and print some text in it. Please check this and let me know, because I have some suspicions.
If this is true, and there are two instances of MyService class, there is possibility that when you put some data to map, you use instance A of MyService and when you get data from the map you use instance B of MyService... I will wait for your response to continue/stop this thinking.

How to configure the prime face FileUploadFilter using WebApplicationInitializer

I have been porting a working Primefaces JSF 2 app from spring XML configuration to the newer Spring 3.2 Java Configuration model.
So at the same time I decided to port the web.xml configuration as well. Things have gone pretty good but I seem to be stuck with one particular thing.
The root question I have is how to set init parms for a filter in the class implementing WebApplicationInitializer.
So I have the following section of web.xml
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>
org.primefaces.webapp.filter.FileUploadFilter
</filter-class>
<init-param>
<!-- we set the threshold size to be exactly 1 megabyte -->
<param-name>thresholdSize</param-name>
<param-value>1048576</param-value>
</init-param>
<init-param>
<!-- this is the location for the upload -->
<param-name>uploadDirectory</param-name>
<!-- we select the system tmp directory for this -->
<param-value>/tmp/myapp/uploads</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
In my ApplicationInitializer which implements WebApplicationInitializer, I defined a filter. But I cannot see how I would set the init parms for thresholdSize and uploadDirectory.
Is there a straightforward way to do this?
Thanks
Ok I figured it out. I created my own implementation of the FilterConfig interface and after I created the filter and passed it in through the init method on the filter.
For those interested here is the code
private void setupFileUploadFilter(ServletContext container) {
try {
// create the filter config for the file upload filter
FilterConfig filterConfig = setupFileUpLoadFilterConfig(container);
// create the filter
FileUploadFilter fileUploadFilter = new FileUploadFilter();
// initialize the file upload filter with the specified filter config
fileUploadFilter.init(filterConfig);
// register the filter to the main container
FilterRegistration.Dynamic fileUploadFilterReg = container.addFilter("PrimeFaces FileUpload Filter", fileUploadFilter);
// map it for all patterns
fileUploadFilterReg.addMappingForUrlPatterns(null, false, "/*");
// add a mapping to the faces Servlet
fileUploadFilterReg.addMappingForServletNames(null, false, "facesServlet");
} catch (ServletException e) {
e.printStackTrace();
}
}
/**
* create the initialization parameters for the file upload filter
*
* #param container the main container
* #return the created filter config
*/
private FilterConfig setupFileUpLoadFilterConfig(ServletContext container) {
CustomFilterConfig filterConfig = new CustomFilterConfig(container, "PrimeFaces FileUpload Filter");
// add the size parameter which is 1 Megabyte
filterConfig.addInitParameter("thresholdSize", "1048576");
// add the size parameter
filterConfig.addInitParameter("uploadDirectory", "/tmp/myapp/uploads");
return filterConfig;
}

Resources