Do want to get a better understanding of Spring web application architecture? If so, get started right now!

Adding Social Sign In to a Spring MVC Web Application: Configuration

Social Media Keyboard

In the good old days users logged in by using the combination of username and password. Although nowadays some people still prefer the traditional way, a growing number of users want to sign in by using their social media accounts.

This is a what makes Spring Social (and its sub projects) an useful addition to the Spring project portfolio. However, integrating Spring Social with Spring Security has been a bit cumbersome.

Spring Social 1.1.0 changes all this. It provides seamless integration with Spring Security, and the Java configuration support of Spring Security makes the configuration feel like a walk in the park.

You don’t have to take my word for it. Keep on reading and you will learn how this is done.

The requirements of our solution are the following:

  • It must be possible to create an user account by using a normal registration form.
  • It must be possible to create an user account by using a social sign in.
  • It must be possible to login by using username and password.
  • It must be possible to login by using a SaaS API provider.
  • The application must support Facebook and Twitter.
  • The application must use “regular” Spring MVC controllers (no REST).

Let’s start by taking a look at the prerequisites of this tutorial.

Prerequisites

This tutorial assumes that you have already created the Facebook and Twitter application used by the example application. You can create these applications by following these links:

If you don’t know how to do this, you can check out the following links:

Let’s move on and find out how we can get the required dependencies with Maven.

Getting the Required Dependencies with Maven

The first thing that we have to do is to get the required dependencies with Maven. We can do this by declaring the following dependencies in our POM file:

  • Spring Security (version 3.2.0.RELEASE).
    • The core module contains core authentication and and access control components.
    • The config module contains the code used to parse XML configuration files using the Spring Security XML namespace.
    • The taglibs module contains the Spring Security JPS tag libraries.
    • The web module contains filters and all other code related to web security.
  • Apache HttpClient (version 4.3.2). Apache HttpClient is an optional dependency (but recommended) dependency of Spring Social. If it is present, Spring Social will use it as a HTTP client. If not, Spring social will use the standard Java SE components.
  • Spring Social (version 1.1.0.RELEASE).
    • The config module contains the code used to parse XML configuration files using the Spring Social XML namespace. It also adds support for Java Configuration of Spring Social.
    • The core module contains the connect framework and provides support for OAuth clients.
    • The security module integrates Spring Security with Spring Social. It delegates the authentication concerns typically taken care by Spring Security to service providers by using Spring Social.
    • The web module contains components which handle the authentication handshake between our web application and the service provider.
  • Spring Social Facebook (version 1.1.0.RELEASE) is an extension to Spring Social and it provides Facebook integration.
  • Spring Social Twitter (version 1.1.0.RELEASE) is an extension to Social Social which provides Twitter integration.

The relevant part of the pom.xml file looks as follows:

<!-- Spring Security -->
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-core</artifactId>
	<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-config</artifactId>
	<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-taglibs</artifactId>
	<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-web</artifactId>
	<version>3.2.0.RELEASE</version>
</dependency>

<!-- Use Apache HttpClient as HTTP Client -->
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.3.2</version>
</dependency>

<!-- Spring Social -->
<dependency>
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-config</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-core</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
<dependency>     
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-security</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-web</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
 
<!-- Spring Social Facebook -->
<dependency>
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-facebook</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
 
<!-- Spring Social Twitter -->
<dependency>
	<groupId>org.springframework.social</groupId>
	<artifactId>spring-social-twitter</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>
Our application has other dependencies as well. For example, it uses Spring Framework 4.0.0.RELEASE, Spring Data JPA 1.4.3, and Hibernate 4.2.4.Final. These dependencies are left out from the dependency listing for the sake of clarity. You can get the full list of dependencies from Github.

You might also want to read the following documents which give you more information about the dependencies of the frameworks discussed in this blog post (Spring Security and Spring Social):

Next we have to create a properties file for the configuration properties of our application. Let’s find out how this is done.

Creating the Properties File

We can create the properties file by following these steps:

  1. Create a file called application.properties and ensure that it is found from the classpath.
  2. Configure the database connection.
  3. Configure Hibernate.
  4. Add the Facebook application id and application secret to the properties file.
  5. Add the Twitter consumer key and consumer secret to the properties file.

The contents of the application.properties file looks as follows:

#Database Configuration
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/socialtwitter
db.username=socialtwitter
db.password=password

#Hibernate Configuration
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.format_sql=true
hibernate.hbm2ddl.auto=validate
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=false

#Facebook
facebook.app.id=foo
facebook.app.secret=bar

#Twitter
twitter.consumer.key=foo
twitter.consumer.secret=bar

Before we can configure our application, we have to create a few common components. Let’s find out what these components are, and how we can create them.

Creating the Common Components

We have to create three components which are used during the authentication process. These components are:

  • We have create a class which contains the user details of an authenticated user.
  • We have to create a class which implements the UserDetailsService interface. This class is used to load user information when the user uses form login.
  • We have to create a class which implements the SocialUserDetailsService interface. This class is used to load user information when the user uses social sign in.

Let’s move on and find out how we can implement these classes.

Creating the User Details Class

We have to take the following requirements into account when we are creating the class which contains the user details of the authenticated user:

  • The class which stores the user details of a user who uses form login must implement the UserDetails interface.
  • The class which stores the user details of a user who uses social sign in must implement the SocialUserDetails interface.

Spring Social has a SocialUser class which fulfils both of these requirements. However, often we want to add application specific information to our user details class.

We can do this by following these steps:

  1. Create the user details class.
  2. Extend the SocialUser class.
  3. Add application specific fields to the created class. The application specific fields of our example application are: id, firstName, lastName, role, and socialSignInProvider.
  4. Create a constructor which takes the username, password and a collection of granted authorities as parameters. Pass these parameters forward to the constructor of the SocialUser class.
  5. Create getters for application specific fields.
  6. Add an inner builder class which is used to build new ExampleUserDetails objects.

The source code of our user details class looks as follows:

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.social.security.SocialUser;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class ExampleUserDetails extends SocialUser {

    private Long id;

    private String firstName;

    private String lastName;

    private Role role;

    private SocialMediaService socialSignInProvider;

    public ExampleUserDetails(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

	//Getters are omitted for the sake of clarity.

    public static class Builder {

        private Long id;

        private String username;

        private String firstName;

        private String lastName;

        private String password;

        private Role role;

        private SocialMediaService socialSignInProvider;

        private Set<GrantedAuthority> authorities;

        public Builder() {
            this.authorities = new HashSet<>();
        }

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder id(Long id) {
            this.id = id;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Builder password(String password) {
            if (password == null) {
                password = "SocialUser";
            }

            this.password = password;
            return this;
        }

        public Builder role(Role role) {
            this.role = role;

            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.toString());
            this.authorities.add(authority);

            return this;
        }

        public Builder socialSignInProvider(SocialMediaService socialSignInProvider) {
            this.socialSignInProvider = socialSignInProvider;
            return this;
        }

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public ExampleUserDetails build() {
            ExampleUserDetails user = new ExampleUserDetails(username, password, authorities);

            user.id = id;
            user.firstName = firstName;
            user.lastName = lastName;
            user.role = role;
            user.socialSignInProvider = socialSignInProvider;

            return user;
        }
    }
}

The Role is a simple enum which specifies the “legal” user roles of our example application. Its source code looks as follows:

public enum Role {
    ROLE_USER
}

The SocialMediaService is an enum which identifies the SaaS API provider which was used when user created an user account to our example application. Its source code looks as follows:

public enum SocialMediaService {
    FACEBOOK,
    TWITTER
}

Implementing the UserDetailsService interface

We can create our own implementation of the UserDetailsService interface by following these steps:

  1. Create a class which implements the UserDetailsService interface.
  2. Add a UserRepository field to created class.
  3. Create a constructor which takes a UserRepository as a constructor argument and annotate the constructor with the @Autowired annotation.
  4. Implement the loadUserByUsername(String username) method of the UserDetailsService interface. The implementation of this method consists of following steps:
    1. Get the user by calling the findByEmail() method of the UserRepository interface. This method returns the user whose email matches with the username given as a method parameter.
    2. If the user is not found, throw a new UsernameNotFoundException.
    3. Create a new ExampleUserDetails object.
    4. Return the created object.

The source code of the RepositoryUserDetailsService class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class RepositoryUserDetailsService implements UserDetailsService {

    private UserRepository repository;

    @Autowired
    public RepositoryUserDetailsService(UserRepository repository) {
        this.repository = repository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = repository.findByEmail(username);

        if (user == null) {
            throw new UsernameNotFoundException("No user found with username: " + username);
        }

        ExampleUserDetails principal = ExampleUserDetails.getBuilder()
                .firstName(user.getFirstName())
                .id(user.getId())
                .lastName(user.getLastName())
                .password(user.getPassword())
                .role(user.getRole())
                .socialSignInProvider(user.getSignInProvider())
                .username(user.getEmail())
                .build();

        return principal;
    }
}

The UserRepository is a simple Spring Data JPA repository, and its source code looks as follows:

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

    public User findByEmail(String email);
}

The User is the only entity of our example application, and it contains the information of a user who has created user account to our example application. The relevant part of its source code looks as follows:

import javax.persistence.*;

@Entity
@Table(name = "user_accounts")
public class User extends BaseEntity<Long> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "email", length = 100, nullable = false, unique = true)
    private String email;

    @Column(name = "first_name", length = 100,nullable = false)
    private String firstName;

    @Column(name = "last_name", length = 100, nullable = false)
    private String lastName;

    @Column(name = "password", length = 255)
    private String password;

    @Enumerated(EnumType.STRING)
    @Column(name = "role", length = 20, nullable = false)
    private Role role;

    @Enumerated(EnumType.STRING)
    @Column(name = "sign_in_provider", length = 20)
    private SocialMediaService signInProvider;

    public User() {

    }

	//Getters and other methods are omitted for the sake of clarity.
}

Implementing the SocialUserDetailsService interface

