Spring Security annotation configuration regarding web.xml - spring

I'm using annotation based configuration and so far worked without a web.xml.
Now, according to documentation, I'll need to create a web.xml file and add these fields to it:
<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>
Can I configure this too with annotations?
Because If I make a web.xml and put only this, I'll get some other errors in runtime (like missing ContextLoaderListener etc etc..).

web.xml is part of the standard web-application packaging structure. This structure allows you to deploy your packaged war file on different servers such as Tomcat and Jetty.
You can read more about web.xml here: http://en.wikipedia.org/wiki/Deployment_descriptor
You can read about the standard directory structure here (this is for Tomcat, but most web-servers follow the same/similar structure):
http://tomcat.apache.org/tomcat-6.0-doc/appdev/deployment.html#Standard_Directory_Layout
You should already have a web.xml if your application is a web-application. If not, then you should not create a web.xml but find another way of hooking in Spring Security. Please let us know how your application is currently deployed.
Here is an example of a web.xml for Spring with Spring Security:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Spring Security Filter -->
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- The front controller of the Spring MVC Web application, responsible
for handling all application requests -->
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/web-application-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

For a web app you need a web.xml.
Regarding your error missing ContextLoaderListener, just add this to the web.xml
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

Related

Spring MVC make a rest controller without suffix in URL. My other controllers need to have suffix

I am running a Spring Project which is a combination of Spring MVC and Spring boot. Its configuration has set all the controllers must need to use .html in the URL suffix. Now I need to connect with a third party that shared a predefined URL that I have to make where URL does not have any suffixes.
My system URL https://mysystem.com/api/urls.html
I need to have https://mysystem.com/thrid_party_string
I am facing trouble configuring. Both at the same time. how can I manage?
Note: I cannot change existing controllers since they are already in us for many services.
My web.xml file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>test</display-name>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.test</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContextService.xml</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jExposeWebAppRoot</param-name>
<param-value>false</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>
<!-- filter -->
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- filter-mapping -->
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>*.asx</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>*.m3u8</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>cors</filter-name>
<filter-class>some.com.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Standard Action Servlet Configuration -->
<servlet>
<servlet-name>spring-mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>spring-mvc-dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/general_error.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/general_error_500.html</location>
</error-page>
</web-app>
By using spel(Spring expression language) you can set prefix for each controller
#Controller
#RequestMapping(path = "${apiPrefix}/users")
public class UserController {
}
Then, we simply specify the property value in our application.properties:
apiPrefix=/api
for more information you can see its
documentatihttps://www.baeldung.com/spring-boot-controllers-add-prefixon
Normally if you're the one providing the service, the caller needs to adjust to your URL patterns, not the other way around.
That said... it appears recent servlet specs can have more than one url-pattern. If the desired REST URLs don't have a common pattern of their own, like /api/xxx, you might have to bind the dispatcher to / and expect a lot of URLs that don't match the REST ones or *.html to just produce internal 404 errors

Configuring jersey SpringServlet as a servlet throws "IllegalStateException: No Such servlet"

