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:

  • [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    (Select “website with Facebook login” when you are asked how your application integrates with FB).
  • [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    (Enable the “allow this application to be used to Sign in with Twitter” checkbox).

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.RC1).
    • 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.2.5). 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.BUILD-SNAPSHOT).
    • 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.BUILD-SNAPSHOT) is an extension to Spring Social and it provides Facebook integration.
  • Spring Social Twitter (version 1.1.0.BUILD-SNAPSHOT) is an extension to Social Social which provides Twitter integration.

The relevant part of the pom.xml file looks as follows:
01 <!-- Spring Security -->

02 <dependency>

03 <groupId>org.springframework.security</groupId>

04 <artifactId>spring-security-core</artifactId>

05 <version>3.2.0.RC1</version>

06 </dependency>

07 <dependency>

08 <groupId>org.springframework.security</groupId>

09 <artifactId>spring-security-config</artifactId>

10 <version>3.2.0.RC1</version>

11 </dependency>

12 <dependency>

13 <groupId>org.springframework.security</groupId>

14 <artifactId>spring-security-taglibs</artifactId>

15 <version>3.2.0.RC1</version>

16 </dependency>

17 <dependency>

18 <groupId>org.springframework.security</groupId>

19 <artifactId>spring-security-web</artifactId>

20 <version>3.2.0.RC1</version>

21 </dependency>

22

23 <!-- Use Apache HttpClient as HTTP Client -->

24 <dependency>

25 <groupId>org.apache.httpcomponents</groupId>

26 <artifactId>httpclient</artifactId>

27 <version>4.2.5</version>

28 </dependency>

29

30 <!-- Spring Social -->

31 <dependency>

32 <groupId>org.springframework.social</groupId>

33 <artifactId>spring-social-core</artifactId>

34 <version>1.1.0.BUILD-SNAPSHOT</version>

35 </dependency>

36 <dependency>

37 <groupId>org.springframework.social</groupId>

38 <artifactId>spring-social-security</artifactId>

39 <version>1.1.0.BUILD-SNAPSHOT</version>

40 </dependency>

41 <dependency>

42 <groupId>org.springframework.social</groupId>

43 <artifactId>spring-social-web</artifactId>

44 <version>1.1.0.BUILD-SNAPSHOT</version>

45 </dependency>

46

47 <!-- Spring Social Facebook -->

48 <dependency>

49 <groupId>org.springframework.social</groupId>

50 <artifactId>spring-social-facebook</artifactId>

51 <version>1.1.0.BUILD-SNAPSHOT</version>

52 </dependency>

53

54 <!-- Spring Social Twitter -->

55 <dependency>

56 <groupId>org.springframework.social</groupId>

57 <artifactId>spring-social-twitter</artifactId>

58 <version>1.1.0.BUILD-SNAPSHOT</version>

59 </dependency>



Note: Our application has other dependencies as well. For example, it uses Spring Framework 3.2.4.RELEASE, Spring Data JPA 1.3.4, and Hibernate 4.2.4.Final. These dependencies are left out from the dependency listing for the sake of clarity. You can [Only Registered and Activated users can see Content.
Click Here To Register..
]
.
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:
01 #Database Configuration

02 db.driver=com.mysql.jdbc.Driver

03 db.url=jdbc:[Only Registered and Activated users can see Content.
Click Here To Register..
]

04 db.username=socialtwitter

05 db.password=password

06

07 #Hibernate Configuration

08 hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

09 hibernate.format_sql=true

10 hibernate.hbm2ddl.auto=validate

11 hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy

12 hibernate.show_sql=false

13

14 #Facebook

15 facebook.app.id=foo

16 facebook.app.secret=bar

17

18 #Twitter

19 twitter.consumer.key=foo

20 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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    interface. This class is used to load user information when the user uses form login.
  • We have to create a class which implements the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    interface.
  • The class which stores the user details of a user who uses social sign in must implement the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    interface.

Spring Social has a [Only Registered and Activated users can see Content.
Click Here To Register..
]
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:
001 import org.apache.commons.lang3.builder.ToStringBuilder;

002 import org.springframework.security.core.GrantedAuthority;