We can implement the SocialUserDetailsService interface by following these steps:

  1. Create a class which implements the SocialUserDetailsService.
  2. Add a UserDetailsService field to the created class.
  3. Create a constructor which takes a UserDetailsService object as a constructor parameter, and annotate the constructor with the @Autowired annotation.
  4. Implement the loadUserByUserId(String userId) method of the SocialUserDetailsInterface.
  5. Get the correct UserDetails object by calling the loadUserByUsername() method and pass the user id as a method parameter. We can do this because our application uses the username of the user as the user id.
  6. Cast the returned object to SocialUserDetails object and return it.

The source code of the SimpleSocialUserDetailsService class looks as follows:

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.social.security.SocialUser;
import org.springframework.social.security.SocialUserDetails;
import org.springframework.social.security.SocialUserDetailsService;


public class SimpleSocialUserDetailsService implements SocialUserDetailsService {

    private UserDetailsService userDetailsService;

    public SimpleSocialUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException {
        UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
        return (SocialUserDetails) userDetails;
    }
}

That is all. We are now ready to configure the application context of our application. Let’s find out how we can do that.

Configuring the Application Context

This section describes how we can configure the application context of our example application by using Java configuration. The application context configuration has been divided into multiple configuration classes by following these guidelines:

  1. Each configuration class contains configuration which is associated with a specific part of our example application. This make it easy to find out the relevant configuration if we have to check something out or change something a few months (or years) after we created the initial configuration.
  2. The configuration has been divided in a way which makes it easy to write unit tests for the web layer by using Spring MVC Test. We will talk more about this in the third part of this tutorial where we will write unit tests for the web layer of our application.
  3. The configuration makes it easy remove dependencies to external resources when we are writing integration tests for our application. We will talk more about this in the fourth part of this tutorial which describes how we can write integration tests for our application.
If you want to use XML configuration, you can take look at the example application of this blog post which has a working XML configuration as well (no web.xml though).

Let’s start by configuring the persistence layer of our application.

Configuring the Persistence Layer

The persistence layer of our application stores the user account information and provides a way to access this information. This important for two reasons:

  • We can provide a way to sign in by using username and password.
  • We can store application specific information and link this information to the user who uses social sign in.

Let’s find out how we can configure it by using both Java configuration class.

The persistence layer of example application uses Spring Data JPA 1.3.4. I will keep this section as thin as possible. If you want to learn more about Spring Data JPA, you can read my Spring Data JPA tutorial. I have also written a book about Spring Data which should help you to get started in no time.

We can configure our persistence layer by following these steps:

  1. Create the configuration class and annotate the created class with the @Configuration annotation.
  2. Annotate the class with the @EnableJpaRepositories annotation and set the base package of our Spring Data JPA repositories.
  3. Enable the Spring transaction management by annotating the configuration class with the @EnableTransactionManagement annotation.
  4. Add an Environment field to the class and annotate the field with the @Autowired annotation. We don’t need to configure the properties file by using the @PropertySource annotation because it is already configured in the “parent” application context configuration class.
  5. Configure the data source bean. This bean provides database connections to the entity manager but it has also another purpose. It is used by Spring Social when it persists connections to the database and loads them from the database.
  6. Configure the transaction manager bean.
  7. Configure the entity manager factory bean.

The source code of the PersistenceContext class looks as follows:

import com.jolbox.bonecp.BoneCPDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableJpaRepositories(basePackages = {
        "net.petrikainulainen.spring.social.signinmvc.user.repository"
})
@EnableTransactionManagement
public class PersistenceContext {

    @Resource
    private Environment env;

    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();

        dataSource.setDriverClass(env.getRequiredProperty("db.driver"));
        dataSource.setJdbcUrl(env.getRequiredProperty("db.url"));
        dataSource.setUsername(env.getRequiredProperty("db.username"));
        dataSource.setPassword(env.getRequiredProperty("db.password"));

        return dataSource;
    }

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        entityManagerFactoryBean.setPackagesToScan({
	            "net.petrikainulainen.spring.social.signinmvc.common.model",
	            "net.petrikainulainen.spring.social.signinmvc.user.model"
	    });

        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
        jpaProperties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));
        jpaProperties.put("hibernate.hbm2ddl.auto", env.getRequiredProperty("hibernate.hbm2ddl.auto"));
        jpaProperties.put("hibernate.ejb.naming_strategy", env.getRequiredProperty("hibernate.ejb.naming_strategy"));
        jpaProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));

        entityManagerFactoryBean.setJpaProperties(jpaProperties);

        return entityManagerFactoryBean;
    }
}

Let’s move on and find out how we can create the security configuration for our application.

Configuring Spring Security

Spring Security provides authentication mechanism for users who uses either form login or social sign in, and it is also responsible of authorization.

We can configure Spring Security by following these steps:

  1. Create the configuration class and annotate the created class with the @Configuration annotation.
  2. Annotate the class with the @EnableWebSecurity annotation. This makes it possible to configure Spring Security by implementing the WebSecurityConfigurer interface.
  3. Ensure that our configuration class extends the WebSecurityConfigurerAdapter class which is a base class for creating WebSecurityConfigurer instances. After we have done this, we can customize the security configuration by overriding methods.
  4. Add an UserRepository field to the configuration and annotate the field with the @Autowired annotation.
  5. Override the configure(WebSecurity web) method of the WebSecurityConfigurerAdapter class. Ensure that Spring Security ignores requests made to static resources such as CSS and Javascript files.
  6. Override the configure(HttpSecurity http) method of the WebSecurityConfigurerAdapter class and implement it by following these steps:
    1. Configure form login by following these steps:
      1. Set the login page url to ‘/login’.
      2. Set the url which processes login form submissions to ‘/login/authenticate’.
      3. Set the login failure url to ‘/login?error=bad_credentials’.
    2. Configure the logout function by following these steps:
      1. Ensure that a cookie called JSESSIONID is deleted after logout.
      2. Set the logout url to ‘/logout’.
      3. Set the logout success url to ‘/login’.
    3. Configure url based authorization. The main point of this phase is to ensure that anonymous users can access all urls which are related to the sign in / registration process, and protect the rest of our application from anonymous users.
    4. Add the SocialAuthenticationFilter to the Spring Security filter chain. We can do this by creating a new SpringSocialConfigurer object and ensuring that this object is used when Spring Security is configured.
  7. Configure the PasswordEncoder bean which is used to hash the password of the user (if the user uses form registration and login). We can do this by creating a new BCryptPasswordEncoder object and returning the created object.
  8. Configure the UserDetailsService bean. We can do this by creating a new RepositoryUserDetailsService object and passing the UserRepository as a constructor argument.
  9. Override the configure(AuthenticationManagerBuilder auth) method of the WebSecurityConfigurerAdapter class. We use this method for configuring authentication requests if the user uses form login. Implement this method by following these steps:
    1. Pass the UserDetailsService bean to the AuthenticationManagerBuilder object given as a method parameter.
    2. Pass the PasswordEncoder bean to the AuthenticationManagerBuilder object given as a method parameter.
  10. Configure the SocialUserDetailsService bean. We can do this by creating a new SimpleSocialUserDetailsService object and passing the UserDetailsService bean as a constructor argument. This bean loads the user specific data when social sign in is used.

The source code of our application context configuration class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.social.security.SocialUserDetailsService;
import org.springframework.social.security.SpringSocialConfigurer;

@Configuration
@EnableWebSecurity
public class SecurityContext extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserRepository userRepository;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
                //Spring Security ignores request to static resources such as CSS or JS files.
                .ignoring()
                    .antMatchers("/static/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //Configures form login
                .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/login/authenticate")
                    .failureUrl("/login?error=bad_credentials")
                //Configures the logout function
                .and()
                    .logout()
                        .deleteCookies("JSESSIONID")
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login")
                //Configures url based authorization
                .and()
                    .authorizeRequests()
                        //Anyone can access the urls
                        .antMatchers(
                                "/auth/**",
                                "/login",
                                "/signup/**",
                                "/user/register/**"
                        ).permitAll()
                        //The rest of the our application is protected.
                        .antMatchers("/**").hasRole("USER")
                //Adds the SocialAuthenticationFilter to Spring Security's filter chain.
                .and()
                    .apply(new SpringSocialConfigurer());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10);
    }

    @Bean
    public SocialUserDetailsService socialUserDetailsService() {
        return new SimpleSocialUserDetailsService(userDetailsService());
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new RepositoryUserDetailsService(userRepository);
    }
}

Let’s move on and find out how we can configure Spring Social.

Configuring Spring Social

Spring Social provides integrations with SaaS API providers such as Facebook and Twitter. We can configure Spring Social by following these steps:

  1. Create the application context configuration class which implements the SocialConfigurer interface and annotate the created class with the @Configuration annotation. The SocialConfigurer interface declares callback methods which can be used to configure Spring Social.
  2. Annotate the class with the @EnableSocial annotation. This enables Spring Social and imports the SocialConfiguration configuration class.
  3. Add a DataSource field to the configuration class and annotate the field with the @Autowired annotation.
  4. Add the addConnectionFactories() method of the SocialConfigurer interface to the created configuration class. This method takes two method parameters which are described in the following:
    1. The first parameter is a ConnectionFactoryConfigurer object which can be used to register connection factories.
    2. The second parameter is an Environment object which represents the environment in which our example application is running.
  5. Implement the addConnectionFactories() method by following these steps:
    1. Create a new TwitterConnectionFactory object, and pass the consumer key and the consumer secret as constructor arguments.
    2. Register the created TwitterConnectionFactory object by calling the addConnectionFactory() method of the ConnectionFactoryConfigurer interface. Pass the created TwitterConnectionFactory object as a method parameter.
    3. Create a new FacebookConnectionFactory object, and pass the application id and the application secret as constructor arguments.
    4. Register the created FacebookConnectionFactory object by calling the addConnectionFactory method of the ConnectionFactoryConfigurer interface. Pass the created FacebookConnectionFactory object as a method parameter.
  6. Add the getUserIdSource() method of the SocialConfigurer interface to the created class. The UserIdSource object returned by this method is responsible of determining the correct account id of the user. Because our example application uses the username of the user as an account id, we have to implement this method by returning a new AuthenticationNameUserIdSource object.
  7. Add the getUsersConnectionRepository() method of the SocialConfigurer interface to the created class. This method takes a ConnectionFactoryLocator object as a method parameter and returns a UsersConnectionRepository object.
  8. Implement the getUsersConnectionRepository() method by following these steps:
    1. Create a new JdbcUsersConnectionRepository object and pass the following objects as constructor arguments:
      1. The first argument is a DataSource object. We pass the value of the dataSource field as the first method parameter.
      2. The second argument is a ConnectionFactoryLocator object. We pass the value of the connectionFactoryLocator method parameter as the second method parameter.
      3. The third parameter is a TextEncryptor object which encrypts the authorization details of the connection established between a SaaS API provider and our application. We create this object by calling the noOpText() method of the Encryptors class. This means that our example application stores these details as plaintext. This is handy during the development phase but we should not use it in production.
    2. Return the created object.
  9. Configure the ConnectController bean. The method which configures this bean has two parameters. The first parameter is the ConnectionFactoryLocator bean. The second parameter is the used ConnectionRepository bean. Pass these parameters as constructor arguments when you are creating a new ConnectController object.