I am attempting to configure the Jersey SpringServlet in the web.xml for my Jetty 8 server on Jersey 1.x and when I configure it as a <servlet> I get the exception thrown:
java.lang.IllegalStateException: No Such servlet: null
at org.eclipse.jetty.servlet.ServletHandler.updateMappings(ServletHandler.java:1320)
at org.eclipse.jetty.servlet.ServletHandler.setFilterMappings(ServletHandler.java:1414)
at org.eclipse.jetty.servlet.ServletHandler.addServletMapping(ServletHandler.java:896)
Sorry for the short stack trace, I can't copy/paste.
Here is my web.xml
<!?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd"
version="3.0">
<display-name>tpm</display-name>
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prod</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/tpm-ui-context.xml</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.providers</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.resources</param-name>
<param-value>false</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoadListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<filter>
<filter-name>securityCheckFilter</filter-name>
<filter-class>tpm.ui.filter.SecurityCheckFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>cacheControlFilter</filter-name>
<filter-class>tpm.core.rest.filter.ControlFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<!-- HERE'S THE PROBLEM, WHEN DECLARED AS A FILTER THE APPLICATION WORKS! -->
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>tpm.ui.resources</param-value>
</init-param>
<!-- WHEN DEFINED AS A FILTER THIS <init-param> IS UNCOMMENTED
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContexRegex</param-name>
<param-value>/|/.*(jsp|txt|html|woff|ttf)|/(images|js|swf|css|font|styles|api|(WEB-INF/jsp)|favicon.ico)/.*</param-value>
-->
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<filter-mapping>
<filter-name>securityCheckFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>cacheControlFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I need to get SpringServlet to work as a Servlet and not a Filter because I am adding another Servlet which is utilizing Comet to perform push services. If I keep SpringServlet as a Filter the request will never get to my new Servlet.
Note: Jetty 8 is EOL (End of Life), consider upgrading.
That stacktrace makes no sense.
java.lang.IllegalStateException: No Such servlet: null
at org.eclipse.jetty.servlet.ServletHandler.updateMappings(ServletHandler.java:1320)
at org.eclipse.jetty.servlet.ServletHandler.setFilterMappings(ServletHandler.java:1414)
at org.eclipse.jetty.servlet.ServletHandler.addServletMapping(ServletHandler.java:896)
It goes from addServletMapping -> setFilterMappings -> updateMappings
I can find no version of Jetty 8 that had that call path.
Which version of Jetty 8 are you using?
Even accounting for the fact that com.sun.jersey.spi.spring.container.servlet.SpringServlet implements all of the following interfaces ...
javax.servlet.Filter
javax.servlet.Servlet
javax.servlet.ServletConfig
If we make an assumption that jetty determines the type poorly, there is still no way that call stack would occur.
Went ahead and mocked up a quick test case with a class that implements all 3 of those interfaces and used it against Jetty 8.1.16.v20140903 distribution and it does not trigger that stacktrace.
Perhaps you need to enable full debug logging to see what was happening immediately before that IllegalStateException occurred. (its quite likely not the SpringServlet init that caused it)
If you have a larger (and more accurate) stacktrace, that might help too.

Spring mvc configuration to integrate with a custom SSO authentication

