I have integrated Spring Security with Spring MVC and seeing strange behaviour. Every method in the Controller is executed twice for the same request. I googled for it quite a bit but didn't help much. The closest I could find is this http://forum.springsource.org/archive/index.php/t-83158.html I tried the suggestions without any success.
Here is my web.xml :
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/security-app-context.xml
/WEB-INF/application-context.xml
</param-value>
</context-param>
Here is relevant part of applicationcontext.xml :
<context:component-scan base-package="com.*" />
<context:spring-configured/>
<mvc:annotation-driven />
<context:property-placeholder location="classpath:/conf/myConfig.properties" />
<mvc:resources mapping="/resources/**" location="/resources/" />
The servlet-context.xml only has mapping for the InternalResourceViewResolver
The security-context.xml is as follows :
<http pattern="/resources/**" security="none"/>
<http auto-config="false" create-session="stateless" entry-point-ref="loginUrlAuthenticationEntryPoint" >
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/j_spring_security_check" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/accessdenied" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/logout" access="ROLE_USER"/>
<custom-filter before="SECURITY_CONTEXT_FILTER" ref="cookieSecurityContextFilter" />
<custom-filter position="LOGOUT_FILTER" ref="logoutfilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
<custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="customExceptionFilter" />
</http>
<beans:bean id="logoutfilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg value="/"/>
<beans:constructor-arg ref="customLogouthandler"/>
</beans:bean>
And then further mapping for the filters.
Am I doing something wrong in the configuration that could lead to the controller being called twice. I have checked the logs and the beans are instantiated only once. Please help.
Thanks in advance.
Just in case someone stumbles on this post and solution posted here thinking it will fix the duplicate requests, please first check if it is your browser/rest client making the additional call.
I wasted many hours trying to configure app and servlet contexts "after seeing the first suggested solution", until I figured it was the rest client on certain browsers (Chrome) creating an additional request for "GET requests on image resources". Curl showed only one method execution.
However, I do agree that it is a good practice to separate controller specific beans and their required Spring beans into servlet-context and keep all common beans in app-context. This is especially important if you have multiple Spring dispatcher servlet- in your web.xml.
Elaborating the previous answer:
You can either define both component-scan and mvc in the same context file to keep it simple.
app-context.xml:
<context:component-scan base-package="..." />
<mvc:annotation-driven />
...
Or separate them as follows:
app-context.xml:
<context:component-scan base-package="....">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:exclude-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
<context:exclude-filter expression="org.springframework.web.bind.annotation.ExceptionHandler" type="annotation"/>
</context:component-scan>
...
servlet-context.xml:
<context:component-scan base-package="...">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
<context:include-filter expression="org.springframework.web.bind.annotation.ExceptionHandler" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven />
...
I would try moving <mvc:.. elements to servlet-context.xml, maybe having it on applicationContext.xml causes you to have duplicate dispatcher servlet (although beans are only created once)
Scan all components except #Controller on applicationContext.xml by using <context:exclude-filter... Likewise scan only #Controller on servlet-context.xml using <context:include-filter..
Related
I have a web application protected by spring security. However, there is one particular URL pattern that I do not want to apply any security to. I've tried a few different approaches, but none of them seem to be working. Whenever I attempt to go to that specific URL, I am forwarded to the spring_security_login page.
A piece of the web.xml:
<!-- NOT SECURE -->
<servlet>
<servlet-name>dontSecureServlet</servlet-name>
<servlet-class>org.com.gov.lol.DontSecure</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dontSecureServlet</servlet-name>
<url-pattern>/dontSecure</url-pattern>
</servlet-mapping>
<!-- SECURE -->
<servlet>
<servlet-name>secureServlet</servlet-name>
<servlet-class>org.com.gov.lol.Secure</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>secureServlet</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!-- SECURITY FILTER -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
A piece of the security-context.xml:
<!-- This did not work -->
<http pattern="/dontSecure" security="none" />
<http entry-point-ref="entryPoint" use-expressions="true">
<custom-filter ref="customFilter" position="PRE_AUTH_FILTER" />
<!-- I've also tried adding the following here (with no luck) -->
<intercept-url pattern="/dontSecure" filters="none" />
<intercept-url pattern="/secureMe" requires-channel="https" />
<intercept-url pattern="/secureUs" requires-channel="https" />
</http>
<!-- I have even tried adding a separate <http> block just for /dontSecure -->
<http>
<intercept-url pattern="/dontSecure" security="none" />
</http>
Again, with any combination of the above configuration, the url /dontSecure is still forwarded to the spring login page.
Any ideas as to what could be causing this?
Cheers.
UPDATE
From the server logs, it seems that the /dontSecure url is loading the dontSecureServlet. However, an error seems to be generated and I am being forwareded the 404 error page (which is configured as /404.htm, which must be what brings me back to the login page).
I've included some extra snippits from the web.xml that I didn't think were relevant at first.
Try to change your intercept-url in your configuration with this one:
<intercept-url pattern="/dontSecure/**" access="permitAll" />
not in a separate <http> tag
The problem might be caused by the fact that your custom filter is getting applied to all the paths. You have to find a way to register your custom filter only for certain paths (I could show you how to do this in Spring Boot, but you probably aren't using it).
Trying to set up basic authentication in a web-app using spring. I am patterning what I do off this example: http://howtodoinjava.com/2013/04/16/custom-userdetailsservice-example-for-spring-3-security/. I am using Spring 4.
The behavior is that my HttpRequestHandler runs, never challenging for password. LoginDao never runs.
spring config:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
<security:http-basic />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="loginDao" />
</security:authentication-manager>
<bean id="loginDao" class="weight.dao.LoginDao" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/wt.properties" />
</bean>
What's missing in this tutorial are the entries you have to add to your web.xml. These will load you security context and add the security filter chain to your whole app (which is the main strut of Spring Security):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/your-security-context-file.xml
classpath:/your-other-context-files.xml
...
</param-value>
</context-param>
<filter>
<display-name>Spring Security Filter</display-name>
<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>
I've been trying to implement a solution for multiple login pages. I currently have a unique LoginController, and all it does is to retrieve the login jsp when somebody request /app_name/login.htm. I want that to stay that way, but also add two more locations: /app_name/customers/login.htm and /app_name/employees/login.htm each one with an individual controller CustomerLoginController and EmployeeLoginController.
So my idea is that employees access through their URL and customer using theirs, but if someone try to access the old login.htm the controller redirects him/her to their respective login using an stored cookie and customer as default.
To me it sounds good, but when I tried to access /app_name/customers/login.htm or /app_name/employees/login.htm it just redirects me to login.htm when I'm not authenticated.
I really don't know why it's not resolving them. Any opinion, suggestion, guide, tutorial, example code or link would be helpful.
The project I'm working on has this configs
Web.xml
<!-- 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>
servlet-config.xml
<!-- Controllers Mapping -->
<context:component-scan base-package="com.company.project.controllers">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
security-context.xml
<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint" access-denied-page="/warning/accessDenied.htm" >
<sec:intercept-url pattern="/employees/login.htm" filters="none" />
<sec:intercept-url pattern="/customers/login.htm" filters="none" />
<sec:intercept-url pattern="/login**" filters="none" />
</sec:http>
<bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.htm" />
<property name="forceHttps" value="false" />
</bean>
<bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationFailureUrl" value="/login.htm?login_error=1"/>
<property name="defaultTargetUrl" value="/home.htm"/>
<property name="alwaysUseDefaultTargetUrl" value="true"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean>
PD: using Spring 2.5.4 and Spring Security 2.0.4 -_- I Know, but is a fairly sized project and it's been in production for a while
Multiple login pages can be done with 2 separate http declarations:
<http pattern="/customers/**" authentication-manager-ref="customerAuthenticationManager">
<form-login login-page="/customers/login" default-target-url="/customers" login-processing-url="/customers/j_spring_security_check"/>
<logout logout-url="/customers/logout"/>
...
</http>
<http pattern="/employees/**" authentication-manager-ref="employeeAuthenticationManager">
<form-login login-page="/employees/login" default-target-url="/employees" login-processing-url="/employees/j_spring_security_check"/>
<logout logout-url="/employees/logout"/>
...
</http>
I am using Spring MVC(for REST), Spring Security 3 and Apache Wicket (UI) on Google App Engine. Everything is working fine except I am having trouble in getting the Authentication on the Wicket Page through the SecurityContextHolder after login.
I have google'd this issue, but none seems to be working for me. I suspect this is something wrong with my web xml. Can anyone please help. Thanks.
I am using the tutorials for Spring Security on Google App Engine from http://blog.springsource.org/2010/08/02/spring-security-in-google-app-engine/
Here is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>MTP Portal</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/mtp-web-servlet.xml, /WEB-INF/mtp-web-security-context.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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mtp-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mtp-web</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>WicketApp</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>WicketApp</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here is my spring security config:
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security pre-post-annotations="enabled"/>
<http pattern="/images/**" security="none"/>
<http pattern="/css/**" security="none"/>
<http pattern="/js/**" security="none"/>
<http pattern="/api/**" security="none"/>
<http pattern="/favicon.ico" security="none"/>
<http pattern="/disabled" security="none"/>
<http use-expressions="true" entry-point-ref="gaeEntryPoint" auto-config="true">
<intercept-url pattern="/" access="permitAll"/>
<intercept-url pattern="/api/**" access="permitAll"/>
<intercept-url pattern="/admin/logout" access="permitAll"/>
<intercept-url pattern="/register" access="hasRole('NEW_USER')"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>
<custom-filter position="PRE_AUTH_FILTER" ref="gaeFilter"/>
</http>
<b:bean id="gaeEntryPoint"
class="com.peerbuccoss.apps.mtp.web.authentication.impl.GoogleAccountsAuthenticationEntryPoint"/>
<b:bean id="gaeFilter" class="com.peerbuccoss.apps.mtp.web.authentication.filter.GaeAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="failureHandler">
<b:bean class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<b:property name="exceptionMappings">
<b:map>
<b:entry key="org.springframework.security.authentication.DisabledException"
value="/disabled"/>
</b:map>
</b:property>
</b:bean>
</b:property>
</b:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="gaeAuthenticationProvider"/>
</authentication-manager>
<b:bean id="gaeAuthenticationProvider"
class="com.peerbuccoss.apps.mtp.web.authentication.provider.GoogleAccountsAuthenticationProvider"/>
I'm not sure what URL is failing to obtain the SecurityContext (perhaps you can provide an example URL), but the SecurityContext will not be populated for any URL that is mapped to security="none". This is because security="none" instructs Spring Security to ignore this URL entirely. If you need to access the SecurityContext on a URL that is allowed for every user, then you need to use permitAll.
PS: If this does not help you might provide an example URL that you are having trouble with getting the Authentication. You might also provide details on what you mean by "having trouble in getting the Authentication on the Wicket Page" (i.e. is it null, throwing an Exception, etc).
I all,
i have a spring application working with role based security. Application is working fine it's just i need to introduce some static HTML pages which will also be hosted in the same war. So if www.myapp.com/abc/work.jsp is my secure page then www.myapp.com/home.htm should show static html page. I have incorporated HTML files but issue is i am getting 404 on www.myapp.com/home.htm and www.myapp.com/abc/work.jsp works fine.
web.xml -
<display-name>guru</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-security-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>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/home.htm</welcome-file>
</welcome-file-list>
My app-security-config.xml
<http auto-config="false" disable-url-rewriting="false" access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationProcessingFilterEntryPoint">
<custom-filter position="FORM_LOGIN_FILTER" ref="authenticationProcessingFilter" />
<custom-filter position="LOGOUT_FILTER" ref="customLogoutFilter"/>
<access-denied-handler error-page="/login.jsp?login_error=true"/>
<intercept-url pattern="/login.htm" filters="none" />
<intercept-url pattern="/abc/def/**" access="ROLE_USER"/>
<intercept-url pattern="/**" access="ROLE_ANONYMOUS" />
<anonymous enabled='true'/>
<session-management session-authentication-strategy-ref="sas"/>
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
</http>
Hi you should provide a mapping for static contents inside your dispatcher servlet configuration, something like:
<mvc:resources mapping="/resources/**" location="/WEB-INF/" />
In this way, if your static home.htm content is located inside /WEB-INF/ folder you can reach it from the url /resources/home.htm.
This will avoid that spring intercept and redirect to a controller all paths starting with /resources reserving that path to static resources like images, css files, scripts and html static pages