Solved

Using spring security to handle pre-authenticated user.

Posted on 2009-04-06
6
21,702 Views
Last Modified: 2013-11-24
Hello,

This is my second post relating to this question. I got a pointer to the pre-authenticated section of the spring security in the answer of my last request for help and felt kind of silly when I realized that I hadn't read the documentation. I can now say that I've read through the security documentation multiple times, read 2 books on spring security, and downloaded the spring security sample source files and am still stuck!

I can get authentication to work perfectly for form based authentication, but cannot seem to get my custom authentication. I've put my security-config.xml below for the basic authentication. I'm using Dacs for authentication which handles single sign on for a number of our apps that sit in the same server space. Dacs creates an encrypted cookie, which we then gets decrypted when it hits our entry point servlet. The challenge is that I need an HttpServletRequest to get Dacs to decrypt the cookie and need to do so without using form based authentication.

As you can see below I've created a custom authentication provider to handle authentication against our userProfile database. The actual authentication is happening in the dacsLogin.htm, which is a servlet. The servlet redirects to a jsp which automatically posts to spring security with the extracted details captured in the servlet. This is a real hack and is causing problems for me in ajax based requests when the session times out. If I could either replace the servlet with the pre-auth stuff without causing anything to be output to the client that would be the perfect solution.

The problem is I've tried 20 different configurations and can't seem to get the pre-auth to work. Does someone have a stipped down example of pre-auth working. Your help would be greatly appreciated.

Please don't refer me to spring documentation, as I've read it over and over and can't come to a solution from there. I need an example of using pre-auth with all the required pieces.

Thanks,

Jared


-----security-config.xml--------
 
<?xml version="1.0" encoding="UTF-8"?>
<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-2.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
 
   <!-- Put '@Secured( {"ROLE_SUPER"} )' over service methods ~ Not working causes error -->
    <!--<global-method-security secured-annotations="enabled" /> -->
 
    <http>
        <intercept-url pattern='/dacsLogin.htm' filters='none'/>
        <intercept-url pattern='/system/**' access='ROLE_SUPER' />
        <intercept-url pattern='/admin/**' access='ROLE_ADMIN' />
        <intercept-url pattern='/**' access='ROLE_BASIC' />
        <form-login login-page='/dacsLogin.htm' default-target-url='/index.jsp' always-use-default-target='false' />
    </http>
 
    <authentication-provider user-service-ref='userDetailsService'/>
 
    <beans:bean id="userDetailsService" class="com.cisco.btd.security.BtdUserDetailsService">
        <beans:property name="userService" ref="userService"/>
    </beans:bean>
 
</beans:beans>
 
------web.xml---------
..................
 <!-- Spring security -->
    <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
 
    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
.........................
 
---------dacs authentication servlet -----------
 
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        String dacsUsername;
        try {
            dacsUsername = DacsUtil.resolveUsername(DACS_BASE_URI, DACS_AUTH_JURIS, request);
            if (dacsUsername == null) {
                dacsUsername = "dacsuser";
                logger.error("Authentication problem. Couldn't find dacsUsername");
            }
            // Set session info.
            request.getSession(true).setAttribute(SESSION_USER_NAME, dacsUsername);
 
            logger.info("DACS credentials set for : " + dacsUsername);
        } catch (DacsException de) {
            dacsUsername = "dacsuser";
            logger.error("Failed authenticating with DACS: " + de.getMessage());
        }
 
        request.setAttribute("btdUser", dacsUsername);
        request.setAttribute("btdPassword", "");
        RequestDispatcher dispatcher;
        dispatcher = request.getRequestDispatcher("localLogin.jsp");
        dispatcher.forward(request, response);
 
}
 
--------------my hacked login jsp with auto-submit --------------
 
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
 
<html>
    <head>
        <title>Login Page</title>
    </head>
    <body>
        <form name='loginForm' action='<%= request.getContextPath() %>/j_spring_security_check' method='POST'>
            <input type='hidden' name='j_username' value='${btdUser}'>
            <input type='hidden' name='j_password' value='${btdPassword}' />
        </form>
        <SCRIPT language="JavaScript">
            document.loginForm.submit();
        </SCRIPT>
    </body>