003 import org.springframework.security.core.authority.SimpleGrantedAuthority;

004 import org.springframework.social.security.SocialUser;

005

006 import java.util.Collection;

007 import java.util.HashSet;

008 import java.util.Set;

009

010 public class ExampleUserDetails extends SocialUser {

011

012 private Long id;

013

014 private String firstName;

015

016 private String lastName;

017

018 private Role role;

019

020 private SocialMediaService socialSignInProvider;

021

022 public ExampleUserDetails(String username, String password, Collection<? extendsGrantedAuthority> authorities) {

023 super(username, password, authorities);

024 }

025

026 //Getters are omitted for the sake of clarity.

027

028 public static class Builder {

029

030 private Long id;

031

032 private String username;

033

034 private String firstName;

035

036 private String lastName;

037

038 private String password;

039

040 private Role role;

041

042 private SocialMediaService socialSignInProvider;

043

044 private Set<GrantedAuthority> authorities;

045

046 public Builder() {

047 this.authorities = new HashSet<>();

048 }

049

050 public Builder firstName(String firstName) {

051 this.firstName = firstName;

052 return this;

053 }

054

055 public Builder id(Long id) {

056 this.id = id;

057 return this;

058 }

059

060 public Builder lastName(String lastName) {

061 this.lastName = lastName;

062 return this;

063 }

064

065 public Builder password(String password) {

066 if (password == null) {

067 password = "SocialUser";

068 }

069

070 this.password = password;

071 return this;

072 }

073

074 public Builder role(Role role) {

075 this.role = role;

076

077 SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.toString());

078 this.authorities.add(authority);

079

080 return this;

081 }

082

083 public Builder socialSignInProvider(SocialMediaService socialSignInProvider) {

084 this.socialSignInProvider = socialSignInProvider;

085 return this;

086 }

087

088 public Builder username(String username) {

089 this.username = username;

090 return this;

091 }

092

093 public ExampleUserDetails build() {

094 ExampleUserDetails user = new ExampleUserDetails(username, password, authorities);

095

096 user.id = id;

097 user.firstName = firstName;

098 user.lastName = lastName;

099 user.role = role;

100 user.socialSignInProvider = socialSignInProvider;

101

102 return user;

103 }

104 }

105 }



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

2 ROLE_USER

3 }



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:
1 public enum SocialMediaService {

2 FACEBOOK,

3 TWITTER

4 }



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 @Autowiredannotation.
  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:
01 import org.springframework.beans.factory.annotation.Autowired;

02 import org.springframework.security.core.userdetails.UserDetails;

03 import org.springframework.security.core.userdetails.UserDetailsService;

04 import org.springframework.security.core.userdetails.UsernameNotFoundException;

05

06 public class RepositoryUserDetailsService implements UserDetailsService {

07

08 private UserRepository repository;

09

10 @Autowired

11 public RepositoryUserDetailsService(UserRepository repository) {

12 this.repository = repository;

13 }

14

15 @Override

16 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

17 User user = repository.findByEmail(username);

18

19 if (user == null) {

20 throw new UsernameNotFoundException("No user found with username: " + username);

21 }

22

23 ExampleUserDetails principal = ExampleUserDetails.getBuilder()

24 .firstName(user.getFirstName())

25 .id(user.getId())

26 .lastName(user.getLastName())

27 .password(user.getPassword())

28 .role(user.getRole())

29 .socialSignInProvider(user.getSignInProvider())

30 .username(user.getEmail())

31 .build();

32

33 return principal;

34 }

35 }



The UserRepository is a simple Spring Data JPA repository, and its source code looks as follows:
1 import org.springframework.data.jpa.repository.JpaRepository;

2

3 public interface UserRepository extends JpaRepository<User, Long> {

4

5 public User findByEmail(String email);

6 }



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:
01 import javax.persistence.*;

02

03 @Entity

04 @Table(name = "users")

