package com.github.mikhailerofeev.mars.calendar.server; import com.google.common.collect.Lists; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.core.env.Environment; import org.springframework.security.access.annotation.Secured; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.encrypt.Encryptors; import org.springframework.security.crypto.encrypt.TextEncryptor; import org.springframework.social.connect.*; import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository; import org.springframework.social.connect.support.ConnectionFactoryRegistry; import org.springframework.social.connect.web.ConnectController; import org.springframework.social.connect.web.ProviderSignInController; import org.springframework.social.connect.web.ProviderSignInUtils; import org.springframework.social.connect.web.SignInAdapter; import org.springframework.social.google.api.Google; import org.springframework.social.google.connect.GoogleConnectionFactory; import org.springframework.social.twitter.api.Twitter; import org.springframework.social.twitter.connect.TwitterConnectionFactory; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.ModelAndView; import javax.inject.Inject; import javax.sql.DataSource; import java.util.Random; /** * @author Mikhail Erofeev https://github.com/MikhailErofeev * @since 11.04.14 */ @Configuration @Controller public class SocialConfig { @Inject private Environment environment; @Inject private DataSource dataSource; @Inject private TextEncryptor textEncryptor; public static final GrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER"); public static final GrantedAuthority ROLE_ANONYMOUS = new SimpleGrantedAuthority("ROLE_ANONYMOUS"); @Bean public ConnectController connectController() { return new ConnectController(connectionFactoryLocator(), connectionRepository()); } @Bean @Scope(value = "singleton", proxyMode = ScopedProxyMode.INTERFACES) public ConnectionFactoryLocator connectionFactoryLocator() { ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry(); final GoogleConnectionFactory gcf = new GoogleConnectionFactory( environment.getProperty("google.consumerKey"), environment.getProperty("google.consumerSecret")); registry.addConnectionFactory(gcf); final TwitterConnectionFactory tcf = new TwitterConnectionFactory (environment.getProperty("twitter.consumerKey"), environment.getProperty("twitter.consumerSecret")); registry.addConnectionFactory(tcf); return registry; } @Bean @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) public ConnectionRepository connectionRepository() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in"); } return usersConnectionRepository().createConnectionRepository(authentication.getName()); } @Bean @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) public Twitter twitter() { return connectionRepository().getPrimaryConnection(Twitter.class).getApi(); } @Bean @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) public Google google() { return connectionRepository().getPrimaryConnection(Google.class).getApi(); } @Bean @Scope(value = "singleton", proxyMode = ScopedProxyMode.INTERFACES) public UsersConnectionRepository usersConnectionRepository() { return new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator(), textEncryptor); } @Bean public ProviderSignInController providerSignInController() { final ProviderSignInController providerSignInController = new ProviderSignInController(connectionFactoryLocator(), usersConnectionRepository(), new SpringSecuritySignInAdapter()); providerSignInController.setSignUpUrl("/register"); return providerSignInController; } @Service public static class SpringSecuritySignInAdapter implements SignInAdapter { public String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) { SecurityContextHolder.getContext().setAuthentication( //todo change to SocialAuthToken? new UsernamePasswordAuthenticationToken(localUserId, null, Lists.newArrayList(ROLE_USER))); return null; } } @RequestMapping(value = "/register", method = RequestMethod.GET) @ResponseBody //could been extended to registration form public ModelAndView signupForm(WebRequest request) { Connection<?> connection = ProviderSignInUtils.getConnection(request); if (connection != null) { final UserProfile userProfile = connection.fetchUserProfile(); ProviderSignInUtils.handlePostSignUp(userProfile.getUsername(), request); return new ModelAndView("redirect:/?signup=success"); } else { return new ModelAndView("redirect:/?signup=error"); } } @RequestMapping(value = "/disconnect", method = RequestMethod.DELETE) @Secured("ROLE_USER") @ResponseBody public ModelAndView disconnect(WebRequest request) { Connection<?> connection = ProviderSignInUtils.getConnection(request); final String key = new Random().nextInt() + ""; final AnonymousAuthenticationToken anonymous = new AnonymousAuthenticationToken(key, "Anonymous", Lists.newArrayList(ROLE_ANONYMOUS)); SecurityContextHolder.getContext().setAuthentication(anonymous); return new ModelAndView("redirect:/"); } @Bean public TextEncryptor textEncryptor() { return Encryptors.noOpText(); } }