</html>
 
------------my custom user authentication class - which works perfectly at this point -------------
 
public class BtdUserDetailsService implements UserDetailsService {
........................
 
@Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
 
        //find user - do the regular stuff.
        checkDefaultRoles();
 
        User user = userService.findByUserId(userName);
 
        user = checkUser(user, userName);
 
        return new BtdUserDetails(user);
    }
 
............................
 
}

Open in new window

0
Comment
Question by:intlgd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
6 Comments
 
LVL 14

Expert Comment

by:boonleng
ID: 24083402
By default spring pre-auth retrieve the user from "request.getUserPrincipal()".
To retrieve user from other source e.g cookie, you need to extends the class "J2eePreAuthenticatedProcessingFilter" and override the method "getPreAuthenticatedPrincipal(HttpServletRequest request)".

Then configure the security-config.xml to use the custom preauth filter, e.g:
 

Let me know if you are still have problem getting the user.


Boon Leng
0
 

Author Comment

by:intlgd
ID: 24088321
I'm not in a J2EE situation. Not sure how this applies to me. Do you have a functional security.xml example? I've downloaded and reviewed the J2EE Pre-auth sample source and don't see how this ties into my situation. I need a functional example.

Thanks,

Jared
0
 

Author Comment

by:intlgd
ID: 24089651
Alright, I've taken you example and what I've found in other places and it is compiling and trying to authenticate. Can you look over this and point me in the right direction. See code below:

