Solved

Using spring security to handle pre-authenticated user.

Posted on 2009-04-06
6
21,082 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
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
nested class vs inner class 5 58
Tools or ways to handle development of complex web applications 4 101
eclipse shortcuts 9 45
eclipse apache tomcat admin console 50 55
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…
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.

920 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

17 Experts available now in Live!

Get 1:1 Help Now