The source code of our configuration class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.social.UserIdSource;
import org.springframework.social.config.annotation.ConnectionFactoryConfigurer;
import org.springframework.social.config.annotation.EnableSocial;
import org.springframework.social.config.annotation.SocialConfigurer;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;
import org.springframework.social.connect.web.ConnectController;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import org.springframework.social.security.AuthenticationNameUserIdSource;
import org.springframework.social.twitter.connect.TwitterConnectionFactory;

import javax.sql.DataSource;

@Configuration
@EnableSocial
public class SocialContext implements SocialConfigurer {

    @Autowired
    private DataSource dataSource;

    @Override
    public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
        cfConfig.addConnectionFactory(new TwitterConnectionFactory(
                env.getProperty("twitter.consumer.key"),
                env.getProperty("twitter.consumer.secret")
        ));
        cfConfig.addConnectionFactory(new FacebookConnectionFactory(
                env.getProperty("facebook.app.id"),
                env.getProperty("facebook.app.secret")
        ));
    }

    @Override
    public UserIdSource getUserIdSource() {
        return new AuthenticationNameUserIdSource();
    }

    @Override
    public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
        return new JdbcUsersConnectionRepository(
                dataSource,
                connectionFactoryLocator,
                Encryptors.noOpText()
        );
    }

    @Bean
    public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
        return new ConnectController(connectionFactoryLocator, connectionRepository);
    }
}

Our next step is to configure the web layer of our application. Let’s get to work.

Configuring the Web Layer

We can configure the web layer of our application by following these steps:

  1. Create the configuration class by following these steps:
    1. Extend the WebMvcConfigurerAdapter class.
    2. Annotate the created class with the @Configuration annotation.
  2. Ensure that all controller classes are found by annotating the class with the @ComponentScan annotation and setting the base packages of our controllers.
  3. Enable the annotation driven web mvc by annotating the class with the @EnableWebMvc annotation.
  4. Ensure that static resources are served by container’s default servlet.
    1. Configure the static resources by overriding the addResourceHandlers() method of the WebMvcConfigurerAdapter class.
    2. Ensure that requests made to static resources are delegated forward to the container’s default servlet. This is done by overriding the configureDefaultServletHandling() method of the WebMvcConfigurerAdapter class.
  5. Configure the exception resolver bean.
  6. Configure the ViewResolver bean.

The source code of the WebAppContext class looks as follows:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import java.util.Properties;

@Configuration
@ComponentScan(basePackages = {
        "net.petrikainulainen.spring.social.signinmvc.common.controller",
        "net.petrikainulainen.spring.social.signinmvc.security.controller",
        "net.petrikainulainen.spring.social.signinmvc.user.controller"
})
@EnableWebMvc
public class WebAppContext extends WebMvcConfigurerAdapter {

	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public SimpleMappingExceptionResolver exceptionResolver() {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();

        Properties exceptionMappings = new Properties();

        exceptionMappings.put("java.lang.Exception", "error/error");
        exceptionMappings.put("java.lang.RuntimeException", "error/error");

        exceptionResolver.setExceptionMappings(exceptionMappings);

        Properties statusCodes = new Properties();

        statusCodes.put("error/404", "404");
        statusCodes.put("error/error", "500");

        exceptionResolver.setStatusCodes(statusCodes);

        return exceptionResolver;
    }

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");

        return viewResolver;
    }
}

Let’s find out how we can tie this all together and create a “parent” application context configuration class for our application.

Tieing It All Together

The last application context configuration class has three responsibilities:

  1. It configures general components used throughout our example application.
  2. It ensures that the service classes of our application are found during the classpath scan.
  3. It is the root application context configuration class of our application.

We can create this configuration class by following these steps:

  1. Create the configuration class and annotate the created class with the @Configuration annotation.
  2. Ensure that our service classes are found during the component scan by annotating the class with @ComponentScan annotation and setting the base package of our services.
  3. Import the other application context configuration classes by annotating the class with the @Import annotation.
  4. Annotate the class with the @PropertySource annotation, and configure it to look for a properties file called application.properties from the classpath. This ensures that the configuration properties can be accessed in the imported application context configuration classes.
  5. Configure the MessageSource bean.
  6. Configure the PropertySourcesPlaceholderConfigurer bean.

The source code the ExampleApplicationContext class looks as follows:

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
@ComponentScan(basePackages = {
        "net.petrikainulainen.spring.social.signinmvc.user.service"
})
@Import({WebAppContext.class, PersistenceContext.class, SecurityContext.class, SocialContext.class})
@PropertySource("classpath:application.properties")
public class ExampleApplicationContext {

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

        messageSource.setBasename("i18n/messages");
        messageSource.setUseCodeAsDefaultMessage(true);

        return messageSource;
    }

    @Bean
    public PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

We have now configured the application context of our example application. However, we still have to configure our web application. Let’s see how we can do this by using Java configuration.

Configuring the Web Application

Our last step is to configure our example application. We can do this without web.xml as long as our application is deployed to a servlet 3.0 compliant container.

We can configure the web application by following these steps:

  1. Create a class which implements the WebApplicationInitializer interface.
  2. Configure our application by overriding the onStartup() method of the WebApplicationInitializer interface. We can implement this method by following these steps:
    1. Create the root context of the application and register the ExampleApplicationContext class to the created root context.
    2. Configure the dispatcher servlet.
    3. Configure character encoding filter.
    4. Configure the Spring Security filter chain.
    5. Configure Sitemesh.
    6. Add the context loader listener to the servlet context.

The source code of the ExampleApplicationConfig class looks as follows:

import org.sitemesh.config.ConfigurableSiteMeshFilter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.*;
import java.util.EnumSet;

public class ExampleApplicationConfig implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(ExampleApplicationContext.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);

        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);

        FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);
        characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

        FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
        security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

        FilterRegistration.Dynamic sitemesh = servletContext.addFilter("sitemesh", new ConfigurableSiteMeshFilter());
        sitemesh.addMappingForUrlPatterns(dispatcherTypes, true, "*.jsp");

        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
}

What is Next?

We have now successfully configured our example application by using Java configuration. This tutorial has taught us two things:

  • We learned how we can implement the components required by Spring Security and Spring Social.
  • We learned to integrate Spring Security and Spring Social by using Java configuration.

The next part of this tutorial describes how we can add registration and login functions to our example application.

As always, the example application of this blog post is available at Github.

If you want to learn more about Spring Social, you should read my Spring Social tutorial.

About the Author

Petri Kainulainen is passionate about software development and continuous improvement. He is specialized in software development with the Spring Framework and is the author of Spring Data book.

About Petri Kainulainen →