I'm failing to integrate an existing custom Single-sign-on service (for the authentication of my spring mvc application -aka. myApp-).
Once I map the spring DispatcherServlet to "/", myApp skips the authentication process against the SSO application, no matter if there's session or not.
Web.xml (Spring Configuration)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<!-- Spring MVC DispatcherServlet -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Here is the configuration that I need to integrate in myApp web.xml, to integrate the SSO authentication:
Web.xml (Custom SSO Configuration)
<filter>
<filter-name>SSOAuthenticationFilter</filter-name>
<filter-class>custom.sso.SSOAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SSOAuthenticationFilter</filter-name>
<url-pattern>/WEB-INF/views/*</url-pattern>
</filter-mapping>
<!-- Context Params -->
<context-param>
<param-name>myAppId</param-name>
<param-value>65asd5a4sd65asd65a4sd65asd4</param-value>
</context-param>
<context-param>
<param-name>loginPath</param-name>
<param-value>login.jsp</param-value>
</context-param>
<context-param>
<param-name>ssoAppPath</param-name>
<param-value>http://localhost:8080/SSO_AuthenticationApp</param-value>
</context-param>
<!-- SSO Login Servlet -->
<servlet>
<servlet-name>SSOloginServlet</servlet-name>
<servlet-class>custom.sso.SSOLoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SSOloginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<!-- SSO properties (myAppId, ssoAppPath, loginPath) -->
<listener>
<listener-class>custom.sso.SSOPropertiesRetriever</listener-class>
</listener>
How can I configurate spring to let the SSO servlet to do the authentication process?
I was thinking if there's a way of declaring the customSSO servlet as a bean in the spring dispatcher-servlet-config.xml?
Or maybe implementing it in a #Controller?
(My hands are tied about the sso, I'm forced to use it for the authentication, cause myApp will be just another in a family of applications login through this custom sso... I would prefer to use spring security instead).
Thanks.
EDITED:
I finally opted for a migration to Spring Boot, seems way more clear to configure a project that way.
For the filter you can use a SpringFilter and implement the logic in a bean:
<filter>
<filter-name>springFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>authenticationFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springFilter</filter-name>
<url-pattern>/some-url</url-pattern>
</filter-mapping>
For the servlet I guess you may have to change your mappings to something that looks like the following:
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>my.package.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Here I'm assuming that everything goes in the same WEB.xml file

Spring + Wicket + Tomcat: Program fails to start because of IllegalArgumentException

I've got a problem when im trying deploy my WAR in tomcat. The program is a Wicket + Spring application which uses a annotation-based approach, https://cwiki.apache.org/WICKET/spring.html#Spring-AnnotationbasedApproach, to load/create spring beans. Tomcat fails to load the application because of this error
SEVERE: Exception starting filter WicketFilter
java.lang.IllegalArgumentException: ListableBeanFactory must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:273)
at org.apache.wicket.spring.SpringWebApplicationFactory.createApplication(SpringWebApplicationFactory.java:160)
at org.apache.wicket.spring.SpringWebApplicationFactory.createApplication(SpringWebApplicationFactory.java:143)
at org.apache.wicket.protocol.http.WicketFilter.init(WicketFilter.java:708)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:273)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:254)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:372)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4584)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5262)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5257)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
This is driving me nuts and I've searched wicket + spring and stackoverflow forums for similar problems but cant find anything. Any help on this problem would be very much appreciated.
Heres my Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/TR/xmlschema-1/"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>GIT</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/classes/spring/git-spring-config.xml
</param-value>
</context-param>
<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>
<filter>
<filter-name>WicketFilter</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>WicketFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<session-config>
<!-- timeout in minutes -->
<session-timeout>30</session-timeout>
</session-config>
<!-- When app loads Tomcat will create a Listener object of this type,
the Listener will initialize the Spring framework. -->
<listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</listener>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
</web-app>
I've also got addComponentInstantiationListener(new SpringComponentInjector(this)); in my WebApp.class
It looks like you forgot to configure Spring ContextLoaderListener. Make sure it's configured in your web.xml.

RESTEasy Asynchronous HTTP with Spring MVC

Is there any handy way to use RESTEasy Asynchronous HTTP support (in my case on Tomcat 6) in conjunction with the Spring MVC framework. I've found useful articles on using RESTEasy with Spring, but none that cover asynchronous support, which appears to be a bit of a thorn at present, due to requring a different Servlet class depending on the container (Tomcat6CometDispatcherServlet for Tomcat, for example).
Thanks,
FB
I have created a sample app using Comet, Bayeux, Java, Maven and a Raphael JS frontend and wrote a blog post about it, you can use it as a base for your app, just wrapping the current service code in REST.
http://geeks.aretotally.in/thinking-in-reverse-not-taking-orders-from-yo
Hopefully it will help you.
For anybody interested, I ended up having to use the Tomcat6CometDispatcherServlet in preference to the Spring DispatcherServlet to get my application working.
I still have the Spring ContextLoaderListener in place to create the various beans within my Application Context, but have to use less than ideal means of accessing these from within my Controller classes, which are now JAX-RS annotated rather than Spring MVC annotated. (There are various articles a quick Google will uncover on accessing the Spring context programmatically.)
Here's a cleaned up version of my web.xml (nothing earth-shattering, but perhaps it will have some useful hints for somebody!):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>myapp</display-name>
<description>My App</description>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>myapp.root</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<filter>
<filter-name>TrustedIPFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>TrustedIPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>PollServlet</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.Tomcat6CometDispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PollServlet</servlet-name>
<url-pattern>/poll/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/jsp/uncaughtException.jsp</location>
</error-page>
</web-app>

Resources