Spring Security Custom Preauthentication filter with Digest Authentication - filter

I have an app with uses a Digest authentication. I want to customize the authentication process by checking a custom HTTP header in addition to the Digest method. If the header is present in the request the authentication should proceed as before, if it isn't then the user should be rejected. I tried to do this by defining a custom preauthentication filter, but somehow it doesn't work together with the Digest filter.
<security:http entry-point-ref="digestEntryPoint">
<security:custom-filter ref="customPreauthFilter" position="PRE_AUTH_FILTER"/>
<security:custom-filter ref="digestFilter" before="BASIC_AUTH_FILTER"/>
<security:anonymous enabled="false"/>
</security:http>
<bean id="customPreauthFilter" class="com.myapp.messaging.security.SoundianRequestHeaderAuthenticationFilter">
<property name="authenticationManager" ref="appControlAuthenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="customUserDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="appControlAuthenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
<security:authentication-provider ref="daoAuthenticationProvider"/>
</security:authentication-manager>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="customUserDetailsService"/>
</bean>
<!-- Digest authentication -->
<bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<security:authentication-provider ref="preauthAuthProvider" />
<!-- <security:authentication-provider ref="daoAuthenticationProvider"/>-->
</bean>
<bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
<property name="realmName" value="myvalue"/>
<property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/>
</bean>
The Preauthentication filter succeeds, but I am still getting 401 results.
If I uncomment
<!-- <security:authentication-provider ref="daoAuthenticationProvider"/>-->
then the preauthentication filter is disregarded.

Related

Obtaining OAuth token with Basic Authentication

Background
I have a Spring application with OAuth2 security.
I can easily obtain an OAuth Bearer token with the following request:
POST {{...}}/oauth/token
?grant_type=password
&client_id={{client_id}}
&username={{username}}
&password={{password}}
This returns a 200 OK request with my access_token in the response.
Problem
My problem is that one of my clients doesn't like the idea of sending plain text passwords in the query as a query parameter and they want to get the OAuth Bearer token using Basic Autentication.
However I can't make it work the following way:
POST {{...}}/oauth/token
Authorization: Basic base64encoded(username:password)
Content-Type: application/x-www-form-urlencoded
Request Body:
{
"grant_type": "password",
"client_id": {{client_id}}
}
It returns 401 Unauthorized, and
{
"error": "unauthorized",
"error_description": "Bad credentials"
}
My applicationContext.xml file looks like this:
<beans>
...
<!-- Definition of the Authentication Service -->
<security:http
pattern="/oauth/token"
create-session="stateless"
authentication-manager-ref="clientAuthenticationManager">
<security:anonymous enabled="false"/>
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<security:access-denied-handler ref="oauthAccessDeniedHandler"/>
</security:http>
<!-- Protected resources -->
<security:http
pattern="/v3/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false"/>
<security:intercept-url pattern="/v3/**" access="IS_AUTHENTICATED_FULLY"/>
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<security:access-denied-handler ref="oauthAccessDeniedHandler"/>
</security:http>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/>
<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">
<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>
<security:authentication-manager id="clientAuthenticationManager">
<security:authentication-provider user-service-ref="clientDetailsUserService"/>
</security:authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myAuthProvider"/>
</security:authentication-manager>
<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="accessTokenValiditySeconds" value="86400"/>
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="oAuth2RequestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg ref="clientDetails"/>
</bean>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices"/>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="web-console"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
scope="read,write,trust"
access-token-validity="86400"
refresh-token-validity="86400"/>
</oauth:client-details-service>
...
</beans>
Question
Ideally I should be able to call the /oauth/token endpoint with Authorization Basic xxxxxxxxxxxxxxx header, and I would be able to obtain the OAuth bearer token.

Spring Security having two authentication layers