05 public class User extends BaseEntity<Long> {

06

07 @Id

08 @GeneratedValue(strategy = GenerationType.AUTO)

09 private Long id;

10

11 @Column(name = "email", length = 100, nullable = false, unique = true)

12 private String email;

13

14 @Column(name = "first_name", length = 100,nullable = false)

15 private String firstName;

16

17 @Column(name = "last_name", length = 100, nullable = false)

18 private String lastName;

19

20 @Column(name = "password", length = 255)

21 private String password;

22

23 @Enumerated(EnumType.STRING)

24 @Column(name = "role", length = 20, nullable = false)

25 private Role role;

26

27 @Enumerated(EnumType.STRING)

28 @Column(name = "sign_in_provider", length = 20)

29 private SocialMediaService signInProvider;

30

31 public User() {

32

33 }

34

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

36 }



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:
01 import org.springframework.dao.DataAccessException;

02 import org.springframework.security.core.userdetails.UserDetails;

03 import org.springframework.security.core.userdetails.UserDetailsService;

04 import org.springframework.security.core.userdetails.UsernameNotFoundException;

05 import org.springframework.social.security.SocialUser;

06 import org.springframework.social.security.SocialUserDetails;

07 import org.springframework.social.security.SocialUserDetailsService;

08

09

10 public class SimpleSocialUserDetailsService implements SocialUserDetailsService {

11

12 private UserDetailsService userDetailsService;

13

14 public SimpleSocialUserDetailsService(UserDetailsService userDetailsService) {

15 this.userDetailsService = userDetailsService;

16 }

17

18 @Override

19 public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException {

20 UserDetails userDetails = userDetailsService.loadUserByUsername(userId);

21 return (SocialUserDetails) userDetails;

22 }

23 }



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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    . 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.

Note: If you want to use XML configuration, you can take look at the example application of this blog post which has a [Only Registered and Activated users can see Content.
Click Here To Register..
]
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.
Note: 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 [Only Registered and Activated users can see Content.
Click Here To Register..
]
. I have also written a [Only Registered and Activated users can see Content.
Click Here To Register..
]
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 @EnableTransactionManagementannotation.
  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:
01 import com.jolbox.bonecp.BoneCPDataSource;

02 import org.springframework.context.annotation.Bean;

03 import org.springframework.context.annotation.Configuration;

04 import org.springframework.core.env.Environment;

05 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

06 import org.springframework.orm.jpa.JpaTransactionManager;

07 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

08 import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

09 import org.springframework.transaction.annotation.EnableTransactionManagement;

10

11 import javax.annotation.Resource;

12 import javax.sql.DataSource;

13 import java.util.Properties;

14

15 @Configuration

16 @EnableJpaRepositories(basePackages = {

17 "net.petrikainulainen.spring.social.signinmvc.user.repository"

18 })

19 @EnableTransactionManagement

20 public class PersistenceContext {

21

22 @Resource

23 private Environment env;

24

25 @Bean

26 public DataSource dataSource() {

27 BoneCPDataSource dataSource = new BoneCPDataSource();

28

29 dataSource.setDriverClass(env.getRequiredProperty("db.driver"));

30 dataSource.setJdbcUrl(env.getRequiredProperty("db.url"));

31 dataSource.setUsername(env.getRequiredProperty("db.username"));

32 dataSource.setPassword(env.getRequiredProperty("db.password"));

33

34 return dataSource;

35 }

36

37 @Bean

38 public JpaTransactionManager transactionManager() {

39 JpaTransactionManager transactionManager = new JpaTransactionManager();

40 transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());

41 return transactionManager;

42 }

43

44 @Bean

45 public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

46 LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = newLocalContainerEntityManagerFactoryBean();

47

48 entityManagerFactoryBean.setDataSource(dataSource());

49 entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

50 entityManagerFactoryBean.setPackagesToScan({

51 "net.petrikainulainen.spring.social.signinmvc.common.model",

52 "net.petrikainulainen.spring.social.signinmvc.user.model"

53 });

54

55 Properties jpaProperties = new Properties();

56 jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));

57 jpaProperties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));

58 jpaProperties.put("hibernate.hbm2ddl.auto", env.getRequiredProperty("hibernate.hbm2ddl.auto"));

59 jpaProperties.put("hibernate.ejb.naming_strategy", env.getRequiredProperty("hibernate.ejb.naming_strategy"));

60 jpaProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));

61

