Commit 297b6aff authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '102-userservice-from-app-blocks' into 'master'

Resolve "UserService from app-blocks"

Closes #102

See merge request !104
parents dea64edc 24be8181
......@@ -45,8 +45,7 @@ public interface UserRepository extends JpaRepository<User, Long> {
* @param pageable the pageable
* @return the list
*/
@Query("select u from User u where u.email like ?1")
List<User> autocompleteByEmail(String email, Pageable pageable);
List<User> findByEmailStartingWith(String email, Pageable pageable);
/**
* Search.
......
......@@ -17,113 +17,15 @@ package org.genesys.catalog.service;
import java.util.List;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser;
import org.genesys.blocks.security.service.BasicUserService;
import org.genesys.catalog.model.user.User;
import org.genesys.catalog.model.user.UserRole;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
* The Interface UserService.
*/
public interface UserService extends UserDetailsService {
public interface UserService extends BasicUserService<UserRole, User> {
/**
* Get User by id.
*
* @param id id of user
* @return the user or <code>null</code>
*/
User getUser(Long id);
/**
* Get User by email.
*
* @param email email of user
* @return the user
*/
User getUserByEmail(String email);
/**
* Create a new user account.
*
* @param email unique email address
* @param fullName Full name
* @param password initial account password
* @param accountType TODO
* @return the new user
*/
User createUser(String email, String fullName, String password, BasicUser.AccountType accountType);
/**
* Grant specified roles to user. The {@link UserRole#USER} will be added if
* missing.
*
* @param user user
* @param roles role that be set to user
* @return the updated user
*/
User setRoles(User user, UserRole... roles);
/**
* Update user information.
*
* @param user the user
* @param email new email address
* @param fullName new fullName
* @return updated user
*/
User updateUser(User user, String email, String fullName);
/**
* Change password.
*
* @param user the user
* @param password new password
* @return updated user
*/
User changePassword(User user, String password);
/**
* Try to delete user.
*
* @param user user to delete
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
void deleteUser(User user);
/**
* Method for set AccountType for user.
*
* @param user user
* @param accountType accountType
* @return updated user
*/
User setAccountType(User user, BasicUser.AccountType accountType);
/**
* Autocomplete User by email.
*
* @param email email of user
* @return List of users
*/
List<User> autocompleteUser(String email);
/**
* Method for remove user by userId.
*
* @param userId user id
* @throws UserException the user exception
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
void removeUserById(long userId) throws UserException;
/**
* Get current user.
*
* @return current user
*/
@PreAuthorize("isAuthenticated()")
User getMe();
}
......@@ -16,14 +16,14 @@
package org.genesys.catalog.service.impl;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.security.NoUserFoundException;
import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser;
import org.genesys.blocks.security.model.BasicUser.AccountType;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys.blocks.security.service.impl.BasicUserServiceImpl;
import org.genesys.catalog.model.user.User;
import org.genesys.catalog.model.user.UserRole;
import org.genesys.catalog.persistence.user.UserRepository;
......@@ -31,15 +31,12 @@ import org.genesys.catalog.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
......@@ -47,159 +44,51 @@ import com.google.common.collect.Sets;
*/
@Service(value = "userService")
@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
public class UserServiceImpl extends BasicUserServiceImpl<UserRole, User> implements UserService {
private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);
/// A non-password used for system and Google accounts
private static final String THIS_IS_NOT_A_PASSWORD = "THIS-IS-NOT-A-PASSWORD";
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
protected static final List<UserRole> availableRoles = Collections.unmodifiableList(Lists.newArrayList(UserRole.values()));
@Override
public User getUser(final Long id) {
final User user = userRepository.findOne(id);
if (user != null) {
user.getRoles().size();
}
return user;
public UserRole getDefaultUserRole() {
return UserRole.USER;
}
@Override
public User getUserByEmail(final String email) {
final User user = userRepository.findByEmail(email);
if (user != null) {
user.getRoles().size();
}
return user;
public List<UserRole> listAvailableRoles() {
return availableRoles;
}
@Override
public UserDetails loadUserByUsername(final String email) throws UsernameNotFoundException {
LOG.trace("Attempting login for email={}", email);
final User user = userRepository.findByEmail(email);
if (user == null) {
LOG.warn("Failed login, no user registered with email={}", email);
throw new UsernameNotFoundException("No such user");
} else {
user.getRoles().size();
LOG.debug("Starting login for user={} user.roles={}", user, user.getRoles());
return user;
}
public User deepLoad(User user) {
return super.deepLoad(user);
}
@Override
@Transactional
public User createUser(final String email, final String fullName, final String password, final BasicUser.AccountType accountType) {
LOG.info("Creating user email={} fullName={}", email, fullName);
final User user = new User();
user.setEmail(email);
user.setFullName(fullName);
user.setAccountType(accountType);
user.getRoles().add(UserRole.USER);
setPassword(user, password);
return userRepository.save(user);
public User getUserByEmail(String email) {
return deepLoad(userRepository.findByEmail(email));
}
// TODO FIXME PreAuthorize
// TODO FIXME Email check
// @PreAuthorize("")
@Override
@Transactional
public User updateUser(final User user, final String email, final String fullName) {
public User createUser(String email, String fullName, String password, AccountType accountType) throws NotUniqueUserException, PasswordPolicyException, UserException {
LOG.info("Creating user {} <{}>", fullName, email);
User user = new User();
user.setEmail(email);
user.setFullName(fullName);
return userRepository.save(user);
}
// FIXME PreAuthorize
@Override
@Transactional
public User changePassword(final User user, final String password) {
user.setAccountType(accountType);
user.setRoles(Sets.newHashSet(getDefaultUserRole()));
setPassword(user, password);
return userRepository.save(user);
}
private void setPassword(final User user, final String password) {
user.setPassword(password == null ? null : passwordEncoder.encode(password));
return deepLoad(userRepository.save(user));
}
@Override
@Transactional
// FIXME Needs permission check
public User setRoles(User user, final UserRole... roles) {
user = userRepository.findOne(user.getId());
// If roles match, do nothing
final HashSet<UserRole> newRoles = Sets.newHashSet(roles);
newRoles.add(UserRole.USER);
if (newRoles.containsAll(user.getRoles()) && user.getRoles().containsAll(newRoles)) {
LOG.debug("Roles {} match {}. No change.", newRoles, user.getRoles());
return user;
}
user.getRoles().clear();
user.getRoles().addAll(newRoles);
LOG.info("Setting roles for user {} to {}", user.getEmail(), user.getRoles());
return userRepository.save(user);
}
@Override
@Transactional
public void deleteUser(final User user) {
userRepository.delete(user);
}
@Override
@Transactional
public User setAccountType(final User user, final BasicUser.AccountType accountType) {
final User u = userRepository.findOne(user.getId());
u.setAccountType(accountType);
if (accountType != BasicUser.AccountType.LOCAL) {
user.setPassword(THIS_IS_NOT_A_PASSWORD);
}
return userRepository.save(u);
}
/**
* {@inheritDoc}
*/
@Override
public List<User> autocompleteUser(final String email) {
public List<User> autocompleteUser(String email) {
if (StringUtils.isBlank(email) || (email.length() < 4))
return Collections.emptyList();
return userRepository.autocompleteByEmail(email + "%", new PageRequest(0, 10, new Sort("email")));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public void removeUserById(final long userId) throws UserException {
try {
userRepository.delete(userId);
} catch (final EmptyResultDataAccessException e) {
throw new NoUserFoundException(e, userId);
} catch (final RuntimeException e) {
throw new UserException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public User getMe() {
final User user = userRepository.findOne(SecurityContextUtil.getCurrentUser().getId());
if (user != null) {
user.getRoles().size();
}
return user;
return userRepository.findByEmailStartingWith(email, new PageRequest(0, 20, new Sort("email")));
}
}
......@@ -16,11 +16,15 @@
package org.genesys.catalog.service;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys.catalog.model.user.User;
import org.genesys.catalog.model.user.UserRole;
import org.genesys.catalog.persistence.user.UserRepository;
......@@ -29,8 +33,12 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import com.google.common.collect.Sets;
public class UserServiceTest extends ServiceTest {
private static final String USER_EMAIL = "testuser@example.com";
private static final String USER_PASSWORD = "GooDPassW87!";
@Autowired
private UserService userService;
......@@ -44,39 +52,43 @@ public class UserServiceTest extends ServiceTest {
}
@Test(expected = DataIntegrityViolationException.class)
public void failUserSave() {
userService.createUser(null, null, "1", BasicUser.AccountType.LOCAL);
public void failUserSave() throws NotUniqueUserException, PasswordPolicyException, UserException {
userService.createUser(null, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
}
@Test(expected = DataIntegrityViolationException.class)
public void failDuplicateUser() {
userService.createUser(USER_EMAIL, null, "1", BasicUser.AccountType.LOCAL);
userService.createUser(USER_EMAIL, null, "1", BasicUser.AccountType.LOCAL);
public void failDuplicateUser() throws NotUniqueUserException, PasswordPolicyException, UserException {
userService.createUser(USER_EMAIL, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
userService.createUser(USER_EMAIL, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
}
@Test
public void saveUser() {
final User user = userService.createUser(USER_EMAIL, null, "1", BasicUser.AccountType.LOCAL);
public void saveUser() throws NotUniqueUserException, PasswordPolicyException, UserException {
final User user = userService.createUser(USER_EMAIL, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
assertThat("User#id must be generated", user.getId(), not(nullValue()));
User loaded = userService.getUserByEmail(USER_EMAIL);
assertThat(loaded, not(nullValue()));
assertThat(loaded.getEmail(), is(USER_EMAIL));
}
@Test
public void updateUser() {
User user = userService.createUser(USER_EMAIL, null, "1", BasicUser.AccountType.LOCAL);
public void updateUser() throws NotUniqueUserException, PasswordPolicyException, UserException {
User user = userService.createUser(USER_EMAIL, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
user = userService.updateUser(user, "1" + USER_EMAIL, "New Full Name");
user = userService.changePassword(user, "newpassword");
user = userService.changePassword(user, "NewW8Wrd!");
}
@Test
public void grantRoles() {
User u = userService.createUser(USER_EMAIL, null, "1", BasicUser.AccountType.LOCAL);
assertThat("Account must have USER and ADMINISTRATOR roles", u.getRoles(), containsInAnyOrder(UserRole.USER));
u = userService.setRoles(u, UserRole.USER, UserRole.ADMINISTRATOR);
public void grantRoles() throws NotUniqueUserException, PasswordPolicyException, UserException {
User u = userService.createUser(USER_EMAIL, null, USER_PASSWORD, BasicUser.AccountType.LOCAL);
assertThat("Account must have default role assigned", u.getRoles(), containsInAnyOrder(UserRole.USER));
u = userService.setRoles(u, Sets.newHashSet(UserRole.USER, UserRole.ADMINISTRATOR));
assertThat("Account must have USER and ADMINISTRATOR roles", u.getRoles(), containsInAnyOrder(UserRole.USER, UserRole.ADMINISTRATOR));
u = userService.getUser(u.getId());
assertThat("Account must have USER and ADMINISTRATOR roles", u.getRoles(), containsInAnyOrder(UserRole.USER, UserRole.ADMINISTRATOR));
userService.setRoles(u, UserRole.USER);
userService.setRoles(u, Sets.newHashSet(UserRole.USER));
u = userService.getUser(u.getId());
assertThat("Account must have USER role", u.getRoles(), containsInAnyOrder(UserRole.USER));
}
......
......@@ -21,7 +21,10 @@ import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.oauth.model.OAuthClient;
import org.genesys.blocks.oauth.model.OAuthRole;
import org.genesys.blocks.oauth.persistence.OAuthClientRepository;
import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys.catalog.model.user.User;
import org.genesys.catalog.model.user.UserRole;
import org.genesys.catalog.persistence.user.UserRepository;
......@@ -33,6 +36,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.google.common.collect.Sets;
@Component
public class StartupInitializer implements InitializingBean {
private static final Logger LOG = LoggerFactory.getLogger(StartupInitializer.class);
......@@ -74,7 +79,11 @@ public class StartupInitializer implements InitializingBean {
@Transactional
void startup() {
ensure1Admin();
try {
ensure1Admin();
} catch (UserException e) {
LOG.error("Default admin account could not be created", e);
}
ensure1OAuthClient();
}
......@@ -98,11 +107,11 @@ public class StartupInitializer implements InitializingBean {
}
}
public void ensure1Admin() {
public void ensure1Admin() throws NotUniqueUserException, PasswordPolicyException, UserException {
LOG.info("Startup initializer checking stuff");
if (userRepository.count() == 0) {
final User admin = userService.createUser(defaultAdminEmail, "Administrator", defaultAdminPassword, BasicUser.AccountType.LOCAL);
userService.setRoles(admin, UserRole.ADMINISTRATOR, UserRole.USER);
userService.setRoles(admin, Sets.newHashSet(UserRole.ADMINISTRATOR));
LOG.warn("Default admin email={} password={}", defaultAdminEmail, defaultAdminPassword);
}
LOG.info("Startup initializer done.");
......
......@@ -24,7 +24,10 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys.catalog.model.user.User;
import org.genesys.catalog.server.service.GoogleSocialService;
import org.genesys.catalog.service.UserService;
......@@ -79,19 +82,23 @@ public class GoogleSocialServiceImpl implements GoogleSocialService {
final GoogleIdToken.Payload payload = idToken.getPayload();
final User user = findOrCreateUser(payload.getEmail(), (String) payload.get("name"));
final Set<String> scope = new HashSet<>(Arrays.asList("trust", "read", "write"));
final OAuth2Request oAuth2Request = new OAuth2Request(null, clientId, user.getAuthorities(), true, scope, null, null, null, null);
final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
final OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
return tokenServices.createAccessToken(auth);
try {
final User user = findOrCreateUser(payload.getEmail(), (String) payload.get("name"));
final Set<String> scope = new HashSet<>(Arrays.asList("trust", "read", "write"));
final OAuth2Request oAuth2Request = new OAuth2Request(null, clientId, user.getAuthorities(), true, scope, null, null, null, null);
final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
final OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
return tokenServices.createAccessToken(auth);
} catch (UserException e) {
throw new InvalidTokenException(e.getMessage(), e);
}
}
private User findOrCreateUser(final String email, final String name) {
private User findOrCreateUser(final String email, final String name) throws NotUniqueUserException, PasswordPolicyException, UserException {
User user;
try {
user = userService.getUserByEmail(email);
......@@ -105,7 +112,7 @@ public class GoogleSocialServiceImpl implements GoogleSocialService {
}
} catch (final UsernameNotFoundException e) {
_logger.info("Username not found, creating new Google account");
user = userService.createUser(email, null, name, BasicUser.AccountType.GOOGLE);
user = userService.createUser(email, name, null, BasicUser.AccountType.GOOGLE);
}
return user;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment