I am new to spring. I'm using spring boot in order to avail some predefined configurations. It seems to be useful.
For more than 2-weeks I'm stuck with creating an Authentication and Authorization using spring security. I would like to use Google users for authentication. And I'm using MongoDB as data storage.
Here's my code for connecting with Google users,
1. SocialConnectionConfiguration.java
package com.example.social;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.google.connect.GoogleConnectionFactory;
@Configuration
public class SocialConnectionConfiguration {
// Google Application Credentials
private static final String GoogleClientID = "<clientID>";
private static final String GoogleClientSecret = "<clientSecret>";
@Bean
public GoogleConnectionFactory getGoogleConnectionFactory() {
GoogleConnectionFactory connectionFactory =
new GoogleConnectionFactory(GoogleClientID, GoogleClientSecret);
return connectionFactory;
}
}
2. SocialConnectionConfiguration.java
package com.example.social;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.google.connect.GoogleConnectionFactory;
@Configuration
public class SocialConnectConfiguration{
@Autowired
GoogleConnectionFactory gplusConnectionFactory;
@Bean
public GoogleAPI getGoogleAPI(){
GoogleAPI googleAPI = new GoogleAPI(gplusConnectionFactory);
return googleAPI;
}
}
3. GoogleAPI.java
package com.example.social;
import org.springframework.social.connect.Connection;
import org.springframework.social.google.api.Google;
import org.springframework.social.google.connect.GoogleConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.GrantType;
import org.springframework.social.oauth2.OAuth2Parameters;
public class GoogleAPI {
private GoogleConnectionFactory GplusConnectionFactory;
private Google google;
private static final String REDIRECT_URI = "http://localhost:8080/google_response";
public Google getGoogle() {
return google;
}
public GoogleAPI(GoogleConnectionFactory GplusConnectionFactory) {
this.GplusConnectionFactory = GplusConnectionFactory;
}
public String getRedirectURI() {
OAuth2Parameters params = new OAuth2Parameters();
params.setRedirectUri(REDIRECT_URI);
params.setScope("profile");
params.setScope("openid");
params.setScope("email");
String authorizeUrl = GplusConnectionFactory.getOAuthOperations().buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
return authorizeUrl;
}
public Google establishFacebookConnection(String accessToken) {
AccessGrant accessGrant = GplusConnectionFactory.getOAuthOperations().exchangeForAccess(accessToken,REDIRECT_URI, null);
Connection<Google> connection = GplusConnectionFactory.createConnection(accessGrant);
google = connection.getApi();
return google;
}
public boolean isAuthorized() {
if(google != null){
return google.isAuthorized();
}
return false;
}
}
The above three files are used to get connect with google. But how can I give authentication with same code.
As I have gone through this tutorial (Follow Tutorial-1,2,3) . I have come across some information's (down below) that we should have,
So I have created the below classes :
1.a) Entity Model (UserAccount.java)
package com.example.model;
import java.util.Set;
import javax.validation.constraints.NotNull;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection="user_account")
public class UserAccount {
@Id
private ObjectId id;
private String firstName;
@Indexed
private String lastName;
private Integer age;
@Indexed
@NotNull
private final String username;
@NotNull
private String password;
@NotNull
private boolean enabled = true;
@NotNull
private boolean credentialsexpired = false;
@NotNull
private boolean expired = false;
@NotNull
private boolean locked = false;
private Set<Role> roles;
@PersistenceConstructor
public UserAccount(String username, String firstName, String lastName, Integer age) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public ObjectId getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isCredentialsexpired() {
return credentialsexpired;
}
public void setCredentialsexpired(boolean credentialsexpired) {
this.credentialsexpired = credentialsexpired;
}
public boolean isExpired() {
return expired;
}
public void setExpired(boolean expired) {
this.expired = expired;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "[" + this.getId() +
" : " + this.getUsername() +
" : " + this.firstName +
" : " + this.getLastName() +
" : " + this.getAge().toString()+"]";
}
}
1.b) Entity Model (Role.java)
package com.example.model;
import javax.validation.constraints.NotNull;
public class Role {
private static final String ADMIN = "ADMIN";
private static final String MANAGER = "MANAGER";
private static final String USER = "USER";
@NotNull
private String code;
@NotNull
private String label;
public Role() {
}
public Role(String code) {
this.code = code;
assignRole(code);
}
private void assignRole(String code) {
if(code.equals("1")) {
this.label = ADMIN;
}
else if(code.equals("2")) {
this.label = MANAGER;
}
else if(code.equals("3")) {
this.label = USER;
}
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
2. Data Repository(UserAccountRepository.java)
package com.example.repository;
import java.io.Serializable;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.example.model.UserAccount;
@Repository
public interface UserAccountRepository extends MongoRepository<UserAccount, Serializable> {
public UserAccount findById(ObjectId id);
public UserAccount findByUsername(String username);
}
3.a) UserDteailsService(UserAccountDetailsService.java)
package com.example.secutiry;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.model.Role;
import com.example.model.UserAccount;
import com.example.service.UserAccountService;
@Service
public class UserAccountDetailsService implements UserDetailsService{
@Autowired
private UserAccountService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserAccount user = userService.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("Given user name doesn't match !");
}
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
for (Role role : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getLabel()));
}
User userDetails = new User(user.getUsername(),
user.getPassword(),user.isEnabled(),
user.isExpired(),user.isCredentialsexpired(),
user.isLocked(), grantedAuthorities);
return userDetails;
}
}
3.b) UserDteailsService(UserAccountService.java)
package com.example.service;
import java.io.Serializable;
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import com.example.model.UserAccount;
import com.example.repository.UserAccountRepository;
@Service
public class UserAccountService implements UserAccountRepository {
@Autowired
private UserAccountRepository repository;
@Override
public <S extends UserAccount> List<S> save(Iterable<S> entites) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<UserAccount> findAll() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<UserAccount> findAll(Sort sort) {
// TODO Auto-generated method stub
return null;
}
@Override
public <S extends UserAccount> S insert(S entity) {
// TODO Auto-generated method stub
return null;
}
@Override
public <S extends UserAccount> List<S> insert(Iterable<S> entities) {
// TODO Auto-generated method stub
return null;
}
@Override
public Page<UserAccount> findAll(Pageable pageable) {
// TODO Auto-generated method stub
return null;
}
@Override
public <S extends UserAccount> S save(S entity) {
repository.save(entity);
return null;
}
@Override
public UserAccount findOne(Serializable id) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean exists(Serializable id) {
// TODO Auto-generated method stub
return false;
}
@Override
public Iterable<UserAccount> findAll(Iterable<Serializable> ids) {
// TODO Auto-generated method stub
return null;
}
@Override
public long count() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void delete(Serializable id) {
// TODO Auto-generated method stub
}
@Override
public void delete(UserAccount entity) {
// TODO Auto-generated method stub
}
@Override
public void delete(Iterable<? extends UserAccount> entities) {
// TODO Auto-generated method stub
}
@Override
public void deleteAll() {
// TODO Auto-generated method stub
}
@Override
public UserAccount findById(ObjectId id) {
UserAccount user = repository.findById(id);
return user;
}
@Override
public UserAccount findByUsername(String username) {
UserAccount user = repository.findByUsername(username);
return user;
}
}
4. AuthenticationProvider (UserAccountAuthenticationProvider.java)
package com.example.secutiry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class UserAccountAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Autowired
private UserAccountDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken token)
throws AuthenticationException {
if(token.getCredentials() == null
|| userDetails.getPassword() == null) {
throw new BadCredentialsException("Credentials may not be Empty!");
}
if(!passwordEncoder.matches(token.getCredentials().toString(),
userDetails.getPassword())) {
throw new BadCredentialsException("Invalid Credentials !");
}
}
@Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return userDetails;
}
}
5. Security Configuration(SecurityConfiguration.java)
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.example.secutiry.UserAccountAuthenticationProvider;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Autowired
private UserAccountAuthenticationProvider userAccountAuthenticationProvider;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(userAccountAuthenticationProvider);
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter
extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
}
So now, If I use the Google connectivity code separately I can able to connect to google. That's fine, but how can I use the Google connectivity code to authenticate ?
If my code is wrong please correct me, If I'am suppose to include or exclude any line or file please guide me since I'm new to spring.
Thanks in advance
Why do you check password again in your own UserDetailsService implementation?
if(token.getCredentials() == null
|| userDetails.getPassword() == null) {
throw new BadCredentialsException("Credentials may not be Empty!");
}
if(!passwordEncoder.matches(token.getCredentials().toString(),
userDetails.getPassword())) {
throw new BadCredentialsException("Invalid Credentials !");
}
Password check is done by google identity provider only. So you'll never will get a password. Did you already check http://gabiaxel.github.io/spring-social-google-reference/connecting.html and http://docs.spring.io/spring-social/docs/1.1.x/reference/htmlsingle/#enabling-provider-sign-in-with-code-socialauthenticationfilter-code
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.