Solved

Using spring security to handle pre-authenticated user.

Posted on 2009-04-06
6
20,950 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
  • 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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
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

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

I had a project requirement for a displaying a user workbench .This workbench would consist multiple data grids .In each grid the user will be able to see a large number of data. These data grids should allow the user to 1. Sort 2. Export the …
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
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.

707 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now