Custom Spring OAuth2 Security with Spring Social Integration

Custom Spring Protection OAuth2 works fine and now wants to add Spring Social Integration (facebook login, google login, etc.) when the user clicks on the Facebook login (the user will not specify any username / password) Facebook will return access_token, but we won’t be able to use this access_token to request my application web services, to get my access_token application, we need to pass the username and password using grant_type as the password. Below are the configuration files

AuthorizationServerConfiguration.java

@Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired DataSource dataSource; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Override public void configure( AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.allowFormAuthenticationForClients(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); } @Bean @Primary public DefaultTokenServices tokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setSupportRefreshToken(true); tokenServices.setTokenStore(tokenStore()); tokenServices.setAccessTokenValiditySeconds(86400000); tokenServices.setRefreshTokenValiditySeconds(86400000); return tokenServices; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenServices(tokenServices()) .authenticationManager(authenticationManager); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } } 

ResourceServerConfiguration.java

 @Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { private String resourceId = "rest_api"; @Override public void configure(ResourceServerSecurityConfigurer resources) { // @formatter:off resources.resourceId(resourceId); // @formatter:on } @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll() .antMatchers(HttpMethod.GET, "/**/login").permitAll() .antMatchers(HttpMethod.GET, "/**/callback").permitAll() .anyRequest().authenticated() .and() .formLogin().permitAll(); } } 

and finally WebSecurityConfigurerAdapter.java

 @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll() .antMatchers(HttpMethod.GET, "/**/login").permitAll() .antMatchers(HttpMethod.GET, "/**/callback").permitAll() .anyRequest().authenticated() .and() .formLogin().permitAll(); } } 

Read different posts in SO, but could not get any working example, please help me with this. Thanks in advance.!

+5
source share
2 answers
  String redirectURL = messages.getProperty(Constant.REDIRECT_URI.getValue()); String clientSecret = messages.getProperty(Constant.CLIENT_SECRET.getValue()); HttpHeaders header = new HttpHeaders(); header.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); String req = "client_id=myas&" + "client_secret=" + clientSecret + "&grant_type=authorization_code&" + "scope=user_profile&" + "code=" + loginReqeust.getCode() + "&redirect_uri=" + loginReqeust.getRedirectURL(); HttpEntity<String> body = new HttpEntity<String>(req, header); Map<Object, Object> mapRes = new LinkedHashMap<Object, Object>(); // call to get access token mapRes = getEndpoint("https://auth.mygov.in/oauth2/token", null, body, null); String accessToken = mapRes.get("access_token").toString(); // Call for getting User Profile String userUrl = "https://auth.mygov.in/myasoauth2/user/profile"; HttpHeaders head = new HttpHeaders(); head.add("Authorization", "Bearer " + accessToken); HttpEntity<String> ent = new HttpEntity<String>(head); Map<Object, Object> mapResponse = new LinkedHashMap<Object, Object>(); mapResponse.put("userProfile", getEndpoint(userUrl, null, ent, null)); //In my case userKey represents the username basically the email of the user using which he/she logged into facebook/google String userKey = (String) ((LinkedHashMap<Object, Object>) mapResponse.get("userProfile")).get("mail"); // Store the user profile in your database with basic info like username & an autogenerated password for the time being and other basic fields. userService.save(userprofileInfo); mapResponse.put("username", "retrieved from facebook/google user profile"); mapResponse.put("password", "autogenerated by your application"); //send back this response (mapResponse) to your UI and then from there make a call by passing this username and pwd to retrieve the access_token from your own applicatioon. 
+1
source

I had a similar requirement to get the facebook access token and create my own JWT token by checking the facebook token on the server side.

I changed the project mentioned here: https://github.com/svlada/springboot-security-jwt

My settings are as follows (I assume you already have a facebook access token):

LoginRequest.java

 public class LoginRequest { private String token; @JsonCreator public LoginRequest(@JsonProperty("token") String token) { this.token = token; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } } 

AjaxLoginProcessingFilter.java

 @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (!HttpMethod.POST.name().equals(request.getMethod()) || !WebUtil.isAjax(request)) { if(logger.isDebugEnabled()) { logger.debug("Authentication method not supported. Request method: " + request.getMethod()); } throw new AuthMethodNotSupportedException("Authentication method not supported"); } LoginRequest loginRequest = objectMapper.readValue(request.getReader(), LoginRequest.class); if (StringUtils.isBlank(loginRequest.getToken())) { throw new AuthenticationServiceException("token not provided"); } UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getToken(), null); return this.getAuthenticationManager().authenticate(token); } 

AjaxAuthenticationProvider.java

 @Component public class AjaxAuthenticationProvider implements AuthenticationProvider { @Autowired private BCryptPasswordEncoder encoder; @Autowired private DatabaseUserService userService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { Assert.notNull(authentication, "No authentication data provided"); String username = null; try { username = getUsername(authentication.getPrincipal()); } catch (UnsupportedOperationException e) { } catch (IOException e) { } //You can either register this user by fetching additional data from facebook or reject it. User user = userService.getByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found")); if (user.getRoles() == null) throw new InsufficientAuthenticationException("User has no roles assigned"); List<GrantedAuthority> authorities = user.getRoles().stream() .map(authority -> new SimpleGrantedAuthority(authority.getRole().authority())) .collect(Collectors.toList()); UserContext userContext = UserContext.create(user.getUsername(), authorities); return new UsernamePasswordAuthenticationToken(userContext, null, userContext.getAuthorities()); } private String getUsername(Object principal) throws UnsupportedOperationException, IOException { HttpClient client = new DefaultHttpClient(); //I am just accessing the details. You can debug whether this token was granted against your app. HttpGet get = new HttpGet("https://graph.facebook.com/me?access_token=" + principal.toString()); HttpResponse response = client.execute(get); BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } JSONObject o = new JSONObject(result.toString()); //This is just for demo. You should use id or some other unique field. String username = o.getString("first_name"); return username; } @Override public boolean supports(Class<?> authentication) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } } 

In addition, I also had to add a custom BeanPostProcessor to override the default behavior of UsernamePasswordAuthenticationFilter, to accept only a token as a field instead of a username and password.

UserPassAuthFilterBeanPostProcessor.java

Public class UserPassAuthFilterBeanPostProcessor implements BeanPostProcessor {

 private String usernameParameter; private String passwordParameter; @Override public final Object postProcessAfterInitialization(final Object bean, final String beanName) { return bean; } @Override public final Object postProcessBeforeInitialization(final Object bean, final String beanName) { if (bean instanceof UsernamePasswordAuthenticationFilter) { final UsernamePasswordAuthenticationFilter filter = (UsernamePasswordAuthenticationFilter) bean; filter.setUsernameParameter(getUsernameParameter()); filter.setPasswordParameter(getPasswordParameter()); } return bean; } public final void setUsernameParameter(final String usernameParameter) { this.usernameParameter = usernameParameter; } public final String getUsernameParameter() { return usernameParameter; } public final void setPasswordParameter(final String passwordParameter) { this.passwordParameter = passwordParameter; } public final String getPasswordParameter() { return passwordParameter; } 

Configuration:

 @Bean public UserPassAuthFilterBeanPostProcessor userPassAuthFilterBeanPostProcessor(){ UserPassAuthFilterBeanPostProcessor bean = new UserPassAuthFilterBeanPostProcessor(); bean.setUsernameParameter("token"); bean.setPasswordParameter(null); return bean; } 

postman output

+1
source

Source: https://habr.com/ru/post/1261438/


All Articles