In our application, we are required to have two layers of authentication,Database and LDAP, i.e,
Once User logins with username and password, Database validation is done only to check if username exists in database using custom authentication privider.
If username exists in the database then second layer of LDAP has to be invoked to check if password matches.If password matches with that in LDAP then user should be authenticated.If username doesn't exist in the database, the LDAP layer shouldn't be invoked and user shouldn't be authenticated.
I have implemented the first layer of authentication i.e Database validation for username.
However I am not able to figure out how I can have second layer i.e LDAP for password check.
It would be great if someone helps me on this.
Below is the code in security xml file:
<security:http auto-config="false" use-expressions="true"
entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
<security:custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER" />
<security:access-denied-handler
error-page="/accessDenied" />
<security:logout delete-cookies="JSESSIONID" logout-success-url="/logout" />
<security:session-management session-authentication-strategy-ref="sas" />
<security:headers >
<security:cache-control />
<security:hsts/>
</security:headers>
</security:http>
<security:global-method-security
pre-post-annotations="enabled" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="customAuthenticationProvider" />
</security:authentication-manager>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/">
</property>
</bean>
<bean id="customAuthenticationFilter"
class="com.honeywell.wfm.util.CustomAuthenticationFilter">
<property name="usernameParameter" value="username"></property>
<property name="passwordParameter" value="password"></property>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="successHandler"/>
<property name="sessionAuthenticationStrategy" ref="sas" />
</bean>
<bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/dashboard"/>
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/failTologin"/>
</bean>
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl" value="/logout" />
</bean>
<bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
<property name="exceptionIfMaximumExceeded" value="false" />
</bean>
<bean
class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</bean>
<bean
class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value="" />
</bean>
<bean id="customAuthenticationProvider"
class="com.honeywell.wfm.service.impl.CustomAuthenticationProvider"></bean>
CustomAuthenticationProvider.java
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String employeeNumber = authentication.getName();
String password = (String) authentication.getCredentials();
UserDTO userDTO = loginComponent.loadUserByUsername(employeeNumber);
if (userDTO.getEmployeeNo() == null) {
logger.error("Authentication failure for "+employeeNumber);
throw new BadCredentialsException("Invalid Employee Number");
}
logger.info("Successfully Authenticated " +userDTO.getUserName());
userDTO.setPassword(password);
return new UsernamePasswordAuthenticationToken(userDTO, password, userDTO.getAuthorities());
}

Spring Security and custom Remember me filter: logout issue

I need to define a custom RememberMeAuthenticationFilter so that I can override the onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) method to put some custom logic.
I've configured the XML in order to use my custom filter:
<security:http disable-url-rewriting="true" request-matcher-ref="excludeUrlRequestMatcher" entry-point-ref="authenticationEntryPoint">
<security:custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordAuthenticationFilter"/>
<security:custom-filter position="REMEMBER_ME_FILTER" ref="extRememberMeProcessingFilter"/>
<security:anonymous username="anonymous" granted-authority="ROLE_ANONYMOUS"/>
<security:session-management session-authentication-strategy-ref="fixation" />
<!-- Intercepts url HERE: removed for brevity -->
<!--<security:form-login: using custom filter -->
<!--login-page="/login"-->
<!--authentication-failure-handler-ref="loginAuthenticationFailureHandler"-->
<!--authentication-success-handler-ref="loginGuidAuthenticationSuccessHandler"/>-->
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>
<security:port-mappings>
<security:port-mapping http="#{configurationService.configuration.getProperty('tomcat.http.port')}"
https="#{configurationService.configuration.getProperty('tomcat.ssl.port')}"/>
<security:port-mapping http="80" https="443"/>
<!--security:port-mapping http="#{configurationService.configuration.getProperty('proxy.http.port')}"
https="#{configurationService.configuration.getProperty('proxy.ssl.port')}" /-->
</security:port-mappings>
<security:request-cache ref="httpSessionRequestCache"/>
<security:access-denied-handler ref="b2bAccessDeniedHandler"/>
<!-- RememberMe: using custom filter -->
<!--<security:remember-me key="comtestrememberme" services-ref="rememberMeServices"/>-->
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myAuthenticationProvider"/>
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
<bean id="myAuthenticationProvider"
class="com.test.security.MyAuthenticationProvider">
<property name="bruteForceAttackCounter" ref="bruteForceAttackCounter"/>
<property name="customerService" ref="customerService"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeServices"
class="com.test.security.MyRememberMeServices">
<property name="key" value="comtestrememberme"/>
<property name="cookieName" value="myRememberMe"/>
<property name="alwaysRemember" value="false"/>
<property name="customerService" ref="customerService"/>
<property name="useSecureCookie" value="false"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="comtestrememberme"/>
<aop:scoped-proxy/>
</bean>
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationSuccessHandler" ref="loginGuidAuthenticationSuccessHandler"/>
<property name="authenticationFailureHandler" ref="loginAuthenticationFailureHandler"/>
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login"/>
</bean>
<bean id="extRememberMeProcessingFilter" class="com.test.security.filters.ExtRememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
The remember me cookie is getting created and my custom filter is being used, but the problem is that the logout never happens.
When I click on the logout button it looks like I'm going through the authentication process again and the customer is logged in again.
If I revert back to the standard Spring Filters everything is working fine.
Have I missed something in the configuration?
What may be happening here is - your logout is working fine but you haven't deleted myRememberMe cookie on logout. So, when your session is getting invalidated on logout, remember me services is creating a new session by using myRememberMe cookie.
Solution: You can modify your configuration by adding delete-cookies attribute in your <security:logout> tag.
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler" delete-cookies="JSESSIONID,myRememberMe" />