155 comments… add one

  • Looking forward to second part of tutorial…

    Reply
    • I start writing it tomorrow. I think that I can publish it next week.

      Reply
  • great post, helped me very much. I’m waiting for the next.

    obrigado

    Reply
    • I am happy to hear that I could help you out.

      Reply
  • Petri, I have made a pause in a Spring article writing, but you inspired me to return to this =)

    Reply
    • Hi Alexey,

      It is good to hear from you! Also, continue writing Spring articles. :)

      Reply
  • Great, I’m from Brazil and this post helped to understand spring’s configuration.

    congratulations

    Reply
    • Thank you! I appreciate your kind words.

      Reply
  • Hi Petri,

    nice detail articular. i am struggling to get this working, appreciate you help.

    1. i could not working, hence i configured below in xml then, at deployment it failed with below error

    exception
    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘socialAuthenticationFilter’ defined in ServletContext resource [/WEB-INF/spring/LBSWeb/security-config.xml]: Unsatisfied dependency expressed through constructor argument with index 2 of type [org.springframework.social.connect.UsersConnectionRepository]: Could not convert constructor argume
    nt value of type [com.sun.proxy.$Proxy198] to required type [org.springframework.social.connect.UsersConnectionRepository]: Failed to convert value of type ‘com.sun.proxy.$Proxy198 implementing org.springframework.social.connect.ConnectionRepository,java.io.Serializable,org.springframework.
    aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,
    org.springframework.aop.Spring
    Proxy,org.springframework.aop.framework.Advised’ to required type ‘org.springframework.social.connect.UsersConnectionRepository'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy198 implementing org.springframework.social.connect.ConnectionRepository,java.io.Serializable,
    org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.
    AopInfrastructureBean,
    org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.social.connect.UsersConnectionRepository]: no matching editors or conversion strategy found
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray
    (ConstructorResolver.java:702)

    hope you can help me out.

    Reply
    • Hi Sam,

      It seems that Wordpress ate your XML configuration. However, it seems that Spring cannot convert the constructor argument with index 2 to required type (UsersConnectionRepository). It is kind of hard to figure out what could be wrong without seeing the XML configuration file. Can you paste it to Pastebin?

      Also, have you compared the XML configuration of the example application to your application context configuration?

      The configuration files which are relevant to you are: exampleApplicationContext-social.xml and exampleApplicationContext-security.xml.

      Reply
  • Thank you for the quick revert.

    i posted the xml on Pastebin ‘ SamJay – spring social xml configuration issue’. i am using spring.social.version>1.1.0.M4

    actually i tried to make the configuration work as give by you. but for some reason social:jdbc-connection-repository did not work or recongnized, it failed to compiler with nodefine bean expectation for usersConnectionRepository, that’s why i switched to xml configuration at first place.

    i understand there are 2 place where usersConnectionRepository has being used (socialAuthenticationFilter and socialAuthenticationProvider ), i get the exception with socialAuthenticationProvider .

    thank you.

    Reply
    • For some reason I cannot find the XML from Pastebin by using the search term: ‘SamJay – spring social xml configuration issue’. Could you provide a direct link to it?

      By the way, this example assumes that you use Spring Social version 1.1.0.BUILD-SNAPHOT. The reason for this is that some classes which makes the configuration a lot simpler are not available in the version 1.1.0.M4.

      Reply
  • here is the link Petri.
    http://pastebin.com/uu9K2tJH

    i did try with the as is configuration given by you but it still does not pick the social:jdbc-connection-repository so its failed at deployment to JBoss.

    thanks.

    Reply
    • The reason why you cannot use Java configuration if you deploy to JBoss is that JBoss doesn’t support Spring Java configuration yet. Have you tried to deploy the application to Tomcat 7? It could be useful because this way you could figure out if this is a JBoss related problem.

      I noticed that you don’t set the value of the index attribute when you use the constructor-arg element. Have you tried to set it?

      Also, some of your configuration files use the old Spring versions (3.1). You should probably update them to the latest versions.

      Have you tried to update your Spring Social version to 1.1.0.BUILD-SNAPSHOT? If you would do that, you should be able to use my versions of the XML configuration files. This would make your application context configuration files easier to read and less brittle.

      Reply
  • thanks,
    i am not using Java configuration at all only old faction xml, and adding constructor-arg element also made no difference.

    i will deploy the app to the tomcat to eliminate the server.

    below has simile issue being discussed, but could not really help.
    http://forum.spring.io/forum/spring-projects/web/social/118162-exception-faced-while-migrating-social-s-java-based-configuration-style-to-xml-based

    thanks
    will write to you with update.

    Reply
    • After I read that discussion, I realized that is probably an AOP related issue. I noticed a small difference between your XML configuration file and a file mentioned in that thread. Have you tried to declare the JdbcUsersConnectionRepository bean as follows:

      
      <bean id="jdbcConnectionRepository"
      	class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository" 
      	primary="true" 
      	scope="singleton" >
      	<constructor-arg ref="dataSource" />
      	<constructor-arg ref="connectionFactoryLocator" />
      	<constructor-arg ref="textEncryptor" />
      	<aop:scoped-proxy proxy-target-class="false" />
      </bean>
      
      
      Reply
  • thanks, i tried that, but still get the same error,

    one other think i tried to get the Spring Social version 1.1.0.BUILD-SNAPHOT from.
    http://projects.spring.io/spring-social/core.html, but it also failed downloading the jar’s.

    dependencies>

    org.springframework.social
    spring-social
    1.1.0.BUILD-SNAPSHOT

    spring-snapshots
    Spring Snapshots
    http://repo.spring.io/snapshot

    true

    Reply
    • Hi,

      You can get the correct dependencies from the Spring snapshot repository by following these steps:

      1. Add the snapshot repository to your POM file (I assume that you did this).
      2. Use the groupId org.springframework.social (This was also right).
      3. Add the following modules to your POM: spring-social-core, spring-social-security, and spring-social-web.
      4. Add the required client modules to your POM.

      Check the POM file of the example application for more details about this.

      Also, It seems that the required modules are found from the snapshot repository. Perhaps the download failed because of a network issue or something.

      Reply
  • Hi Petri,
    deployment failed on tomcat 7 as well with same exception.

    Reply
    • I was expecting that. The problem is related to Spring AOP and not to the used server. I noticed that you answered to this thread.

      Let’s hope that you get an answer soon (I want to hear what the problem was)!

      Reply
  • Will keep you posted as soon as i get a answer.

    on a different note can you please enplane the below please.

    with the ConnectController, called back (redirect) into your app: GET /connect/facebook?code=xxx, which ends up with page not found.

    how should i capture the call back here and seamlessly integrate with the app

    Reply
  • Hi

    do u know the reason for this error please

    [ServerImpl] JBoss (Microcontainer) [5.0.1.GA (build: SVNTag=JBoss_5_0_1_GA date=200902231221)] Started in 1m:27s:96ms
    [STDOUT] WARN : org.springframework.social.connect.web.ConnectController – Exception while handling OAuth2 callback (The OAuth2 ‘state’ parameter doesn’t match.). Redirecting to facebook connection status page.

    Reply
  • Hi Petri,

    I have added /web-inf/jsp/js/app.js and web-inf/jsp/js/controller.js and updated
    layout.jsp with below includes.

    <script type="text/javascript" src="”>

    getting below errors in javascript console

    Refused to execute script from ‘http://localhost:8080/springsocialsignin/js/app.js’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled. login:1
    Refused to execute script from ‘http://localhost:8080/springsocialsignin/js/controller.js’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled. login:1

    do i need to update webapp? any pointers??

    sridhar

    Reply
    • Hi Sai,

      The problem is that tou put your Javascript files to WEB-INF/jsp/js/ directory, and servlet containers do not serve any content put to the WEB-INF directory.

      You can solve this by moving your Javascript files to the src/main/webapp directory. If you use the same approach which I used in the example application, you should move the app.js and controller.js files to the src/main/webapp/static/js/app directory and add the following code to the layout.jsp file:

      
      <script type="text/javascript" 
        src="${pageContext.request.contextPath}/static/js/app/app.js"></script>
      <script type="text/javascript" 
        src="${pageContext.request.contextPath}/static/js/app/controller.js"></script>
      
      

      I hope that this answered to your question.

      Reply
  • I think there is a dependency missing: spring-social-config

    Reply
    • You are right! Thanks for pointing this out. It seems that the spring-social-config module is a transitive dependency but I agree that it might be better to explicitly specify it (at least in this case). I will update the blog post and the example application.

      Reply
  • oops, forgot to say first, awesome article, thanks a lot for sharing :)

    Reply
    • Thanks! I appreciate your kind words.

      Reply
  • Hi petri, i’am newbie in spring. How to add your example source to my project in eclipse?
    Thank you

    Reply
    • Hi Davi,

      I haven’t been using Eclipse for several years but let’s see if I can help you out. Which Eclipse version are you using?

      Reply
  • Thank you for your reply. I’m using eclipse kepler.

    Reply
    • It seems that you should be able to do this by navigating to:

      File -> Import -> Browse to general -> Maven Projects

      This wiki page has more information about this (including screenshots).

      I hope that this solved your problem.

      Reply
  • Great, thank you. Great tutorial petri.

    Reply
  • uhmm. It’s should not be this complicated.

    Reply
    • I agree. It will be interesting to see if Spring Boot will be integrated with Spring Social.

      Reply
  • New to this , I am getting the following error when I import the code to the eclipse
    Error loading property file ‘/Users/akumar/Documents/development/tracks/git/spring-social-examples/sign-in/spring-mvc-normal/profiles/dev/socialConfig.properties’ (org.apache.maven.plugins:maven-resources-plugin:2.6:testResources:default-testResources:process-test-resources)

    Reply
    • You need to create the socialConfig.properties file yourself. This file contains the configuration of your Facebook and Twitter applications. See the README of the example application for more details about this.

      Reply
  • Hello, im having huge problems adopting new facebook api to our application. Before i knew ill have to add it, i’ve created normal spring security besed User management. But now i have to add facebook. With new Social Security have been added XML based configuration with UserIdSource etc. But i’ve no idea how to use it. Could you be so nice and also create tutorial for XML based configuration that can be adopted to already existing spring security projects :( ?
    Huge thx for all help.

    Reply
    • Hi,

      Have you checked out the XML configuration of the example application? It should help you get started if you want to configure your application by using XML.

      I was planning to describe it in this blog post as well but I noticed that the blog post would probably be too long. That is why I decided to skip it and provided a link to the XML configuration instead.

      If you cannot solve problem by reading the configuration files, let me know and I will write a brief description about the required steps.

      Reply
  • Hi Petri,

    I have managed to get the FB logging to work. Now i see that data are being populated to ‘userconnection’ table through ConnectController and when i disconnected from the service, the data from the table get deleted as well (hope the expected behavior).
    My query is:
    I have a table called ‘user’ which maintains the application form logging users information’s and authenticates via spring-security.
    What i want to figure out is, i would like to sync userconnection data which maintains FB user data with ‘user’ table which maintain the form application local user accounts. So in a situation where a client logging with a FB, i should be able to create an account in the site as well and pass that information (ex: a passwrod) via a mail. So that user has the ability to either use FB or site account.
    Can you please help me to understand am i thinking on the right direction? And what are the steps that i should do to achieve this.

    Thanks
    Sam

    Reply
    • Hi Sam,

      If your application uses email as username and you get the email address of the user from Facebook, you can create a row to the user table when a user signs in by using Facebook.

      The way I see this, you have two options:

      1. Modify the example application to create a new user account automatically (without rendering the registration form) when user signs in by using social sign in. However, I wouldn’t create the password automatically and send it to the given email address because email isn’t a secure way to transfer this kind of information. I would implement a password reset function which would allow the user to set his password. Read Troy Hunt’s blog post titled Everything you ever wanted to know about building a secure password reset feature for more details about this (it is not Spring specific). Also, if you have to support other social sign in providers, you might run into problems because all social sign providers do not return the email address.
      2. Modify the example application of this blog post to ask (and process) the password information even if the user is using social sign in.

      The first option provides a better user experience. The problem is that you cannot use it if your application has to support social sign in providers which don’t return the email address of the user or if you don’t use email address as the username.

      The second option is easier to implement but it can be annoying because often users expect that they don’t have to enter password information if they use social sign in.

      I hope that this answered to your question. If you need more advice about this, don’t hesitate to ask additional questions.

      Reply
      • HiPetri,

        Thank you very much for the detail explanation & ill go through the links you provided and get back to you on the outcome. I do want to support FB, Twitter, Googal+, hence need to check whether email is being returned by those services. but my current implementation does not use email as the username, yet i am able to get the username with below.

        Regarding the second point:
        i am not clear on this, what do you mean is; at the end of authentication success, inject a page to capture a password, is it?

        another query that i came across is,

        once the FB authentication is successful, default behaviors is, the flow returns to the facebookConnected.jsp. what is the configuration (bean) to allow the flow to be continued to the application since the user is now authenticated ?

        Thanks
        Saranga

        Reply
        • Hi Sam,

          First, I am not sure if you have tried the example application of this blog post but its registration flow goes like this:

          1. If the user is creating user account by using social sign in, the registration form has first name, last name, and email address fields.
          2. If the user is creating user account by using “normal registration”, the registration form has first name, last name, email address, password, and password verification fields.

          What I meant was that you could ask the password information from users who are using social sign in. If you want to know more about the registration flow of the example application, you should read my blog post titled Adding Social Sign In to a Spring MVC Web Application: Registration and Login.

          Second, have you integrated Spring Social with Spring Security or are you using only Spring Social?

          If you have integrated Spring Social with Spring Security, you can configure the AuthenticationSuccessHandler bean. If you are using Java configuration, you should take a look at this StackOverflow question.

          On the other hand, if you are using only Spring Social, you could try to set the url by calling the setPostSignInUrl() method of the ProviderSignInController class. I haven’t tested this though so I am not sure if this is the right way to handle this.

          Reply
          • Hi Petri,

            i am using the Spring Social with Spring Security and i have gone though your example which user xml, configuration.

            i have posted my 2 xml file here for your reference. http://pastebin.com/P6u6cpyv (social-security xmls). hope it will make sense.

            i am going through the clinks that you are given. i am stuck on what to do with when the authentication call back return to facebookConnected.jsp. i guess, i want to capture the callback and take the control to spring-security and let the application work flow proceed.
            as you can see, i have used default spring provided controller, i guess i need to overwrite this and configure a way to let the flow run through the application flow.

            thank you very much for your help.

            thanks
            saranga

          • Hi Sam,

            I just realized something. Do you use the url /auth/[provider] (in other words, for Facebook this url would be /auth/facebook) to start the social sign in flow or do you use the url /connect/[provider]?

            If you only want to authenticate the user, you should use the first url (/auth/[provider]) because requests send to that url are processed by the SocialAuthenticationFilter.

            I took a very quick look at your configuration files and they seemed to be fine.

  • I want to make a full example integrating spring social and spring security using MongoDB , i need some examples , links or tuorials that help me to achieve that. i don’t know the needed changes to make in order to use mongodb instead of mysql because the problem that i faced is that Spring Social project already provides a jdbc based connection repository implementation to persist user connection data into a relational database. i don’t know if this is only used by relational databases :(

    Reply
  • I am looking forward on using this solution for testing in my environment.
    As i have had no contact yet with sitemesh, here’s my question.
    How would i do sth. like this:
    https://groups.google.com/forum/#!topic/sitemesh3-users/KjxbrtC0fFI
    I think this work should be done in ExampleApplicationConfig, but i am stuck with this.
    Is there some easy solution to add things like ?

    Reply
  • Hi there, forget about my last post.
    I made a small change in “ExampleApplicationConfig” on setting up the sitemesh

    FilterRegistration.Dynamic sitemesh = servletContext.addFilter(“sitemesh”, new TagBundlerFilterForSite());
    sitemesh.addMappingForUrlPatterns(dispatcherTypes, true, “*.jsp”);

    While adding the new Class to the same package:
    public class TagBundlerFilterForSite extends ConfigurableSiteMeshFilter {
    public TagBundlerFilterForSite(){
    this.applyCustomConfiguration(new SiteMeshFilterBuilder());
    }
    @Override
    protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
    builder.addTagRuleBundle (new DivExtractingTagRuleBundle ());
    }
    }

    I can now do this:

    Template:

    JSP-Page:Some more data

    for me this really helps to use my template well, maybe u or others can use that.
    I know the setup on the constructor is a bad thing, but as i really tried to get this working, i was happy for now. If there is a better solution, let me know ! :)

    Reply
    • It is great to hear that you were able to solve your problem!

      Also, thanks for coming back and posting your solution to my blog. Now I know where to look if I need similar functionality (I have never needed it yet).

      Reply
  • Heh,
    This is really an awesome post.This will help me a lot.
    Can you please mail me the zip file of the complete code? I tried to copy the code and and run, but it’s not working. Am trying to remove errors since last 3 days, but not able to do so.
    Please help me out.
    Mail me as soon as possible.

    Reply
  • Hi petri,
    I have one doubt.How to set the anonymous user for authentication without xml configuration?

    Reply
    • Hi,

      If you are talking about the anonymous authentication support of Spring Security, it should be enabled by default. The default role of the anonymous user is ROLE_ANONYMOUS, and you can use this role when you specify the authorization rules of your application.

      Unfortunately I don’t how you can customize the anonymous authentication support without using XML configuration. :(

      Reply
  • Hello! I’m trying to follow this tutorial, but I have a problem downloading the dependencies.
    Can you help me out?

    Thanks

    The following artifacts could not be resolved: org.springframework.social:spring-social-config:jar:1.1.0.BUILD-SNAPSHOT, org.springframework.social:spring-social-core:jar:1.1.0.BUILD-SNAPSHOT, org.springframework.social:spring-social-security:jar:1.1.0.BUILD-SNAPSHOT, org.springframework.social:spring-social-web:jar:1.1.0.BUILD-SNAPSHOT, org.springframework.social:spring-social-facebook:jar:1.1.0.BUILD-SNAPSHOT: Failure to find org.springframework.social:spring-social-config:jar:1.1.0.BUILD-SNAPSHOT in http://repo.springsource.org/libs-milestone was cached in the local repository, resolution will not be reattempted until the update interval of spring-milestone has elapsed or updates are forced

    Reply
  • Please let me know if I’m misunderstanding, but it appears that this application permits a user to associate exactly one social-media account–of any type–with their application account, so that a user can’t associate both Facebook and Twitter accounts simultaneously. It appears that the SocialUserDetails interface has a massive flaw in that its getUserId() method takes no parameter specifying *which* social service for which we’re looking up the user’s identity. Did I overlook some out-of-band information to the persistence layer about which social network is being talked about (such as an injectable thread-local holder), or does is this entire setup limited to a single social-media association per user?

    Reply
    • You are right. If a user creates a user account by using Facebook, he cannot sign in by using Twitter (or associate a Twitter account with his local user account). However, it is possible to support multiple social sign in providers as well.

      I haven’t done this myself but I think that you can do this by following these steps:

      1. Modify the User entity and add support for multiple social sign in providers (this is required only if you want to store this information).
      2. Implement the UserIdSource interface and create a userId which contains the information required to identify the local user and the used social sign in provider.
      3. Implement the SocialUserDetailsService interface and ensure that it can handle the “new” userId (you have to parse the local username from userId and load the correct user).
      4. Use the “new” userId when you persist the connection between the user and the social sign in provider (See the javadoc ProviderSignInUtils class.

      If you have any further questions, don’t hesitate to ask them.

      Reply
  • Petri,

    I was looking around on the web to find out how to change the scope when doing a Facebook login authorization. I was looking to make the change in the configuration rather having to send a post with a hidden variable on the social login button.

    I see in SocialContext that we are adding the Facebook connection factory and it has a method to set the scope. I changed the scope and it does not change the scope on the authorization. Do you know how to change this at the configuration level?

    There is an “Authorization scope” section that explains how it is done but not at the configuration level.
    http://docs.spring.io/spring-social/docs/1.0.3.RELEASE/reference/html/connecting.html

    Have you done this before?

    Reply
    • I was able to verify that setting the scope by calling the setScope(String scope) method of the OAuth2ConnectionFactory class (FacebookConnectionFactory extends this class) doesn’t seem to do anything.

      Unfortunately I cannot provide an answer right away, but I promise that I will take a closer look at this because the Javadoc of that method suggests that it should work. I will let you know if I find a solution.

      Reply
      • I looked around tonight and did not find a way to set the scope but I did find that OAuth2AuthenticationService.defaultScope is really what is being used when it adds the scope to the URL. If you don’t pass a scope as a hidden variable it will use the defaultScope.

        Thanks again for always being so helpful.

        Reply
        • Petri,

          Have you found a work around for this? I have not. I tried looking through the source code and kept getting a little lost and did not find a path to set the scope.

          Reply
          • Hi,

            Actually I did found something from the web:

            It seems that if you want to set the default scope, you have to use the FacebookAuthenticationService class.

            The SecurityEnabledConnectionFactoryConfigurer object given as a method parameter to the addConnectionFactories() method of the SocialConfigurerinterface creates the required authentication service objects BUT it doesn’t set the default scope.

            I assume that if you want to set the default scope, you have remove the @EnableSocial annotation from the SocialContext class and create all required beans manually.

            I can take a closer look at this tomorrow.

          • I checked this out and I noticed one problem:

            I should create a ConnectionRepository bean but I am unable to do it because the ConnectionRepository class is package-private (and I don’t want to move the SocialContext class to the same package).

            You could of course configure Spring Social by using XML configuration but if you don’t want to do that, you should create a new issue to the Spring Social project.

          • Petri,

            Thanks again. I created a ticket. With your help I hope they have enough information to find the bug. I am a little lost.

            https://jira.spring.io/browse/SOCIAL-436

          • You are welcome! Let’s hope that the Spring Social team can solve this soon.

  • great post, helped me very much.

    Reply
    • I am happy to hear that.

      Reply
  • Hi Petri,
    I’m trying to implement spring-social-facebook in my application, however I’m stuck in the JdbcUsersConnectionRepository part. I would like to have my own UsersConnectionRepository using Hibernate but without JPA.

    Thanks much in advance

    Reply
    • The JdbcUsersConnectionRepository class uses the JDBC API. In other words, you can use it in an application which uses the “native” Hibernate API.

      You can of course create your own implementation by implementing the UsersConnectionRepository interface but I am not sure if it is worth the effort.

      Did you mean that you want to create a custom UserDetailsService which uses Hibernate instead of Spring Data JPA?

      Reply
  • HI Petri

    At the end of this tutorial I have an error with the servletContext.addServlet, servletContext.addFilter and servletContext.addListener … I´m workinh with Eclipse and the message that appear is “The method addListener(ContextLoaderListener) is undefined for the type ServletContext”.
    The solution tath Eclipse suggest me is “Add Cast to servletContext”

    What can I do?
    Thanks much in advance

    Reply
  • Hi Petri,

    Thank you very much for the detailed tutorials!
    I have a question that is similar to the one from Ademir. I would like to integrate spring social into my project however I don’t need any of the spring social persistence stuff and just seems to conflict with my application. All I really need is Spring Social’s Facebook methods. Is this possible to simplify the setup in this way?
    Any help would be greatly appreciated!

    Reply
    • Hi,

      Do you want that your application is able to read information from Facebook and write information to Facebook (and that is it)? If that is the case, you should read a tutorial titled Accessing Facebook Data. It should help you to get started.

      If that guide doesn’t solve your problem, let me know!

      Reply
  • hello my friend,
    i have a trouble to run this sample, in “” class on line 68 we have
    .apply(new SpringSocialConfigurer())
    but i get can’t resolve method ! i’m sure that i provide all maven dependencies correctly,
    then i tried to upgrade the “spring.security.version” to 3.2.4.RELEASE but the problem remains.
    whats the problem ?
    thanks.

    Reply
    • Are you getting a compilation error or a runtime error? Also, if you get a runtime error, it would be useful to see the stacktrace.

      Reply
      • hello again,
        when i start packaging app by using maven directly, i get rid of my first question, because that was just an IDE wrong alert.
        but now i have another problem after returning from facebook auth, the page redirected into
        http://localhost:8080/signin#_=_
        and i an error 404 will raise.
        of course i can’t find any controller matching /signin url
        why!?
        whats the problem you think ?
        thank you

        Reply
        • Hi, Petri
          can you help me on my question ?
          thanks

          Reply
        • Hi,

          Yes, I was wondering if your previous problem was an IDE alert because I used to see a similar alert in IntelliJ Idea. However, it disappeared after I updated it to a newer version.

          I assume that your problem occurs when a registered user tries to log in to your application (because of the url). If this isn’t the case, let me know.

          Anyway, you can configure the url in which the user is redirected after a successful login by following the instructions which I gave in this comment.

          Let me know if this doesn’t solve your problem.

          Reply
          • here is my changes

            
            protected void configure(HttpSecurity http) throws Exception {
               SpringSocialConfigurer springSocialConfigurer = new SpringSocialConfigurer();
               springSocialConfigurer.postLoginUrl("/myurl");
               ...
            }
            
            

            in http:/localhost:8080/login i click on Sign in With facebook then i redirected to
            facebook and have a successful login but it still redirected to
            http:/localhost:8080/signin#_=_

            here is statcktrace
            DEBUG – LoginController – Rendering login page.
            DEBUG – RequestAddCookies – CookieSpec selected: best-match
            DEBUG – RequestAuthCache – Auth cache not set in the context
            DEBUG – ttpClientConnectionManager – Connection request: [route: {s}->https:/graph.facebook.com:443][total kept alive: 0; route allocated: 0 of 5; total allocated: 0 of 10]
            DEBUG – ttpClientConnectionManager – Connection leased: [id: 0][route: {s}->https:/graph.facebook.com:443][total kept alive: 0; route allocated: 1 of 5; total allocated: 1 of 10]
            DEBUG – MainClientExec – Opening connection {s}->https:/graph.facebook.com:443
            DEBUG – ttpClientConnectionManager – Connecting to graph.facebook.com/173.252.112.23:443
            DEBUG – anagedHttpClientConnection – http-outgoing-0: Shutdown connection
            DEBUG – MainClientExec – Connection discarded
            DEBUG – anagedHttpClientConnection – http-outgoing-0: Close connection
            DEBUG – ttpClientConnectionManager – Connection released: [id: 0][route: {s}->https:/graph.facebook.com:443][total kept alive: 0; route allocated: 0 of 5; total allocated: 0 of 10]

          • sorry Petri,
            can i ask what url you expected to called after return from facebook ?
            which controller must catch the request and how can i get auth_token to get all friends of logged in user ?
            i have so many quastions, but at first i need to run application properly,
            i googling so much for some other examples but yours is best article ever.
            thanks again.

          • No problem. I happy to help but I am on summer holiday at the moment so my response time might be a bit longer than in a normal situation.

            Anyway, if you implement the registration and login functions as described in this blog post, the only urls you should care about are:

            • The sign up url. A user is redirected to this url when Facebook login is suggesful but a user account isn’t found from the database. The default value of the sign up url is ‘/signup’. You can override this by using XML configuration. At the moment it isn’t possible to override this url if you use Java configuration.
            • The post login url. A user is redirected to this url when Facebook login is successful and a user account is found from the database. You can change this url by following the instruction given in my last comment.

            I have never experienced a situation where the user would have been redirected to the ‘/signin’ url, so I am not sure how you can solve this problem (The log you added to your comment doesn’t reveal anything unusual).

            I think that the easiest to way to solve this problem is to compare the configuration of your application with the configuration of my example application. Unfortunately it is impossible to figure out the root cause without seeing the source code of your application.

            About your second question: I have never used Spring Social Facebook for accessing user’s Facebook data (such as list of friends), so I don’t know how you can do it. I think that your best bet is to read this guide which explains how you can create a simple web application that reads data from Facebook.

          • excuse me Petri,
            i found that my server doesn’t have an access to graph.facebook.com:443
            this make’s the problem, after i resolve this issue now have a null pointer exception at
            org.springframework.social.security.SocialAuthenticationFilter.doAuthentication(SocialAuthenticationFilter.java:301)

            Authentication success = getAuthenticationManager().authenticate(token);
            and getAuthenticationManager(). return null value !
            do you have any suggestion ?
            thanks you for your replies,

          • Have you configured the AuthenticationManager bean?

            You can do this by overriding the protected void configure(AuthenticationManagerBuilder auth) method of the WebSecurityConfigurerAdapter in the SecurityContext class (assuming that your configuration is similar than mine).

          • finally, all thing worked together successfully.
            thanks for all of your advises.
            have a good holidays.

          • Thanks! It is good to hear that you were able to solve your problem.

  • Hi in RepositoryUserDetailService I am getting error “The method getBuilder() is undefined for the type ExampleUserDetails”…Please Help anyone..

    Reply
  • hello Peter.. thank your for this article.. can u create a video tutorial for this article..?

    Reply
    • Hi,

      That is a great idea. I will add this to my Trello board, and I will record the video tutorial in the future.

      Reply
  • I’m using your example and my question is where the method is implemented
    public User findByEmail(String email);?? i dont see (interface UserRepository.class)

    Reply
    • The findByEmail(String email) is a custom query method which is found from the UserRepository interface. This has been explained in the section titled ‘Implementing the UserDetailsService interface’. You can also get the source code of the UserRepository interface from Github.

      Reply
      • yes, but I do not see where is the implementation of the method, see the calling but where is the implementation?

        Reply
      • I really doubt that userRepository class implements the interface for the method to work findByEmail

        sorry for my English

        thanks!!

        Reply
        • The example application uses Spring Data JPA which provides a proxy implementations for each interface which extends the Repository interface. That is why there is no need to implement the UserRepository interface.

          Reply
  • Hi Petri,

    I in the process of implemented Spring Security & Spring Social for the website and also would like to allow for the iOS and Android apps to connect via the social as well. Idea i had in mind is to have the centralised api expose in web end and let it handle the social signup/sing in process where mobile end only connect to this api.

    Can you please help me on modelling such and how should i go on about this.

    Thanks

    Reply
    • Hi Sam,

      I have never done this myself (surprising but it is the truth).

      However, I found an answer to StackOverflow question titled ‘Integrate app with spring social website’ which looks quite promising. The idea is that you have to first implement the social sign in by using the native APIs (Android, iOS) and then provide the required credentials to your backend and log the user in.

      I am planning to extend my Spring Social tutorial to cover REST APIs in the future. I will probably take a closer look at this when I do that.

      Reply
      • Thanks Petri. Look forward to it.

        Reply
  • Hi Petri,
    Thank you for your quick response. I tried working with maven but facing below issue. Can you please help me to look into this issue.

    [INFO] ————————————————————————
    [INFO] BUILD FAILURE
    [INFO] ————————————————————————
    [INFO] Total time: 4.906 s
    [INFO] Finished at: 2014-07-09T15:47:17+05:30
    [INFO] Final Memory: 13M/154M
    [INFO] ————————————————————————
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:2.6:resources (defau
    lt-resources) on project spring-mvc-normal: Error loading property file ‘F:\workspace\login\profile
    s\dev\socialConfig.properties’ -> [Help 1]
    [ERROR]

    Reply
    • Hi Amit,

      the Maven build is a bit different than the setup described in this blog post. It expects to find socialConfig.properties file from the profiles/dev/ directory. This properties file contains the configuration of your Facebook and Twitter application (app id and app secret).

      Also, the example application doesn’t contain this file. This means that you have to create it yourself.The README of the example application explains how you can set up the example application before you can run it.

      I hope this answered to your question. If not, feel free to ask more questions!

      Reply
  • I deployed the project but not able to access registration page and also authentication page is not available. can you please provide me complete setup of this project to learn more.

    Reply
    • Did you follow the steps described in the README of the example application?

      If you did follow them, could you check the log and paste the relevant part of it here (also, if you see any stack traces, add them here as well)?

      Reply
      • I followed the steps as you have mentioned and getting the login page. But when i tried to login my url is this “http://localhost:8080/spring-social-normal-mvc/login” and after submitting the URL it redirects to “http://localhost:8080/login”. So, I feel the problem is redirecting the URL. It’s not redirecting properly. Also, After login with facebook the url redirects to “http://localhost:8080/spring-social-normal-mvc/signin#_=_” and it shows 404 error. Please let me know if i have to update anything more in configuration.

        Reply
        • I followed the steps as you have mentioned and getting the login page. But when i tried to login my url is this “http://localhost:8080/spring-social-normal-mvc/login” and after submitting the URL it redirects to “http://localhost:8080/login”.

          The reason for this is that the action attribute of the login form ignores the context path. You can fix this by replacing the form tag with this one:

          
          <form action="${pageContext.request.contextPath}/login/authenticate" 
                method="POST" 
                role="form">
          
          

          I made the fix to the example application. Thank you for reporting this bug.

          Also, After login with facebook the url redirects to “http://localhost:8080/spring-social-normal-mvc/signin#_=_” and it shows 404 error.

          Another reader had the same problem, and the reason for this behavior was that his server didn’t have access to the Facebook Graph API.

          Reply
          • Thank you Petri. It works…. cheers :)

          • I tried as mentioned above but still it redirects to same url. I pasted my console log. Please have a look and help me to fix this issue.

            DEBUG – ttpClientConnectionManager – Connection leased: [id: 0][route: {s}->https:/
            /graph.facebook.com:443][total kept alive: 0; route allocated: 1 of 5; total alloca
            ted: 1 of 10]
            DEBUG – MainClientExec – Opening connection {s}->https:/graph.facebook
            .com:443
            DEBUG – ttpClientConnectionManager – Connecting to graph.facebook.com/31.13.74.128:
            443
            DEBUG – anagedHttpClientConnection – http-outgoing-0: Shutdown connection
            DEBUG – MainClientExec – Connection discarded
            DEBUG – anagedHttpClientConnection – http-outgoing-0: Close connection
            DEBUG – ttpClientConnectionManager – Connection released: [id: 0][route: {s}->https
            :/graph.facebook.com:443][total kept alive: 0; route allocated: 0 of 5; total allo
            cated: 0 of 10]
            DEBUG – LoginController – Rendering login page.
            DEBUG – RequestAddCookies – CookieSpec selected: best-match
            DEBUG – RequestAuthCache – Auth cache not set in the context
            DEBUG – ttpClientConnectionManager – Connection request: [route: {s}->https:/graph
            .facebook.com:443][total kept alive: 0; route allocated: 0 of 5; total allocated: 0
            of 10]
            DEBUG – ttpClientConnectionManager – Connection leased: [id: 1][route: {s}->https:/
            graph.facebook.com:443][total kept alive: 0; route allocated: 1 of 5; total alloca
            ted: 1 of 10]
            DEBUG – MainClientExec – Opening connection {s}->https:/graph.facebook
            .com:443
            DEBUG – ttpClientConnectionManager – Connecting to graph.facebook.com/31.13.74.128:
            443
            DEBUG – anagedHttpClientConnection – http-outgoing-1: Shutdown connection
            DEBUG – MainClientExec – Connection discarded
            DEBUG – anagedHttpClientConnection – http-outgoing-1: Close connection
            DEBUG – ttpClientConnectionManager – Connection released: [id: 1][route: {s}->https
            :/graph.facebook.com:443][total kept alive: 0; route allocated: 0 of 5; total allo
            cated: 0 of 10]

          • Your log file looks pretty similar than farziny’s log.

            His problem was that his server could not access the Facebook Graph API. I am not exactly sure what he meant by that, but I assumed that either his FB application was not configured properly, or the app secret and app key were not correct.

            When you created the FB Application for your web application, did you enable the Facebook login?

          • Hi Petri,

            As, you said its blocking the facebook graph api, you were correct. I fixed the problem and working fine everything. You rocks dude…
            Trying to implement to get the post feed of user and friend list also. May be your help required in future again. So, thanks a lot in advance.

  • Hi Petri,
    Nice article!!
    I have followed exactly the same steps as described here and can go to facebook login page from my apps login page (by clicking on facebook link).After fb login , the app lands back to the apps login page with the url appended with ‘#_=_’ e.g. ‘http://localhost:8080/MyApp/#_=_’.

    Actually I expected the registration page will be displayed instead.SocialUserService::loadUserByUserId() is not getting called as I put some sop there.

    Any hints?

    Best regards,
    Pradeep

    Reply
    • my own mistake, forgot adding /usr/register twith permitAll() in security context.
      Can see the register form now.

      Reply
      • It is good to hear that you were able to solve your problem!

        Reply
        • Well the user registers now,I mean registration screen comes and user details are saved to my Candidate table but UserConnection table has no entries of this new user.So looks like some configuration error still there regarding SocialUserService since it’s loadUserByUserId() is still not called.

          My securitycontext.xml is:

          and social.xml is

          My databasecontext.xml has the rest:

          3 ? request.getRequestURI().split(‘/’)[3] : ‘guest’}” />

          Any hints for this problem?

          Reply
          • Wordpress ate your XML configuration but I happen to have an idea what might be the problem. You have to persist the user’s connection to the UserConnection table after the registration has been successful (and the user uses social sign in). You can do this by following the instructions given in the second part of this tutorial.

            However, please note that the static handlePostSignUp method of the ProviderSignInUtils class has been deprecated. You should use the doPostSignUp() method instead.

            I hope that this solves your problem.

          • That was a perfect hint!!
            Actually I have commented the call to ProviderSignInUtils.handlePostSignUp() thinking its not useful in my case.
            Thanks a lot :)

          • You are welcome. It is good to hear that you were able to solve your problem.

  • This article is not simple. It’s difficult to understand so please make simple example

    Reply
    • Unfortunately I have no idea how I could create a simpler example application since I think that the example application is already pretty simple.

      However, if you let me know which parts of this blog post were hard to understand, I can try to make them easier to understand.

      Reply
  • HI Petri,

    Logout is not working for facebook. It just redirecting to login page. How can I do logout in facebook.
    And for twitter I’m getting this error.

    org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable
    org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)

    Reply
    • Do you mean that log out function of my example application is not working, or are you trying to follow the instructions given in this blog post and cannot get the log out to work in your application?

      Also, do you mean that after the user clicks the log out link, the user is still logged in to the application and can access protected resources (such as the front page of my example application)?

      Reply
      • yes,
        when I do click on logout button it’s redirecting to login page. but when I try to open facebook.com it’s directly shows me home page.(It’s not asking me use name and password again) That means logut is not working properly.

        Reply
        • As far as I know, Spring Social doesn’t support this. However, there are a couple of workarounds which are described in the following forum discussions:

          I hope that this answered to your question. Also, remember that you have to use similar workarounds for other social sign in providers as well.

          Reply
          • Thanks Petri,
            There is one more issue in my application. when I do click on signin with twitter, I am getting following error. Am I missing something??

            org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable
            org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)

          • Thanks Petri,
            There is one more issue in my application. when I do click on signin with twitter, I am getting following error. Am I missing something??

            org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable
            org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)

          • Hi Petri,

            Find the solution. I was not setting callback URL in twitter that was the problem. But when I do login in twitter and when it’s successful it’s redirecting me to registration form. Why is so? do I need to change my callback URL?

          • Great! It is good to hear that you were able to solve your problem.

            The user is redirected to the registration page because either the user account or the persisted connection is not found from the database. This can be a bit confusing so I will explain it here:

            When a user “returns” to the example application after clicking a social sign button, Spring social tries to find the persisted connection from the UserConnection table.
            If the connection is not found, the user is forwarded to the registration page because the application assumes that the user doesn’t have a user account yet.

            On the other hand, if the connection is found, Spring Social tries to find the correct user account by using the value of the userId column (the example application uses email address as user id). If the user is not found, the user is forwarded to the registration page.

            I hope that this answered to your question.

            By the way, if you want to get more information about the social sign in flow, you should read the second part of this tutorial.

          • Thanks Petri.

            Thank you for help. Project is now working properly. :)

          • You are welcome. :)

  • Hello,
    I have a problem with facebook when I turn on HTTPS for /**. When user is redirected back from Facebook site after successful login, and after granting permissions for my app. It goes back to my SocialAuthenticationFilter and attemptAuthentication method. Everythink is ok for http, but with https this method is called one more time, and the user is already authenticated (in attemptAuthService()) so it tries to addConnection but token.principal is null so entire method returns null. In the end the AuthenticationServiceException(“authentication failed”) is thrown and user is redirected to defaultFailureUrl. I use XML version of your config.

    I tried to force http for /auth/** and it WORKS, but i don’t think it’s safe to transfer tokens on unsecured channel.

    Don’t know what to do :(

    Reply
    • When the user is redirected back to your web application, is the user redirected by using HTTP or HTTPS? The reason why I ask this is that I am using Spring Social in a web application that is served by using HTTPS, and the Facebook login is working correctly.

      I checked the Facebook application configuration of that web application and I noticed that I had entered the website url by using HTTPS (e.g. https://www.example.com instead of http://www.example.com). If I would be you, I would check the website url setting found from the Facebook application configuration and ensure that the website url setting has the ‘https’ prefix instead of ‘http’.

      Let me know if this solves your problem.

      Reply
    • Aww… I have finally figured it out. The problem was in my social configuration. I have added authenticationSuccessHandler (SavedRequestAwareAuthenticationSuccessHandler) with useReferer=true to my socialAuthenticationFilter.

      I have done that because I have bootstrap modal dialog with login form on every page and I wanted to redirect user to the same page after authentication. I had totally forgot about that.

      Reply
      • It is good to hear that you were able to solve your problem!

        Reply
  • Everytime a sql-query is placed it results in a 404 Error. For example I can load the main page without problems. But if I put

    User test = userRepository.findByEmail(“test”)
    somewhere in the code i get the 404 Error again. Also everytime I try to do something like login -> 404. From the logs i see the sql query which works fine if I copy it into phpmyadmin. Except for this logging I se nothing.

    If I place a logging before and after the query I only see the first one. I guess the query somehow crashes and produces a 404.

    I know 404 means not found but this does not make any sense.

    What can I do? Is there a way to turn up more loggings?

    I use Glassfish with the source provided from github.

    Reply
    • I have never tried to run this with Glassfish but I can try to figure out what is going on. Which version of Glassfish are you using?

      Reply
  • Is it possible to override the /auth/{providerId} path?

    I need to do this because I have multiple security chains and in one of them the social login is meant to do something a bit different and also direct you to somewhere a bit different to.

    Reply
    • Hi Ricardo,

      There is a way to override the url that is processed by the social authentication filter, but you have to make your own copies of the SpringSocialConfigurer and SocialAuthenticationFilter classes. I know that this is an ugly solution but unfortunately it seems that there is no other way to do this (yet?).

      The source code of the CustomSocialAuthenticationFilter class looks as follows (check the comments for more details):

      
      public class CustomSocialAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
      	
      	//Removed irrelevant code
      	
      	public CustomSocialAuthenticationFilter(AuthenticationManager authManager, 
      								UserIdSource userIdSource, 
      								UsersConnectionRepository usersConnectionRepository, 
      								SocialAuthenticationServiceLocator authServiceLocator) {
      		//Set the url that is processed by this filter
      		super("/newurl");
      		//Removed irrelevant code
      	}
      	
      	//Removed irrelevant code
      }
      

      The source code of the CustomSpringSocialConfigurer class looks as follows:

      
      public class CustomSpringSocialConfigurer extends SecurityConfigurerAdapter {
      
      	//Removed irrelevant fields.
      	
      	public SpringSocialConfigurer() {
      	}
      	
      	@Override
      	public void configure(HttpSecurity http) throws Exception {		
      		ApplicationContext appContext = http.getSharedObject(ApplicationContext.class);
      		UsersConnectionRepository usersConnectionRepository = getDependency(
      													appContext, 
      													UsersConnectionRepository.class
      		);
      		SocialAuthenticationServiceLocator authServiceLocator = getDependency(
      													applicationContext, 
      													SocialAuthenticationServiceLocator.class
      		);
      		
      		//Removed irrelevant code
      		
      		//Create your custom filter object
      		CustomSocialAuthenticationFilter filter = new CustomSocialAuthenticationFilter(
      				http.getSharedObject(AuthenticationManager.class), 
      				userIdSource != null ? userIdSource : new AuthenticationNameUserIdSource(), 
      				usersConnectionRepository, 
      				authServiceLocator);
      				
      		//Removed irrelevant code
      	}
      
              //Removed irrelevant code
      }
      
      

      After you have created these classes, you need configure your application to use them (modify either the exampleApplicationContext-security.xml file or the SecurityContext class).

      I haven't compiled these classes yet but you probably get the idea anyway. Also, I remember that I removed some irrelevant code to make the code sample more clear. This code must be present in your CustomSocialAuthenticationFilter and CustomSpringSocialConfigurer classes.

      I hope that this answered to your question.

      Reply
  • Hi Petri,

    I am using your demo. I have rename one table named “userconnection” to “mg_userconnection” . I have changed table named in script. But when I am redirecting to register page after social login it’s throws error like this. “bad SQL grammar [select userId from UserConnection where providerId = ? and providerUserId = ?]; nested exception”. My question is how can I rename that table name?

    Thanks.

    Reply
    • Hi Naitik,

      You can configure the table prefix by using setTablePrefix() method of the JdbcUsersConnectionRepository class.

      The SocialContext class implements the getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) method of the SocialConfigurer class. You can make the required modifications to this method. After you are done, the getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) method looks as follows:

      
      @Override
      public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator cfl) {
      	JdbcUsersConnectionRepository repo = new JdbcUsersConnectionRepository(
      			dataSource,
       			cfl,
       			Encryptors.noOpText()
      	);
      	repo.setTablePrefix("mg_");
      	return repo;
      }
      
      

      Now Spring Social is using the table mg_UserConnection instead of the UserConnection table. At the moment it is not possible to configure the “whole” name of this database table. In other words, if your database uses case sensitive table names, you cannot transform the name of created database table into lowercase.

      Reply
  • Hi Petri,
    with a little bit of customization I’ve this scenario:

    when a new user registered (not social) displays the phrase “You cannot create an user account because you are already logged in.”. but if I try to go to the home (index.jsp) I get an internal server error, maybe because the context is wrong.

    here the code of home button: <a href="">home</a>

    but if I use different path (/upload for example) all works fine (I’ve a controller)

    all works fine if I logout and login again whit the login form… the problem is for new registration only.

    can you help me?

    Reply
    • Hi Tiziano,

      I tested this out by following these steps:

      1. Log in as a user that is registered by using the “normal” registration.
      2. Navigate to the registration page.
      3. I see the error message “You cannot create an user account because you are already logged in”, and click the ‘Home’ link found from the header.

      The result is that I can see the home page in my browser. My home link looks as follows:

      
      <a href="/">
      	Home
      </a>
      
      

      However, this assumes that the application uses context path ‘/’. If you want to use another context path, you should create your link by using the following code:

      
      <a href="${pageContext.request.contextPath}/">
      	Home
      </a>
      
      

      Did I miss something? If so, let me know :)

      Reply
      • Thanks Petri,
        I forgot to tell you that I already use the contextPath tag. sorry…

        I obtain a generic error (500 error). with debug I see that creation time in Object principal (cast to UserDetails) is null inside database until I logout and login again.

        something miss in registration process?

        Reply
        • Did you remember to log the user in after the registration is completed? You should take a look at the controller method that processes the request created when the user’s submits the registration form.

          If you are logging the user in after registration, could you add the stacktrace found from the log file here? It is kind of hard to say what is going on without seeing any code or a log.

          Reply
  • Hi Petri,

    Thanks for posting this tutorial this is really good. I used your xml configuration with web.xml . it is unable to locate the bean of userConnectionRepository and connectionFactoryLocator. Below are the error what i am getting

    Cannot resolve reference to bean ‘usersConnectionRepository’ while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘usersConnectionRepository’ is defined.

    Reply
    • Thank you for pointing this problem out. I just noticed that the XML configuration is still using Spring profiles (I removed these profiles from the Java config). If you want to use the XML configuration, you should either

      1. Remove the <beans profile="application"> element and leave the other elements intact.
      2. Set the active Spring profile to ‘application’.

      I will remove the Spring profiles from the XML configuration when I have got time to do it. Again, thank you for pointing this out!

      Reply
      • thanks Petri for your great tutorial and quick response. I have one clarification that how user/provider is binded with registeration. i want to just persist the data and allow the user what should i do. More clear I dont want the registeration form in the case of social sign in.

        Reply
        • Hi,

          The second part of this tutorial explains how you can create a registration form that supports “normal” registration and registration via social sign in. If you have any other questions about the registration process, leave a comment to that blog post.

          Reply
  • thanks ,very usefully

    Reply
    • You are welcome! I am happy to hear that this blog post was useful to you.

      Reply
  • Hi,
    I cloned the repo from https://github.com/pkainulainen/spring-social-examples/tree/master/sign-in/spring-mvc-normal and executed the below command:
    mvn clean install
    It failed by giving the below error:

    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:2.6:resources (default-resources) on project spring
    -mvc-normal: Error loading property file ‘D:\Personal\BACKUP\Non-Cloud\Projects\workspace\petrikainulainen-spring-social-examples-
    master\sign-in\spring-mvc-normal\profiles\dev\socialConfig.properties’ -> [Help 1]
    [ERROR]

    Can you help? Thanks.

    Reply
    • Hi,

      you need to create a Facebook and a Twitter application before you can run the example application. Also, you need to create the socialConfig.properties file and configure the used social sign in providers in that file. The README of the example application provides more details about these steps.

      Reply
      • Hi Petri,

        Thanks for your prompt response. I finished first two parts of this tutorial and sincerely thank you for all your efforts in creating a top-quality example app. I am new to Java & Spring development and learned a lot by going through these two articles and the source code.

        I am able to run the app by “mvn jetty:run -P dev” now after reading the README file but facing few issues in which I need your help. I plan to create a tomcat-deployable WAR file so I did: mvn war:war -P dev, and came up with a WAR. Now things don’t work as they were working earlier:

        1. Once I Log in using my FB account, the app shows me a Welcome page. When I press the Logout button on that page, it takes me to http://localhost:8080/logout instead of the logout success URL: http://localhost:8080/login.

        2. Also, if I type http://localhost:8080/spring-mvc-normal/ again after logging out, I am able to see the Welcome page. That means user is still logged in my app as well as in FB.

        3. Both problems 1 & 2 are there when I create a new normal user (without FB etc).

        4. Create user account also doesn’t work now. It comes to http://localhost:8080/user/register and displays a blank page.

        I believe either the WAR is not getting created properly or Tomcat is not getting configured. Can you suggest what could the problem here? I found this link “http://maciejwalkowiak.pl/blog/2012/03/27/spring-3-1-profiles-and-tomcat-configuration/” but not sure whether it is relevant to my problem.

        Thanks once again for writing such a wonderful tutorial.

        Reply
        • I think that these problems are caused by the fact that the application assumes that it is run by using context path ‘/’. It seems that you are running it by using the context path ‘/spring-mvc-normal/’. Am I right?

          I thought that I already fixed this, but it seems that I didn’t fix it after all. Thank you for pointing this out!

          I will fix the JSP pages and commit my changes to Github.

          Update: I fixed the JSP pages. You can get the working example application from Github.

          Reply
          • Thanks Petri, you nailed down the problem. After pulling your last commit, I was able to run the app perfectly fine from Tomcat.
            BTW, I want to know whether there was a mistake in my running the app. Is it not the right way to launch when one would deploy the app in production environment?

          • You are welcome.

            The problem was that I didn’t think that it should be possible to run this application by using other context paths than ‘/’. In other words, it was a bug in the application (my mistake, not yours).

Leave a Comment