62 entityManagerFactoryBean.setJpaProperties(jpaProperties);

63

64 return entityManagerFactoryBean;

65 }

66 }



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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation. This makes it possible to configure Spring Security by implementing the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    interface.
  3. Ensure that our configuration class extends the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    class which is a base class for creatingWebSecurityConfigurer instances. After we have done this, we can customize the security configuration by overriding methods.
  4. Add an ApplicationContext field to the configuration class and annotate the field with the @Autowired annotation.
  5. Add an UserRepository field to the configuration and annotate the field with the @Autowired annotation.
  6. Override the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    method of the WebSecurityConfigurerAdapter class. Ensure that Spring Security ignores requests made to static resources such as CSS and Javascript files.
  7. Override the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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 [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      to the Spring Security filter chain. We can do this by creating a new SpringSocialConfigurerobject and ensuring that this object is used when Spring Security is configured.
    5. Set the value of the ApplicationContext field as an object which is shared by all [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      instances.

  8. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    object and returning the created object.
  9. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean. We can do this by creating a new RepositoryUserDetailsService object and passing theUserRepository as a constructor argument.
  10. Override the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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.

  11. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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.
  12. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean which This encrypts the authorization details of the connection established between a SaaS API provider and our application. We can do this by calling the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    method of the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    class and returning the created object. Our example application stores these details as plaintext. This is handy during the development phase but we should not use it in production.
  13. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean which is responsible of determining the correct account id of the user. Our example application uses the username of the user as an account id. We can configure this bean by creating a new [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    object and returning the created object.

The source code of our application context configuration class looks as follows:
001 import org.springframework.beans.factory.annotation.Autowired;

002 import org.springframework.context.ApplicationContext;

003 import org.springframework.context.annotation.Bean;

004 import org.springframework.context.annotation.ComponentScan;

005 import org.springframework.context.annotation.Configuration;

006 importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

007 import org.springframework.security.config.annotation.web.builders.HttpSecurity;

008 import org.springframework.security.config.annotation.web.builders.WebSecurity;

009 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

010 importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

011 import org.springframework.security.core.userdetails.UserDetailsService;

012 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

013 import org.springframework.security.crypto.encrypt.Encryptors;

014 import org.springframework.security.crypto.encrypt.TextEncryptor;

015 import org.springframework.security.crypto.password.PasswordEncoder;

016 import org.springframework.social.UserIdSource;

017 import org.springframework.social.security.AuthenticationNameUserIdSource;

018 import org.springframework.social.security.SocialUserDetailsService;

019 import org.springframework.social.security.SpringSocialConfigurer;

020

021 @Configuration

022 @EnableWebSecurity

023 public class SecurityContext extends WebSecurityConfigurerAdapter {

024

025 @Autowired

026 private ApplicationContext context;

027

028 @Autowired

029 private UserRepository userRepository;

030

031 @Override

032 public void configure(WebSecurity web) throws Exception {

033 web

034 //Spring Security ignores request to static resources such as CSS or JS files.

035 .ignoring()

036 .antMatchers("/static/**");

037 }

038

039 @Override

040 protected void configure(HttpSecurity http) throws Exception {

041 http

042 //Configures form login

043 .formLogin()

044 .loginPage("/login")

045 .loginProcessingUrl("/login/authenticate")

046 .failureUrl("/login?error=bad_credentials")

047 //Configures the logout function

048 .and()

049 .logout()

050 .deleteCookies("JSESSIONID")

051 .logoutUrl("/logout")

052 .logoutSuccessUrl("/login")

053 //Configures url based authorization

054 .and()

055 .authorizeRequests()

056 //Anyone can access the urls

057 .antMatchers(

058 "/auth/**",

059 "/login",

060 "/signin/**",

061 "/signup/**",

062 "/user/register/**"

063 ).permitAll()

064 //The rest of the our application is protected.

065 .antMatchers("/**").hasRole("USER")

066 //Adds the SocialAuthenticationFilter to Spring Security's filter chain.

067 .and()

068 .apply(new SpringSocialConfigurer())

069 .and()

070 .setSharedObject(ApplicationContext.class, context);

071 }

072

073 @Override

074 protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {

075 auth

076 .userDetailsService(userDetailsService())

077 .passwordEncoder(passwordEncoder());

078 }

079

080 @Bean

081 public PasswordEncoder passwordEncoder() {

082 return new BCryptPasswordEncoder(10);

083 }

084

085 @Bean

086 public SocialUserDetailsService socialUserDetailsService() {

087 return new SimpleSocialUserDetailsService(userDetailsService());

088 }

089

[Login or Register to remove this advertisement]

090 @Bean

091 public TextEncryptor textEncryptor() {

092 return Encryptors.noOpText();

093 }

094

095 @Bean

096 public UserDetailsService userDetailsService() {

097 return new RepositoryUserDetailsService(userRepository);

098 }

099

100 @Bean

101 public UserIdSource userIdSource() {

102 return new AuthenticationNameUserIdSource();

103 }

104 }



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 and annotate the created class with the @Configuration annotation.
  2. Annotate the configuration class with the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation. This annotation enables JDBC based persistence for connections. It means that connections to SaaS service providers are stored to the UserConnection table ([Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    ). This is handy because it means that the application can restore the connection instead of establishing it every time when it is required.
  3. Annotate the configuration class with the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation, and set the application id and application secret. This annotation adds Facebook support to our example application.
  4. Annotate the configuration with the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation, and set set consumer key and consumer secret. This annotation adds Twitter support to our example application.
  5. Annotate the class with @Profile annotation and set the string ‘application’ as its value. This ensures that this application context configuration class is used only when the active Spring profile is ‘application’. This is important because it gives us the possibility to write integration tests for our application without relying on Facebook or Twitter.
  6. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean. The method which configures this bean has two parameters. The first parameter is the[Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean. The second parameter is the used [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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:
01 import org.springframework.context.annotation.Bean;

02 import org.springframework.context.annotation.Configuration;

03 import org.springframework.social.config.annotation.EnableJdbcConnectionRepository;

04 import org.springframework.social.connect.ConnectionFactoryLocator;

05 import org.springframework.social.connect.ConnectionRepository;

06 import org.springframework.social.connect.web.ConnectController;

07 import org.springframework.social.facebook.config.annotation.EnableFacebook;

08 import org.springframework.social.twitter.config.annotation.EnableTwitter;

09

10 @Configuration

11 @EnableJdbcConnectionRepository

12 @EnableFacebook(appId = "${facebook.app.id}", appSecret = "${facebook.app.secret}")

13 @EnableTwitter(appId = "${twitter.consumer.key}", appSecret = "${twitter.consumer.secret}")

14 @Profile("application")

15 public class SocialContext {

16

17 @Bean

18 public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {

19 return new ConnectController(connectionFactoryLocator, connectionRepository);

20 }

21 }



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 [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation.
  4. Ensure that static resources are served by container’s default servlet.
    1. Configure the static resources by overriding the [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      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 [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      method of the WebMvcConfigurerAdapter class.

  5. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean.
  6. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean.

The source code of the WebAppContext class looks as follows:
01 import org.springframework.context.annotation.Bean;

02 import org.springframework.context.annotation.ComponentScan;

03 import org.springframework.context.annotation.Configuration;

04 import org.springframework.web.servlet.ViewResolver;

05 import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;

06 import org.springframework.web.servlet.config.annotation.EnableWebMvc;

07 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

08 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

09 import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

10 import org.springframework.web.servlet.view.InternalResourceViewResolver;

11 import org.springframework.web.servlet.view.JstlView;

12

13 import java.util.Properties;

14

15 @Configuration

16 @ComponentScan(basePackages = {

17 "net.petrikainulainen.spring.social.signinmvc.common.controller",

18 "net.petrikainulainen.spring.social.signinmvc.security.controller",

19 "net.petrikainulainen.spring.social.signinmvc.user.controller"

20 })

21 @EnableWebMvc

22 public class WebAppContext extends WebMvcConfigurerAdapter {

23

24 @Override

25 public void addResourceHandlers(ResourceHandlerRegistry registry) {

26 registry.addResourceHandler("/static/**").addResourceLocations("/static/");

27 }

28

29 @Override

30 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

31 configurer.enable();

32 }

33

34 @Bean

35 public SimpleMappingExceptionResolver exceptionResolver() {

36 SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();

37

38 Properties exceptionMappings = new Properties();

39

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

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

42

43 exceptionResolver.setExceptionMappings(exceptionMappings);

44

45 Properties statusCodes = new Properties();

46

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

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

49

50 exceptionResolver.setStatusCodes(statusCodes);

51

52 return exceptionResolver;

53 }

54

55 @Bean

56 public ViewResolver viewResolver() {

57 InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

58

59 viewResolver.setViewClass(JstlView.class);

60 viewResolver.setPrefix("/WEB-INF/jsp/");

61 viewResolver.setSuffix(".jsp");

62

63 return viewResolver;

64 }

65 }



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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation.
  4. Annotate the class with the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    annotation, and configure it to look for a properties file called application.propertiesfrom the classpath. This ensures that the configuration properties can be accessed in the imported application context configuration classes.
  5. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean.
  6. Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    bean.

The source code the ExampleApplicationContext class looks as follows:
01 import org.springframework.context.MessageSource;

02 import org.springframework.context.annotation.*;

03 import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

04 import org.springframework.context.support.ResourceBundleMessageSource;

05

06 @Configuration

07 @ComponentScan(basePackages = {

08 "net.petrikainulainen.spring.social.signinmvc.user.service"

09 })

10 @Import({WebAppContext.class, PersistenceContext.class, SecurityContext.class, SocialContext.class})

11 @PropertySource("classpath:application.properties")

12 public class ExampleApplicationContext {

13

14 @Bean

15 public MessageSource messageSource() {

16 ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

17

18 messageSource.setBasename("i18n/messages");

19 messageSource.setUseCodeAsDefaultMessage(true);

20

21 return messageSource;

22 }

23

24 @Bean

25 public PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {

26 return new PropertySourcesPlaceholderConfigurer();

27 }

28 }



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 [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    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 [Only Registered and Activated users can see Content.
      Click Here To Register..
      ]
      .

    C) Configure [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    .
    D) Configure the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    .
    E) Configure [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    .
    F) Add the [Only Registered and Activated users can see Content.
    Click Here To Register..
    ]
    to the servlet context.

The source code of the ExampleApplicationConfig class looks as follows:
01 import org.sitemesh.config.ConfigurableSiteMeshFilter;

02 import org.springframework.web.WebApplicationInitializer;

03 import org.springframework.web.context.ContextLoaderListener;

04 import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

05 import org.springframework.web.context.support.XmlWebApplicationContext;

06 import org.springframework.web.filter.CharacterEncodingFilter;

07 import org.springframework.web.filter.DelegatingFilterProxy;

08 import org.springframework.web.servlet.DispatcherServlet;

09

10 import javax.servlet.*;

11 import java.util.EnumSet;

12

13 public class ExampleApplicationConfig implements WebApplicationInitializer {

14

15 @Override

16 public void onStartup(ServletContext servletContext) throws ServletException {

17 AnnotationConfigWebApplicationContext rootContext = newAnnotationConfigWebApplicationContext();

18 rootContext.register(ExampleApplicationContext.class);

19

20 ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", newDispatcherServlet(rootContext));

21 dispatcher.setLoadOnStartup(1);

22 dispatcher.addMapping("/");

23

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

25

26 CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();

27 characterEncodingFilter.setEncoding("UTF-8");

28 characterEncodingFilter.setForceEncoding(true);

29

30 FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);

31 characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

32

33 FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain",new DelegatingFilterProxy());

34 security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

35

36 FilterRegistration.Dynamic sitemesh = servletContext.addFilter("sitemesh", newConfigurableSiteMeshFilter());

37 sitemesh.addMappingForUrlPatterns(dispatcherTypes, true, "*.jsp");

38

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

40 }

41 }



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 authentication functions to our example application.
P.S. As always, the example application of this blog post is available [Only Registered and Activated users can see Content.
Click Here To Register..
]
.
Xcode Reviewed by Xcode on . Adding Social Sign In to a Spring MVC Web Application: Configuration 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 Rating: 5