6

I want to integrate Spring Social facebook into my application with Spring Security (I use xml configurations). All I need is just connect facebook account with my app's account. In simple example I found this:

<bean id="connectionRepository" factory-method="createConnectionRepository" 
      factory-bean="usersConnectionRepository" scope="request">
    <constructor-arg value="#{request.userPrincipal.name}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>

So, as I understood, this method comes into play:

public ConnectionRepository createConnectionRepository(String userId) {
        if (userId == null) {
            throw new IllegalArgumentException("userId cannot be null");
        }
        return new JdbcConnectionRepository(userId, jdbcTemplate, connectionFactoryLocator, textEncryptor, tablePrefix);
    }

It resives "userId" from #{request.userPrincipal.name}. So, my question: How can I pass "userId" to this method if I want to obtain this "userId" using SecurityContextHolder.getContext().getAuthentication().getPrincipal().

The only way I see is to create my implementation of JdbcUsersConnectionRepository and redefine createConnectionRepository(String userId) method. But maybe there is more elegant solution.

Harshal Patil
  • 6,659
  • 8
  • 41
  • 57
chaldaean
  • 1,222
  • 2
  • 13
  • 24

1 Answers1

7

There is another way:

<bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository"
    scope="request">
    <constructor-arg value="#{authenticationService.getAuthenticatedUsername()}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>

@Service("authenticationService")
public class AuthenticationService {

    public String getAuthenticatedUsername() {
        return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

}

You can do it complitely in SPeL too (I do not like this kind of dependencies):

<bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository"
    scope="request">
    <constructor-arg value="#{T(org.springframework.security.core.context.SecurityContextHolder).getContext().getAuthentication().getPrincipal()}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>
Maksym Demidas
  • 7,707
  • 1
  • 29
  • 36
  • In Spring Social 1.0.x, the SpEL is the best way (albeit a bit cumbersome). In Spring Social 1.1.0 there's a new XML-based configuration namespace and a UserIdSource interface. You implement UserIdSource to lookup the user ID (however you see fit) and configure it as a bean. The XML config elements will look for that UserIdSource and use it. – Craig Walls Apr 10 '13 at 14:11
  • FWIW, the fact that SpEL expressions are just strings and thus aren't easily testable or necessarily typesafe is the main reason they feel kludgy here. But by virtue of the fact that you're choosing XML for configuration, you've already decided against a typesafe configuration option. Which has me wondering why you would not want to use Java configuration, which is the more powerful and typesafe option for configuring Spring? – Craig Walls Apr 10 '13 at 14:13
  • Thank for your clarification Craig. UserIdSource interface is a good news (we need to wait for 1.1.0.RELEASE to be able use it in production code). For you second question: the reason is simple. We have a project that already use xml based config for Spring and Spring Security (framework beans). Annotations are used only for appllication's beans. I think it will be more conviniet for support team to have all config stuff in one format (xml). There is no way to do java conf with Spring Security AFAIK. – Maksym Demidas Apr 10 '13 at 16:36
  • You are correct that there's no easy way (yet) to do Spring Security configuration in JavaConfig. My choice then would still be to do as much auto-configuration (component-scanning/auto-wiring) as possible, use JavaConfig for as much as you can for things that you must explicitly configure, and only use XML configuration in cases where JavaConfig isn't practical (e.g., Spring Security). That said, Spring Security 3.2.0.M1 has some initial support for JavaConfig--so that's coming in Spring Security 3.2.0. – Craig Walls Apr 11 '13 at 13:44
  • @Maksym, I used your solution but I faced with another problem. SecurityContextHolder.getContext().getAuthentication() returns me null. In others methods where I use SecurityContextHolder, all is ok. As I understood the problem lies somewhere in security filters. If you know how to solve this I would appreciate it. – chaldaean Apr 12 '13 at 11:08
  • By default Spring Security will create anonymous session for each anonymous user. May be this feature is turned off in your security xml? For example via – Maksym Demidas Apr 12 '13 at 12:04
  • The problem is that my "user" isn't anonymous. I login into my application before I use getAuthenticatedUsername(). SecurityContextHolder.getContext().getAuthentication() returns null only if I use it in context of getAuthenticatedUsername() method. – chaldaean Apr 12 '13 at 12:15
  • Just make a brakepoint in `SecurityContextImpl.setAuthentication(...)` method and find a cause in debug mode. – Maksym Demidas Apr 12 '13 at 12:21