SessionManagementFilter never calls SessionAuthenticationStrategy - java

I'm quite stuck migrating our web application from Wicket 1.4 to Wicket 6.20.
I'm also moving Spring Security to version 3.2.8.RELEASE from previous (and old) version 2.0.4.
Here it is a copy of Spring security context configuration:
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant" >
<security:filter-chain request-matcher-ref="requestMatcher"
filters="
securityContextPersistenceFilter,
concurrentSessionFilter,sessionManagementFilter"
pattern="/**" />
</security:filter-chain-map>
</bean>
<beans:bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<beans:constructor-arg ref="securityContextRepository"></beans:constructor-arg>
</beans:bean>
<beans:bean id="sessionManagementFilter"
class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg ref="securityContextRepository"></beans:constructor-arg>
<beans:constructor-arg ref="sas"></beans:constructor-arg>
</beans:bean>
<beans:bean id="requestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" >
<beans:constructor-arg value="/**"></beans:constructor-arg>
</beans:bean>
<beans:bean id="concurrentSessionFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:constructor-arg ref="sessionRegistry" ></beans:constructor-arg>
<beans:constructor-arg value="/petrol/login" ></beans:constructor-arg>
</beans:bean>
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="true" />
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="petrolAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<beans:bean name='securityContextRepository'
class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<beans:property name='allowSessionCreation' value='true' />
</beans:bean>
<beans:bean id="petrolAuthenticationProvider"
class="it.loginet.petrol.infrastructure.security.PetrolAuthenticationProvider">
<beans:property name="utenteRepository" ref="utenteRepository" />
</beans:bean>
SessionManagementFilter should filter our Request, testing if concurrent logins are allowed for a user.
The problem is that when it comes to verify a successful Authentication, SecurityContextRepository already contains the SecurityContext, and it doesn't call "SessionAuthenticationStrategy.onAuthentication" method.
if (!securityContextRepository.containsContext(request)) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the session strategy
try {
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
} catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug("SessionAuthenticationStrategy rejected the authentication object", e);
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
.........
SaveToSessionResponseWrapper class save SPRING_SECURITY_KEY attribute on the HttpSession, the SessionManagementFilter already find this attribute on the HttpSession and actually skip the inner SessionAuthenticationStrategy validation.
What I'm doing wrong on the migration?

OK, I think I found solution to my problem..
SessionManagementFilter, as stated here (http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ftn.d5e3442), doesn't recognize form logins authentication as I was using it in my application.
Thus concurrency strategy inside this filter would be never called..
So I decided to extend ProviderManager class with a new SessionManagementProviderManager instance, overriding ProviderManager.authenticate() method to apply 1) initial authentication process using inner AuthenticationManager and 2)SessionAuthenticationStrategy.onAuthentication() on the resulting Authentication returned from point 1).
Maybe this answer can help someone else with same problems migrating Spring Security..

Related

Spring mvc mapping problems

