I was looking through oAuth2.0 and I wrote this demo code, but I am not getting access token.
http://localhost:8080/oauth/token?grant_type=password&client_id=restapp2&client_secret=secret&username=admin&password=admin
It shows Access is Denied as
<error_description>Access is denied</error_description>
<error>access_denied</error>
Please, help me out.
spring-security.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:context="http://www.springframework.org/schema/context" xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
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 pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<http pattern="/admin**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/admin**" access="ROLE_APP"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test"/>
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_APP"/>
</user-service>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="accessTokenValiditySeconds" value="120"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="requestFactory"/>
</bean>
<bean id="requestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg name="clientDetailsService" ref="clientDetails"/>
</bean>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" resource-id="test" token-services-ref="tokenServices"/>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="restapp1" authorized-grant-types="authorization_code,client_credentials" authorities="ROLE_APP" scope="read,write,trust" secret="secret"/>
<oauth:client client-id="restapp2" authorized-grant-types="password,authorization_code,refresh_token,implicit" secret="secret" authorities="ROLE_APP"/>
</oauth:client-details-service>
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler"/>
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
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_2_5.xsd">
<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>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
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">
<!--<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:mvc="http://www.springframework.org/schema/cache"-->
<!--xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">-->
<context:component-scan
base-package="com.suraj.ecommerce.controller"/><!-- DispatcherServlet will search the controller class-->
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<mvc:resources mapping="/resources/**" location="/resources/assets"/>
<mvc:annotation-driven/><!--for using the map-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ecommerce"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="abc#gmail.com " />
<property name="password" value="abc" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
<bean id="mail" class="com.suraj.ecommerce.others.Mail"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.suraj.ecommerce.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<!--<bean id="signupService" class="com.suraj.ecommerce.service.SignUpService"/>-->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="productDAOImpl" class="com.suraj.ecommerce.daoimpl.ProductDAOImpl"/>
<bean id="productService" class="com.suraj.ecommerce.service.ProductService"/>
<bean id="signupService" class="com.suraj.ecommerce.service.SignUpService"/>
<bean id="signupDAOImpl" class="com.suraj.ecommerce.daoimpl.SignUpDAOImpl"/>
The Client secret that you are passing, secret is for client id restapp1
I guess you should pass restapp as the secret
Related
My problem is if I use org.springframework.security.authentication.ProviderManager for my autheticationManager in applicationContext-security.xml then I unable to authenticate with oauth2. If I switch back to authentication-manager id="authenticationManager" version then it works fine.
I have to keep my REST service and oauth2 security settings in separate files. (Sometimes we don't need for REST service at all).
spring-security 4.2.9.RELEASE
spring-security-oauth2 2.3.4
web.xml snippet:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/rest-dispatcher-servlet.xml
/WEB-INF/rest-dispatcher-servlet-security.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
rest-dispatcher-servlet-security
<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:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:secdp="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Definition of the Authentication Service -->
<secdp:http use-expressions="false" pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<secdp:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
<secdp:csrf disabled="true"/>
</secdp:http>
<!-- Protected resources -->
<secdp:http use-expressions="false" pattern="/ws/api/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/ws/api/**"
access="ROLE_USER"/>
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<access-denied-handler
ref="oauthAccessDeniedHandler"/>
<secdp:csrf disabled="true"/>
</secdp:http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler" >
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="dstest"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="xxxxxxxxx"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_USER, ROLE_TRUSTED_USER"
redirect-uri="/"
scope="read,write,trust"
access-token-validity="2678400"
refresh-token-validity="15552000" />
</oauth:client-details-service>
<bean class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory" id="oAuth2RequestFactory">
<constructor-arg ref="clientDetails" />
</bean>
</beans>
applicationContext-security.xml snippet
<!-- works -->
<authentication-manager id="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="CustomUserDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<!-- does not work -->
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</constructor-arg>
</bean>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref bean="CustomUserDetailsService"/>
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder"/>
</property>
<property name="hideUserNotFoundExceptions">
<value>false</value>
</property>
</bean>
I was trying to add spring security to my application. Below are my web.xml and sprin-security.xml files. When I ran the application I get the below error. Can you please let me know what is wrong in my code. This is most likely related to my web.xml
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:252)
web.xml
<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_2_5.xsd"
version="2.5">
<display-name>UniteID Rest WebService</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-config.xml,
/WEB-INF/spring-security.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 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>
</web-app>
Spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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.0.3.xsd">
<!-- <http auto-config="true"> <intercept-url pattern="/welcome*" access="ROLE_USER"
/> <form-login login-page="/login" default-target-url="/welcome" authentication-failure-url="/loginfailed"
/> <logout logout-success-url="/logout" /> </http> -->
<http>
<intercept-url pattern="/welcome*" access="ROLE_USER" />
<http-basic />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="mkyong" password="123456" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
spring-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:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.uniteid.controller" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>mymessages</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#nyvm0467.ptc.un.org:1521:EIDMSUAT" />
<property name="username" value="DBO_EIDMSUAT" />
<property name="password" value="NewPassDBO_EIDMSUAT" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.uniteid.model.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.connection.pool_size">10</prop>
</props>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dataDao" class="com.uniteid.dao.DataDaoImpl"></bean>
<bean id="dataServices" class="com.uniteid.services.DataServicesImpl"> </bean>
</beans>
Your configuration lacks a ContextLoaderListener.
Add it to your web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(And please read the exception outputs more carefully.)
My Spring MVC application shows a weird behavior. When a client who opens the website for the very first time but goes directly to any page other than the home page URL (for example www.xyz.com/signUp), the application returns a HttpStatus.302 and redirects it to the home page (www.xyz.com). The next time the client accesses the sign up page, it works as expected and goes to www.xyz.com/signUp.
Find below the application.xml, web.xml and spring-security.xml for my application. Please feel free to ask for any other content if required for providing a solution.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
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">
<display-name>MyApp</display-name>
<!-- Spring Security Configuration File -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlet and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</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>
<servlet>
<servlet-name>mvc-dispatcher</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>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/exception/404.jsp</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/WEB-INF/jsp/exception/400.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/WEB-INF/jsp/exception/403.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/jsp/exception/commonException.jsp</location>
</error-page>
</web-app>
application.xml
<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:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<import resource="spring-security.xml" />
<!-- <import resource="social.xml" />
<import resource="social-security.xml" /> -->
<context:annotation-config />
<context:component-scan base-package="com.inw.xyz" />
<context:spring-configured />
<jpa:repositories base-package="com.inw.xyz.repository" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="noTextEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
factory-method="noOpText" />
</bean>
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="noTextEncryptor" />
</bean>
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
</bean>
</list>
</property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- setting maximum upload size -->
<property name="maxUploadSize" value="10000000000" />
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:default-servlet-handler />
<mvc:annotation-driven />
<context:annotation-config />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/XYZ" />
<property name="username" value="abc" />
<property name="password" value="abc123" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="database" value="MYSQL" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<!-- spring based scanning for entity classes -->
<property name="packagesToScan" value="com.inw.xyz.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Tiles configuration -->
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles/tiles-definitions.xml</value>
</list>
</property>
</bean>
<bean id="userRegisterationValidator" class="com.inw.xyz.validator.UserRegisterationValidator" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<!-- SMTP settings -->
<property name="host" value="mail.com" />
<property name="port" value="25" />
<property name="username" value="webmaster#xyz.com" />
<property name="password" value="***" />
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<!-- <prop key="mail.smtp.starttls.enable">true</prop> -->
<prop key="mail.mime.charset">UTF-8</prop>
<!-- <prop key="mail.debug">true</prop> -->
</props>
</property>
</bean>
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">
org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</prop>
</props>
</property>
</bean>
<context:property-placeholder location="classpath:environment.properties"/>
</beans>
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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.xsd">
<http pattern="/resources/**" security="none" />
<http authentication-manager-ref="userAuthManager">
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/home" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/signUp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/signUp/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/*" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-page='/' authentication-failure-url="/" />
<logout invalidate-session="true" logout-success-url="/" logout-url="/logout" />
<session-management invalid-session-url="/">
<concurrency-control max-sessions="1"
expired-url="/" />
</session-management>
</http>
<beans:bean id="userAuthManager" class="com.inw.xyz.security.UserAuthManager">
</beans:bean>
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
</beans:beans>
remove invalid-session-url="/" attribute in <session-management > tag in spring-security.xml try this-
<session-management>
<concurrency-control max-sessions="1"
expired-url="/" />
</session-management>
There is lot of similar questions at StackOverflow, but I can't find any answered :(
I have web.xml like:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-web.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring</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>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
and trying to configure method security with annotations. As I see it must be done by <sec:global-method-security pre-post-annotations="enabled"/>, placed at same context as other components, spring-web.xml at my case. So I have following spring-web.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
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.0.xsd"
default-autowire="byName">
<context:component-scan base-package="com.cleanplates.apiserv"/>
<sec:global-method-security pre-post-annotations="enabled"/>
</beans>
and spring-security.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
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.0.xsd">
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/**"
filters="
usernamePasswordProcessingFilter,
rememberMeFilter,
anonymousProcessingFilter,
exceptionTranslationFilter,
filterInvocationInterceptor"/>
</sec:filter-chain-map>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
</list>
</property>
</bean>
<bean id="anonymousProcessingFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="********"/>
<property name="userAttribute">
<bean class="org.springframework.security.core.userdetails.memory.UserAttribute">
<property name="authoritiesAsString">
<list>
<value>ROLE_ANONYMOUS</value>
</list>
</property>
<property name="password" value="none"/>
</bean>
</property>
</bean>
<bean id="usernamePasswordProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="filterProcessesUrl" value="/auth/password"/>
<property name="usernameParameter" value="username"/>
<property name="passwordParameter" value="password"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="*******"/>
<property name="alwaysRemember" value="true"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="******"/>
</bean>
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
</property>
</bean>
<bean id="filterInvocationInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="securityMetadataSource">
<sec:filter-security-metadata-source>
<sec:intercept-url pattern="/**" access="ROLE_ANONYMOUS,ROLE_USER" method="GET"/>
<sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="POST"/>
<sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="PUT"/>
<sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="DELETE"/>
</sec:filter-security-metadata-source>
</property>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<bean class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="***"/>
</bean>
<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="saltSource">
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="salt"/>
</bean>
</property>
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean>
</list>
</property>
</bean>
<bean id="myUserDetailsService" class=".UserDetailsServiceImpl">
</bean>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
</bean>
</beans>
The problem that after adding <sec:global-method-security all controllers stop working. And I have following in logs:
PageNotFound:noHandlerFound:947 - No mapping found for HTTP request with URI [/some/page] in DispatcherServlet with name 'spring'
Everything is working when i remove this global-security element. If i'm adding it into spring-security.xml - nothing changes. Seems that it's not used, because methods annotated with #PreAuthorize("hasRole('ROLE_ADMIN')") (or any other role) are accessible by anyone.
PS I'm using Spring 3.0.5.RELEASE and Spring Security 3.0.5.RELEASE
After you enable <sec:global-method-security> spring security creates proxies for your controllers. spring-mvc can't find annotations like #RequestMapping on bean in this case. If you want to use security annotations on your controllers you should extract interface of controller and put mvc annotations on it.
Spring documentation contains following note about this:
NOTE: When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all your mapping annotations - such as #RequestMapping and #SessionAttributes - on the controller interface rather than on the implementation class.
I have my spring security set up to do basic authentication to a database with no issues, however I would like to add custom login/logout and admin pages as well as md5 encryption on passwords w/ salt.
I keep hitting walls trying to get either of these features to work, and all the examples online seem to be using and declaring like that instead of using bean declarations like I am. This makes it more difficult because options in examples don't seem to directly translate into bean properties.
Here is my web.xml - I am using Spring Security 3.0:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/builder-servlet.xml
/WEB-INF/builder-service.xml
/WEB-INF/builder-data.xml
/WEB-INF/builder-security.xml
</param-value>
</context-param>
<servlet>
<servlet-name>builder</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>builder</servlet-name>
<url-pattern>*.htm</url-pattern>
<url-pattern>*.docx</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.springframework.security.web.FilterChainProxy</param-value>
</init-param>
</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>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>redirect.jsp</welcome-file>
</welcome-file-list>
</web-app>
And here is my builder-security (mind the disorganization):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
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.0.xsd">
<!--<s:authentication-manager>
<s:authentication-provider ref="authenticationProvider"/>
</s:authentication-manager>-->
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<s:filter-chain-map path-type="ant">
<s:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,
exceptionTranslationFilter,
authenticationProcessingFilter,
filterSecurityInterceptor,
anonymousAuthenticationFilter"/>
</s:filter-chain-map>
</bean>
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
<bean id="authenticationProcessingFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="authenticationProvider"/>
<ref bean="anonymousAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<!--<property name="passwordEncoder" ref="md5PasswordEncoder"/>-->
<!--<property name="saltSource" ref="systemWideSaltSource"/>-->
<property name="userDetailsService" ref="authenticationDao"/>
<property name="userCache" ref="userCache"/>
</bean>
<bean id="md5PasswordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
</bean>
<bean id="systemWideSaltSource" class="org.springframework.security.authentication.dao.SystemWideSaltSource">
<property name="systemWideSalt" value="XXXX"/>
</bean>
<bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
<property name="cache" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheName" value="userCache"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="ehcache.xml"/>
</bean>
<bean id="authenticationDao" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="SpecBuilder"/>
</bean>-->
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.html"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<property name="decisionVoters">
<list>
<ref bean="voter"/>
</list>
</property>
</bean>
<bean id="voter" class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value="ROLE_"/>
</bean>
<bean id="anonymousAuthenticationFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="objectDefinitionSource">
<s:filter-invocation-definition-source>
<s:intercept-url pattern="/login*" access="ROLE_ANONYMOUS"/>
<s:intercept-url pattern="/**" access="ROLE_USER"/> <!-- isAuthenticated() probably better -->
</s:filter-invocation-definition-source>
</property>
</bean>
</beans>
Right now I am trying to get login.html to all anonymous access, yet all I get is an infinite security loop.
Is there a reason I shouldn't be using bean declarations for this? Because not very many people seem to be doing so. I'd rather not change the whole thing if there is no advantage to doing it. There has to be something wrong with it or a better place to go to get bean declaration references and examples, because most all searches turn up the other style of implementing spring security.
Step-by-step spring security explained:
http://blog.solidcraft.eu/2011/03/spring-security-by-example-set-up-and.html
Good luck!
After a fair bit of research and testing, I've solved it.
The built in security namespace does a good chunk of the work for you. Creating each filter and manager bean by bean is a good way to customize things, but it makes it quite bit more difficult and it's not really necessary.
My final code involves a custom user class that includes a salt value and a custom dao class to enforce the use of the salt. Everything else is done through use of the security namespace.
builder-security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
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.0.xsd">
<s:http auto-config="true" use-expressions="true">
<s:intercept-url pattern="/login*" access="permitAll"/>
<s:intercept-url pattern="/*" access="hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')"/>
<s:form-login login-page="/login.html"/>
<s:logout logout-url="/logout"/>
</s:http>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider user-service-ref="userDetailsService">
<s:password-encoder ref="passwordEncoder">
<s:salt-source ref="saltSource"/>
</s:password-encoder>
</s:authentication-provider>
</s:authentication-manager>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="salt"/>
</bean>
<bean id="userDetailsService" class="builder.webapp.security.CustomJdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="enableAuthorities" value="true"/>
<property name="enableGroups" value="false"/>
<property name="usersByUsernameQuery"
value="select username,password,enabled,salt from users where username = ?"/>
</bean>
</beans>