-----------security-config.xml using special filter
 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:sec="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-2.5.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
 
    <bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/**" filters="sif,preAuthenticatedProcessingFilter,logoutFilter,fsi"/>
        </sec:filter-chain-map>
    </bean>
 
    <!-- Filter # 1 -->
    <bean id="sif" class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>
 
    <sec:authentication-manager alias="authenticationManager" />
 
    <sec:authentication-provider user-service-ref='userDetailsService'/>
 
    <bean id="userDetailsService" class="com.cisco.btd.security.BtdUserDetailsService">
        <property name="userService" ref="userService"/>
    </bean>
    
    <bean id="preAuthenticatedProcessingFilter" class="com.cisco.btd.security.PreAuthenticatedProcessingFilter">
        <sec:custom-filter position="PRE_AUTH_FILTER" />
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>
 
    <bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
        <sec:custom-authentication-provider />
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper" class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userDetailsService" />
            </bean>
        </property>
    </bean>
    
    <!-- Handle logout -->
    <bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <constructor-arg value="/"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>
 
    <bean id="httpRequestAccessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
    </bean>
 
    <bean id="fsi" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource">
            <sec:filter-invocation-definition-source>
                <sec:intercept-url pattern='/system/**' access='ROLE_SUPER' />
                <sec:intercept-url pattern='/admin/**' access='ROLE_ADMIN' />
                <sec:intercept-url pattern='/**' access='ROLE_BASIC' />
            </sec:filter-invocation-definition-source>
        </property>
    </bean>
 
    <bean id="roleVoter" class="org.springframework.security.vote.RoleVoter"/>
 
    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter">
        <property name="wrapperClass" value="org.springframework.security.wrapper.SecurityContextHolderAwareRequestWrapper"/>
    </bean>
 
</beans>
 
---------- UserDetailsService
 
public class BtdUserDetailsService implements UserDetailsService {
    private UserService userService;
 
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
 
        //find user - do the regular stuff.
        checkDefaultRoles();
 
        User user = userService.findByUserId(userName);
 
        user = checkUser(user, userName);
 
        return new BtdUserDetails(user);
    }
......
}
 
 
------------- Custom filter - this is incomplete and needs some pointers.
 
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter;
 
public class PreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
 
    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        //WHAT OBJECT DO I RETURN HERE?
        String userName = "testUser";
        return userName;
    }
 
    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest arg0) {
        return null;
    }
 
    public int getOrder() {
        return org.springframework.security.ui.FilterChainOrder.PRE_AUTH_FILTER;
    }
 
}

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 14

Expert Comment

by:boonleng
ID: 24093420
Correct, the "getPreAuthenticatedPrincipal()" is returning the username.

For the UserDetailsService, you need to implement "AuthenticationUserDetailsService" rather then "UserDetailsService" coz using class "PreAuthenticatedAuthenticationProvider" as provider. Class "UserDetailsService" is use by DatabaseAuthenticationProvider.

The following is the sample UserDetailsService:
public class BtdUserDetailsService implements AuthenticationUserDetailsService {
 
    public UserDetails loadUserDetails(Authentication authentication)
            throws UsernameNotFoundException {
        String username = (String) authentication.getPrincipal();
        
        User user = userService.findByUserId(userName);
        
        return user;
    }
}

Open in new window

0
 
LVL 14

Accepted Solution

by:
boonleng earned 500 total points
ID: 24093435
For the class "PreAuthenticatedProcessingFilter", the method getPreAuthenticatedCredentials() cannot return null as "PreAuthenticatedAuthenticationProvider" will verify the credential and if null it will throw exception. Just return empty string or any wording.
0
 

Author Comment

by:intlgd
ID: 24098736
Hello booleng,

You rock my friend!!!! Thanks so much for your help. I've attached my latest configuration for anyone else out there struggling with this. Good luck to all out there setting up Spring security.

Jared

---In your web.xml add this:
...
    <!-- 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>
...
.
---In your spring-secutity.xml (or application-context.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:sec="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-2.5.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
 
    <bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/devMachineSetup*" filters="none"/>
			<sec:filter-chain pattern="/css/**" filters="none"/>
			<sec:filter-chain pattern="/js/**" filters="none"/>
            <sec:filter-chain pattern="/img/**" filters="none"/>
            <sec:filter-chain pattern="/**" filters="sif,preAuthenticatedProcessingFilter,logoutFilter,fsi"/>
        </sec:filter-chain-map>
    </bean>
 
    <!-- Filter # 1 -->
    <bean id="sif" class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>
 
    <sec:authentication-manager alias="authenticationManager" />
 
    <sec:authentication-provider user-service-ref='userDetailsService'/>
 
    <bean id="userDetailsService" class="com.cisco.btd.security.BtdUserDetailsService">
        <property name="userService" ref="userService"/>
    </bean>
 
    <bean id="preAuthenticatedProcessingFilter" class="com.cisco.btd.security.PreAuthenticatedProcessingFilter">
        <sec:custom-filter position="PRE_AUTH_FILTER" />
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>
 
    <bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
        <sec:custom-authentication-provider />
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper" class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userDetailsService" />
            </bean>
        </property>
    </bean>
    
    <!-- Handle logout -->
    <bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <constructor-arg value="/"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>
 
    <bean id="httpRequestAccessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
    </bean>
 
    <bean id="fsi" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource">
            <sec:filter-invocation-definition-source>
                <sec:intercept-url pattern='/system/**' access='ROLE_SUPER' />
                <sec:intercept-url pattern='/admin/**' access='ROLE_ADMIN' />
                <sec:intercept-url pattern='/**' access='ROLE_BASIC' />
            </sec:filter-invocation-definition-source>
        </property>
    </bean>
 
    <bean id="roleVoter" class="org.springframework.security.vote.RoleVoter"/>
 
    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter">
        <property name="wrapperClass" value="org.springframework.security.wrapper.SecurityContextHolderAwareRequestWrapper"/>
    </bean>
 
</beans>
.
----Create a custom pre-auth filter
public class PreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        return "loggedInUser";
    }
    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return "";
    }
    public int getOrder() {
        return org.springframework.security.ui.FilterChainOrder.PRE_AUTH_FILTER;
    }
}
.
---Create a custom userDetailsService (if desired)
.
public class BtdUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
 
      //This is a org.springframework.security.userdetails.UserDetails object (extend as needed - I extended it an the roles)
      return new UserDetails(...);
    }

Open in new window

0

Featured Post

Major Serverless Shift

Comparison of major players like AWS, Microsoft Azure, IBM Bluemix, and Google Cloud Platform

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
The viewer will learn how to implement Singleton Design Pattern in Java.
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

635 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question