I'm using spring mvc hibernate for a project.
Now i'm stuck on my mapping.
The normal url is:
localhost:8080/Carre2/......
Somepages have some parameters like
localhost:8080/Carre2/addproduct/edit/1
When i want to go to antoher page he request this:
localhost:8080/Carre2/addproduct/edit/home
I have no idea how to fix this mapping problem.
Someone can help?
Some code:
public class AddproductController {
private ProductService productService;
#Autowired(required = true)
#Qualifier(value = "productService")
public void setProductService(ProductService ps) {
this.productService = ps;
}
#RequestMapping(value = "/addproduct", method = RequestMethod.GET)
public String listProduct(Model model) {
model.addAttribute("product", new Product());
model.addAttribute("listProduct", this.productService.listProduct());
return "addproduct";
}
//For add and update person both
#RequestMapping(value = "/addproduct/add", method = RequestMethod.POST)
public String addProduct(#ModelAttribute("product") Product p) {
if (p.getId() == 0) {
//new person, add it
this.productService.addProduct(p);
} else {
//existing person, call update
this.productService.updateProduct(p);
}
return "redirect:/addproduct";
}
#RequestMapping("addproduct/update/{id}")
public String updateProduct(#PathVariable("id") int id, Model model) {
model.addAttribute("product", this.productService.getProductById(id));
model.addAttribute("listProduct", this.productService.listProduct());
return "productlist";
}
#RequestMapping("addproduct/edit/{id}")
public String editProduct(#PathVariable("id") int id, Model model) {
model.addAttribute("product", this.productService.getProductById(id));
model.addAttribute("listProduct", this.productService.listProduct());
return "addproduct";
}
Here my servlet-context.xml
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<resources mapping="/resources/**" location="/resources/carre/" cache-period="31556926"/>
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/carre" />
<beans:property name="username" value="root" />
<beans:property name="password" value="...." />
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="annotatedClasses">
<beans:list>
<beans:value>com.carre.model.Person</beans:value>
<beans:value>com.carre.model.Product</beans:value>
<beans:value>com.carre.model.Categorie</beans:value>
<beans:value>com.carre.model.Catalogus</beans:value>
<beans:value>com.carre.model.Voorstelling</beans:value>
</beans:list>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="catalogusDAO" class="com.carre.dao.CatalogusDAOImpl">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
<beans:bean id="CatalogusService" class="com.carre.service.CatalogusServiceImpl">
<beans:property name="catalogusDAO" ref="catalogusDAO"></beans:property>
</beans:bean>
<beans:bean id="personDAO" class="com.carre.dao.PersonDAOImpl">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
<beans:bean id="personService" class="com.carre.service.PersonServiceImpl">
<beans:property name="personDAO" ref="personDAO"></beans:property>
</beans:bean>
<beans:bean id="productDAO" class="com.carre.dao.ProductDAOImpl">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
<beans:bean id="productService" class="com.carre.service.ProductServiceImpl">
<beans:property name="productDAO" ref="productDAO"></beans:property>
</beans:bean>
<beans:bean id="categorieDAO" class="com.carre.dao.CategorieDAOImpl">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
<beans:bean id="CategorieService" class="com.carre.service.CategorieServiceImpl">
<beans:property name="categorieDAO" ref="categorieDAO"></beans:property>
</beans:bean>
<beans:bean id="voorstellingDAO" class="com.carre.dao.VoorstellingDAOImpl">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
<beans:bean id="VoorstellingService" class="com.carre.service.VoorstellingServiceImpl">
<beans:property name="voorstellingDAO" ref="voorstellingDAO"></beans:property>
</beans:bean>
<context:component-scan base-package="com.carre.controller" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>
Here is how i want to get to the url.
c:url value='addproduct/edit/${product.id}'
I would recommend to use c:url like as below to fix it:
c:url value="${pageContext.request.contextPath}/addproduct/edit/${product.id}"
Basically try to take ${pageContext.request.contextPath} for each c:url
It will converted into "localhost:8080/Carre2"
You just need to access it as follows,
c:url value='/addproduct/edit/${product.id}'
This will make the url to start from your context path.
Or better way could be to store the context path globally and use it in each url. You can refer to context path as follows,
c:url value="${pageContext.request.contextPath}/addproduct/edit/${product.id}"

Migrating from spring 3 to 4

I have a code snippet
<beans:bean id="accessDecisionManager"
class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:bean
class="org.springframework.security.access.vote.AuthenticatedVoter" />
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
</beans:list>
</beans:property>
</beans:bean>
I want to migrate this to spring 4
According to http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html#m3to4-deprecations-core-aadm
I know that if i have something like this:
<b:bean class="org.springframework.security.access.vote.UnanimousBased">
<b:property name="decisionVoters" ref="voters"/>
</b:bean>
I have to do :
<b:bean class="org.springframework.security.access.vote.UnanimousBased">
<b:constructor-arg ref="voters"/>
</b:bean>
But i don't know how to do it in my case.. please help
I would also appreciate if you could point out the signifacance of property name thank you.
Sorry pretty stupid of me. This seems to work perfect.
<beans:bean id="accessDecisionManager"
class="org.springframework.security.access.vote.AffirmativeBased">
<beans:constructor-arg>
<beans:list>
<beans:bean
class="org.springframework.security.access.vote.AuthenticatedVoter" />
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
</beans:list>
</beans:constructor-arg>
</beans:bean>

Spring MVC : Tying session attributes to each browser tab

I am working on Spring-MVC application in which I am setting and
getting some session attributes which I need in backend. The problem
is, Spring or the browser, someone out of the both is tying these
session attributes to different browsers rather than different tabs.
So if I open a new tab in the same browser, then it is updating the
session attribute for both tabs.
How can I remedy this problem? I tried using session to scope, request, etc. But nothing works. here is my controller and servlet-context.xml
Controller :
#Controller
#Scope("request")
public class PersonController {
#Secured("ROLE_USER")
#RequestMapping(value = "/loadsection/{id}")
public String loadNotePage(#PathVariable("id") Integer id, HttpSession session) {
// here i am setting the canvasid, which I would like to access in other methods
session.setAttribute("canvasid",id);
if (this.personService.returnCurrentOperationalMode()) {
session.setAttribute("canvasid",id);
return "redirect:/section/listing";
} else {
GroupCanvas mcanvas = this.groupCanvasService.getCanvasById(id);
this.personService.setCurrentCanvas(mcanvas.getMcanvasid());
return "redirect:/section/listing";
}
}
#Secured("ROLE_USER")
#RequestMapping(value = "/addbatchsections", method = RequestMethod.POST)
public #ResponseBody String addBatchSections(HttpSession session, #RequestBody Section[] sections) {
int canvasid = (Integer) session.getAttribute("canvasid");
try {
List<Section> sectionList = new ArrayList<>();
for (Section section : sections) {
sectionList.add(section);
}
this.sectionService.addBatchSections(sectionList,canvasid);
return "success";
} catch (Exception e) {
return "failure";
}
}
Servlet-Context.xml
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<resources mapping="/resources/" location="/resources/" />
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="org.postgresql.Driver" />
<beans:property name="url"
value="jdbc:postgresql://localhost:5432/Person2"/>
<beans:property name="username" value="postgres" />
<beans:property name="password" value="asayhk2787" />
<beans:property name="removeAbandoned" value="true"/>
<beans:property name="removeAbandonedTimeout" value="20"/>
<beans:property name="defaultAutoCommit" value="false"/>
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="annotatedClasses">
<beans:list>
<beans:value>com.journaldev.spring.model.Person</beans:value>
<beans:value>com.journaldev.spring.model.Notes</beans:value>
<beans:value>com.journaldev.spring.model.Canvas</beans:value>
<beans:value>com.journaldev.spring.model.Section</beans:value>
<beans:value>com.journaldev.spring.model.Attachment</beans:value>
<beans:value>com.journaldev.spring.model.GroupAccount</beans:value>
<beans:value>com.journaldev.spring.model.GroupMembers</beans:value>
<beans:value>com.journaldev.spring.model.GroupCanvas</beans:value>
<beans:value>com.journaldev.spring.model.GroupSection</beans:value>
<beans:value>com.journaldev.spring.model.GroupNotes</beans:value>
<beans:value>com.journaldev.spring.model.GroupAttachments</beans:value>
<beans:value>com.journaldev.spring.model.Token</beans:value>
<beans:value>com.journaldev.spring.model.WaitingMembers</beans:value>
<beans:value>com.journaldev.spring.model.NoteHistory</beans:value>
<beans:value>com.journaldev.spring.model.GroupNoteHistory</beans:value>
<beans:value>com.journaldev.spring.model.Feedback</beans:value>
</beans:list>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect
</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="connection.pool_size">200</beans:prop>
<beans:prop key="c3p0.max_size">200</beans:prop>
<beans:prop key="c3p0.timeout">1000</beans:prop>
<beans:prop key="hibernate.jdbc.batch_size">100</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/>
</beans:bean>
I hope my question was clear, if there is any doubt, please feel free to ask me. Thanks a lot. :-)
Take a look at Spring Session and its associated examples.
Browsers like Chrome on new tab or new window share the user session because use the same session cookies.
Check this or change your session approach.

