I have a Spring 4 MVC + Security application that runs perfectly.
I am trying to integrate HDIV with it and have been through the documentation and the showcase example: https://github.com/hdiv/hdiv-spring-mvc-showcase/
When I use avoidValidationInUrlsWithoutParams = true, everything works fine till the point where I don't have parameters (Obviously).
When I remove that part, it just throws me to the Security-Error Page. I tried debugging and I see that Spring Security has authenticated successfully -- but HDIV throws the HDIV_PARAMETER DOES NOT EXIST error - this is what I have in the logs:
2016-07-27 08:24:34 [http-apr-8080-exec-5] INFO org.hdiv.logs.Logger - HDIV_PARAMETER_DOES_NOT_EXIST;/EmployeePortal/modules/dashboard.htm;177622190;;;127.0.0.1;127.0.0.1;MALLIKAM;
Apparently, I understand that the page found HDIV_STATE from the number there, but it could not find the CSRF? (I, assume the 3 semicolons are for some paramter that HDIV was trying to find and that parameter is CSRF?)
Also, I am able to see the generated csrf on the index page (which makes me doubt if I have set up HDIV correctly because the last time, when I had tried it, all hidden fields would show up differently - either blank or 0, if I correctly remember.)
If so, I would like to know why and what can I do to resolve it?
This is what I have so far:
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml, /WEB-INF/spring-security.xml, /WEB-INF/hdiv-config.xml, ...</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- For HTTPSession events -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<!-- HDIV Listener -->
<listener>
<listener-class>org.hdiv.listener.InitListener</listener-class>
</listener>
<filter>
<filter-name>ValidatorFilter</filter-name>
<filter-class>org.hdiv.filter.ValidatorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidatorFilter</filter-name>
<!-- Spring MVC Servlet name-->
<servlet-name>serv1</servlet-name>
</filter-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>
<servlet>
<servlet-name>serv1</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-web-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>serv1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
spring-security.xml
<!-- To let spring create login page -->
<http auto-config="false" disable-url-rewriting="true"
use-expressions="true">
<access-denied-handler ref="accessDeniedHandler" />
<!-- CSRF is enabled by default Spring 4 onwards -->
<!-- check roles -->
<intercept-url pattern="/modules/favicon.ico" access="isAnonymous()" />
<intercept-url pattern="/login.htm" access="isAnonymous()" />
<intercept-url pattern="/login.htm?error" access="isAnonymous()" />
<intercept-url pattern="/logout" access="isAnonymous()" />
<intercept-url pattern="/modules/**" access="hasAnyRole('ROLE_y','ROLE_x')" />
<form-login login-page="/" default-target-url="/modules/dashboard.htm"
username-parameter="username" password-parameter="password"
authentication-failure-url="/login.htm?error" />
<custom-filter after="SECURITY_CONTEXT_FILTER" ref="hdivFilter" />
<!-- Logout -->
<logout logout-url="/logout.htm" delete-cookies="JSESSIONID"
invalidate-session="true" logout-success-url="/login.htm" />
<!-- Session Management: Invalid Session Url is for SessionTimeout as well
as invalid login -->
<session-management session-fixation-protection="newSession"
invalid-session-url="/login.htm" session-authentication-error-url="/login.htm">
<!-- Concurrency control is to check number of sessions and act accordingly.
Error If Max exceeded stops a user from logging in if max-sessions have been
exceeded. Expired Url is different from invalid url. -->
<concurrency-control max-sessions="2"
expired-url="/login.htm" error-if-maximum-exceeded="true" />
</session-management>
</http>
<!-- Spring security authentication manager -->
<authentication-manager alias="authenticationManager">
<!-- Custom Auth Provider checks for login with DB and LDAP both -->
<authentication-provider ref="customAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<!-- Bean implements AuthenticationProvider and checks if user is valid -->
<beans:bean id="customAuthenticationProvider"
class="..employeeportal.common.util.CustomAuthenticationProvider">
<beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
<!-- BCrypt Password encoder -->
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<!-- Access Denied Handler -->
<beans:bean id="accessDeniedHandler"
class="..employeeportal.common.util.AccessDeniedHandler">
</beans:bean>
<beans:bean id="hdivFilter" class="org.hdiv.filter.ValidatorFilter" />
spring-web-config.xml
<mvc:annotation-driven validator="hdivEditableValidator"/>
...
applicationContext.xml
... has all the service/ dao layer component scan lines:
<context:component-scan
base-package="..common.service, ..common.dao" />
hdiv-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hdiv="http://www.hdiv.org/schema/hdiv"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.hdiv.org/schema/hdiv http://www.hdiv.org/schema/hdiv/hdiv.xsd">
<hdiv:config excludedExtensions="css,ico,js,woff,woff2,ttf,jpg,jpeg,png,gif,eot"
errorPage="/security-error" randomName="true" confidentiality="true" debugMode="true">
<hdiv:startPages method="get">/,/login.htm</hdiv:startPages>
<hdiv:startPages method="post">/logout, /logout.htm</hdiv:startPages>
<hdiv:startParameters>_csrf</hdiv:startParameters>
</hdiv:config>
<!-- Accepted pattern within the application for all editable parameters (generated from textbox and textarea) -->
<hdiv:validation id="safeText">
<hdiv:acceptedPattern><![CDATA[^[a-zA-Z0-9@.\-_]*$]]></hdiv:acceptedPattern>
</hdiv:validation>
<!-- Finally, it's necessary to define editable data validation list for
the application -->
<hdiv:editableValidations>
<hdiv:validationRule url="/modules/.*"></hdiv:validationRule>
<hdiv:validationRule url="/modules/.*" enableDefaults="false">safeText</hdiv:validationRule>
</hdiv:editableValidations>
index.jsp
<form:form name='loginForm' modelAttribute="loginForm"
action="login" method='POST'>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<form:input path="username" name="username" id="username"/>
</div>
</div>
<div class="form-group">
<div class="input-group">
<form:input path="password" id="password" name="password"/>
</div>
</div>
<div class="form-group no-border margin-top-20">
<input type="submit"
class="btn btn-success btn-block" value="Submit" />
</div>
</form:form>
Any help would be appreciated.
It seems that the problem is not related with CSRF.
Hdiv validates all incoming requests and in order to do that, all the URLs and parameters has to be rendered at server side using some of the supported technologies such as Spring MVC tags.
Are you using Spring MVC URL tag to render the URL included in the error file?
Once you use Spring MVC tag for that, Hdiv will include an additional parameter (HDIV_STATE) to the URL and you will avoid the issue.
This parameter makes possible the protection against any tampering attack to the defined URL.
Other possible solution is to eliminate the validation of this specific URL or URls types using URL exclusions, where Hdiv will not validate those URLs.
See this example: https://github.com/hdiv/hdiv-spring-mvc-showcase-jc/blob/master/src/main/java/org/hdiv/samples/mvc/config/HdivSecurityConfig.java where within addExclusions method are defined different exclusions.
Regards,
Roberto Velasco
Hdiv Security