Method 'setProviders' is marked deprecated in Spring Security 3.2.7

I am using Spring Security 3.2.7 and I got this warning in my spring configuration
Multiple annotations found at this line:
- Method 'setProviders' is marked deprecated
security-config.xml:
<security:http auto-config="true">
<security:intercept-url pattern="/**" />
<security:form-login login-page="/login**"
default-target-url="/dashboard**"
authentication-failure-url="/login.xhtml?failed=true"/>
<security:logout logout-url="/logout" logout-success-url="/login.xhtml"/>
</security:http>
<bean id="userDao" class="com.tds.erp.dao.impl.UserDaoImpl"
autowire="default" />
<bean id="userDetailsService" class="com.tds.erp.services.impl.UserDetailServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" ></property>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<!-- <security:password-encoder hash="bcrypt"/> -->
</security:authentication-provider>
</security:authentication-manager>
</beans>
Try with the following for the authentication manager
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg ref="daoAuthenticationProvider"/>
</bean>

Spring 3.x configuration for multiple login pages

I'm using Spring 3.1 for authentication purpose.
My requirement:
Two different login pages. One for Customer and other for Employee.
Each after successful authentication, will be forwarded to respective successful URL.
My spring security configuration:
<sec:http pattern="/resources/**" security="none" />
<sec:http auto-config="true">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" />
<sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" />
</sec:http>
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/**"
filters="authenticationProcessingFilterForCustomer,authenticationProcessingFilterForEmployee" />
</sec:filter-chain-map>
</bean>
<bean id="authenticationProcessingFilterForCustomer"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForCustomer" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" />
<property name="authenticationSuccessHandler" ref="customerSuccessHandler" />
<property name="authenticationFailureHandler" ref="customerFailureHandler" />
</bean>
<bean id="customerSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/customer/index.html" />
</bean>
<bean id="customerFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/customer.html?login_error=1" />
</bean>
<bean id="authenticationManagerForCustomer"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customCustomerAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customCustomerAuthenticationProvider" class="com.edu.CustomerCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.CustomerUserDetailsService" />
</property>
</bean>
<bean id="authenticationProcessingFilterForEmployee"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForEmployee" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" />
<property name="authenticationSuccessHandler" ref="employeeSuccessHandler" />
<property name="authenticationFailureHandler" ref="employeeFailureHandler" />
</bean>
<bean id="employeeSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/employee/index.html" />
</bean>
<bean id="employeeFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/employee.html?login_error=1" />
</bean>
<bean id="authenticationManagerForEmployee"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customEmployeeAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customEmployeeAuthenticationProvider" class="com.edu.EmployeeCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.EmployeeUserDetailsService" />
</property>
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="customCustomerAuthenticationProvider" />
<sec:authentication-provider ref="customEmployeeAuthenticationProvider" />
</sec:authentication-manager>
Both CustomAuthenticationProvider have implemented Support method as follows:
public boolean supports(Class<? extends Object> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
After launching application, while trying to authenticate, the message displayed in login pages are:
Your login attempt was not successful, try again.
Reason: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
I'm using Spring 3.1. Any help appreciated.
Thank You
I have done similar things in grails, what you need is:
extend UsernamePasswordAuthenticationToken, create two sub-class for employee and customer, say EmployeeUsernamePasswordAuthenticationToken and CustomerUsernamePasswordAuthenticationToken
extend UsernamePasswordAuthenticationFilter, to create different instance of EmployeeUsernamePasswordAuthenticationToken or CustomerUsernamePasswordAuthenticationToken based on current auth request
extend AuthenticationProvider for employee and custoner, create two class say EmployeeAuthenticationProvider and CustomerAuthenticationProvider, overwrite each class' supports method to support its target UsernamePasswordAuthenticationToken
you only need one authenticationManager, register both provide into it
only need one AuthenticationSuccessHandler, you can decide which url want to go in it
I also create a my own instance of AuthenticationEntryPoint to support multi entrypoint
Beginning from Spring 3.1 you have as many configuration as you want :
https://jira.springsource.org/browse/SEC-1171
You should point the authenticationManager ref in 'authenticationProcessingFilterForCustomer' and 'authenticationProcessingFilterForEmployee' beans to correct bean i.e. 'authenticationManager' which has providers. No need to define 'authenticationManagerForCustomer' and 'authenticationManagerForEmployee' beans.

Resources