Spring URL matching case-insensitive does not map when there are numbers in the url

I was trying to make my URL case-insensitive and got the following code from the net.
However now when my urls are having number it is giving me Status 400 error. It was working fine before this change. Url like localhost\toplevel\234\text\2342 are not recognized now. Can someone please help explaining why this is happening and what need to be changed to make those urls work.
public class CaseInsensitiveAnnotationHandlerMapping extends AntPathMatcher
protected boolean doMatch(String pattern,
String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
return super.doMatch(pattern.toLowerCase(),
path.toLowerCase(), fullMatch, uriTemplateVariables);
}
}
my Servlet-Context.xml
<beans:bean class="com.darproject.webUtils.CaseInsensitiveAnnotationHandlerMapping" />
<beans:bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<beans:bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<beans:bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="webBindingInitializer">
<beans:bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<beans:property name="conversionService" ref="conversion-service"></beans:property>
<beans:property name="validator">
<beans:bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<beans:property name="providerClass" value="org.hibernate.validator.HibernateValidator"></beans:property>
</beans:bean>
</beans:property>
</beans:bean>
</beans:property>
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="byteArrayConverter"/>
<beans:ref bean="jaxbConverter"/>
<beans:ref bean="jsonConverter"/>
<beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"></beans:bean>
<beans:bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></beans:bean>
<beans:bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></beans:bean>
<beans:bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></beans:bean>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean name="byteArrayConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></beans:bean>
<beans:bean name="jaxbConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></beans:bean>
<beans:bean name="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></beans:bean>
<beans:bean name="caseInsensitivePathMatcher" class="com.darproject.webUtils.CaseInsensitiveAnnotationHandlerMapping"/>
<beans:bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<beans:property name="pathMatcher" ref="caseInsensitivePathMatcher"></beans:property>
</beans:bean>
Methods that are not working now.
#RequestMapping(value="/commentswindow/{defectId}/{release}/{defectsRowID}",method=RequestMethod.POST)
public String addUserComments(
#PathVariable("defectsRowID") long defectsRowID,
#PathVariable("defectId") String defectId,
#PathVariable("release") String release,
#ModelAttribute("addComments") UserCommentsModel cmtModel,
BindingResult results,
Model model,
HttpServletRequest request,
HttpServletResponse response){
The case-insensitive conflicts with path variable mapping. You can change your variable name to all lowercase: defectId --> defectid. It should work.
#RequestMapping(value="/commentswindow/{defectid}/{release}/{defectsrowid}",method=RequestMethod.POST)public String addUserComments(
#PathVariable("defectsrowid") long defectsRowID,
#PathVariable("defectid") String defectId,
#PathVariable("release") String release,
#ModelAttribute("addComments") UserCommentsModel cmtModel,
BindingResult results,
Model model,
HttpServletRequest request,
HttpServletResponse response){

spring security 2.0.6 AuthenticationProcessingFilter authenticationFailureUrl not working

I solved my issue here.
I had forgotten about the following:
<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<beans:property name="loginFormUrl" value="/index.jsp" />
<beans:property name="forceHttps" value="false" />
</beans:bean>
As you can see from above I do have /index.jsp and that is where it is trying to go.
The other issue is the following line
<concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/>
So this tells me to throw and exception.
So in the end - everything appears to be working as expected.
Original Post:
As the subject states I have the following configuration:
<beans:bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<beans:property name="defaultTargetUrl" value="/admin/adminLanding.html"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/>
<beans:property name="allowSessionCreation" value="true" />
<beans:property name="targetUrlResolver" ref="roleBasedTargetUrlResolver" />
</beans:bean>
My expectation is that when a authentication fails or has expired that it would make use of the setting for authenticationFailureURL. But what I get is the following error in my log:
The requested resource (/ecotrak/index.jsp) is not available.
I do not understand why it is looking for index.jsp when I have given /login.jsp?login_error=1 as the value.
Any direction it this?

Categories