11

I'm using spring-security with HTTP Basic Auth to secure a java webapp. In my webapp I need to get the current user's username and password to further authenticate them against another service. I can get hold of the username, but not the password.

I've tried using SecurityContextHolder.getContext().getAuthentication() to access this information as suggested here How can I get plaintext password from spring-security? but the password is returned as null.

How can I get hold of the password?

Thanks.

This is my applicationContext-security.xml

<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-3.0.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<sec:http authentication-manager-ref='authenticationManager'>
    <sec:intercept-url pattern="/spring/**" access="ROLE_USER" />
    <sec:http-basic />
</sec:http>

<bean id="basicAuthenticationFilter"
    class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
</bean>

<bean id="authenticationEntryPoint"
    class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
    <property name="realmName" value="Announcements Rest Realm" />
</bean>

<bean id="authenticationManager"
    class="org.springframework.security.authentication.ProviderManager">
    <property name="providers">
        <list>
            <ref local="authProvider" />
        </list>
    </property>
</bean>

<bean id="authProvider"
    class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="userDetailsService" />
</bean>

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
    <constructor-arg>
        <list>
            <sec:filter-chain pattern="/spring/**" filters="basicAuthenticationFilter" />
        </list>
    </constructor-arg>
</bean>

<sec:user-service id="userDetailsService">
    <sec:user name="admin" password="**" authorities="ROLE_USER, ROLE_ADMIN" />
    <sec:user name="user" password="**" authorities="ROLE_USER" />
</sec:user-service>

Community
  • 1
  • 1
ssloan
  • 2,226
  • 4
  • 26
  • 40

4 Answers4

27

I've figured it out.

I've changed my authentication manager config to use the authentication-manager element and added the attribute there:

<sec:authentication-manager alias="authenticationManager" erase-credentials="false">
    <sec:authentication-provider ref="authProvider" />      
</sec:authentication-manager>

I can then use SecurityContextHolder.getContext().getAuthentication().getCredentials() in my controller class to get the password.

Thanks for your help though Piotrek De

Ataur Rahman Munna
  • 3,887
  • 1
  • 23
  • 34
ssloan
  • 2,226
  • 4
  • 26
  • 40
  • Nice find. Didnt know about `erase-credentials="false"` – cowls Apr 10 '14 at 14:26
  • That's what I needed, although I am a bit concerned about security issues; but I see no other sensible way to avoid those issues. – Riccardo Cossu Feb 09 '16 at 09:06
  • Works well with LDAP login too. – romil gaurav Aug 25 '16 at 07:18
  • I use the following after setting erase0credentials=false Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication(); String username = loggedInUser.getName(); String password = loggedInUser.getCredentials().toString(); But still, receive the password as an empty string any advise ? – Ahmed Salem Mar 16 '20 at 08:14
0

Do you use remember me/run as/switch user? In such case, password is null (as described in a thread you've mentioned). Also, probably you have to use basic form authentication, (post request to the j_spring_security_check)

omnomnom
  • 8,911
  • 4
  • 41
  • 50
  • I'm not using remember me, run as or switch user as far as I'm aware (unless they're enabled by default? I'm not using auto-config). Also I can't use form authentication as my webapp is a web service. – ssloan Feb 29 '12 at 12:00
  • ok, so how do you inform SI that user has been successfully authenticated? If you use SecurityContextHolder.getContext().setAuthentication(...), then what kind of token do you pass? – omnomnom Feb 29 '12 at 12:21
  • I'm not calling setAuthentication() directly - it must be happening in one of the beans I've configured. I'll update my post with my applicationContext-security.xml incase that helps. – ssloan Feb 29 '12 at 13:27
  • I've just tried setting it up with form based authentication instead and SecurityContextHolder.getContext()getAuthentication().getCredentials() still returns null. – ssloan Feb 29 '12 at 14:11
  • as a form-based, you mean POST to j_spring_security_check? – omnomnom Feb 29 '12 at 14:47
  • Yes. But I think I'm getting to the bottom of things now. The authenticationManager has a property called eraseCredentialsAfterAuthentication which I set in the beans config and this does what I expect for my authenticationManager. However, my authenticationManager seems to be the parent of another authenticationManager which doesn't have this setting so the credentials are still getting erased. – ssloan Feb 29 '12 at 15:41
0

If you are setting the entire details of the current user including password in session object, then you can get the password from that session object.

Tino M Thomas
  • 1,676
  • 2
  • 16
  • 24
  • The only thing that's in the session is the same object that comes back from getAuthentication, and again the getcredentials() method returns null. – ssloan Feb 29 '12 at 12:17
  • 1
    This won't work by default from Spring 3.1 onwards - the credentials are erased on successful authentication. See http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#core-services-erasing-credentials – Rori Stumpf May 06 '12 at 20:52
0

a better way is to implement your 'userDetailsService'. so you can control how the UserDetails could be inited when doing authentication. i implemented a form-based authentication and wrote my self-defined user service,

@Service("userService")
public class UserServiceImpl extends GenericService<User> implements UserDetailsService,UserService{



    @Override
        @Transactional
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
               // Declare a null Spring User
            UserDetails userDetails = null;



            // Search database for a user that matches the specified username
            // You can provide a custom DAO to access your persistence layer
            // Or use JDBC to access your database
            // DbUser is our custom domain user. This is not the same as Spring's User
            User dbUser=this.findUserByUserName(username);

            if (dbUser == null) {
                throw new UsernameNotFoundException("HiMVC Security:: Error in retrieving user(username=" + username + ")");
            }



            userDetails = new org.springframework.security.core.userdetails.User(
                    dbUser.getUserName(),
                    dbUser.getPassword(),//here you can put a clear text password
                    true,
                    true,
                    true,
                    true,
                    loadUserAuthorities(username));


            return userDetails;
        }
horaceman
  • 375
  • 1
  • 5
  • But this way, you're getting the password from a database which should be (hopefully) just a hash, right? So it's useless for the OP's intended usage (further authentication against a 3rd party service). He would need the password sent in an HTTP request. – David Ferenczy Rogožan Jun 27 '19 at 16:40