Compare commits

..

2 Commits

Author SHA1 Message Date
9a6ba0b70b add spring security 2023-12-04 18:58:10 +04:00
86343ae3a6 add spring security 2023-12-04 18:57:43 +04:00
30 changed files with 1143 additions and 5 deletions

Binary file not shown.

20
pom.xml
View File

@ -21,6 +21,26 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>

View File

@ -0,0 +1,21 @@
package com.gipro.giprolab.config;
public class Constants {
public static final String API_1_0 = "/api/1.0/";
public static final String MAIL_ACTIVATE = "Account activation";
public static final String MAIL_RESET = "Password reset";
public static final int MIN_PASSWORD_LENGTH = 6;
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
public static final String COOKIES_NAME = "JSESSIONID";
public static final String LOGOUT_URL = "/login?logout";
public static final String SESSION_ID_ATTR = "sessionId";
public static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
public static final String PASSWORD_RESET_REQUEST_PAGE = "/resetRequest";
public static final String PASSWORD_RESET_PAGE = "/reset";
public static final String SYSTEM_ENDPOINT_URL = "/metrics";
}

View File

@ -0,0 +1,13 @@
package com.gipro.giprolab.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,76 @@
package com.gipro.giprolab.config;
import com.gipro.giprolab.models.UserRoleConstants;
import com.gipro.giprolab.services.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private final UserService userService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public SecurityConfiguration(UserService userService,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
log.debug("Security enabled");
http
.authorizeHttpRequests((authorize) -> authorize
//.requestMatchers(UserController.ACTIVATE_URL).permitAll()
.requestMatchers(Constants.PASSWORD_RESET_REQUEST_PAGE).permitAll()
.requestMatchers(Constants.PASSWORD_RESET_PAGE).permitAll()
//.requestMatchers(UserController.URL + UserController.REGISTER_URL).permitAll()
//.requestMatchers(UserController.URL + UserController.ACTIVATE_URL).permitAll()
//.requestMatchers(UserController.URL + UserController.PASSWORD_RESET_REQUEST_URL).permitAll()
//.requestMatchers(UserController.URL + UserController.PASSWORD_RESET_URL).permitAll()
.requestMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN)
.anyRequest().authenticated())
.formLogin(fl -> fl
.loginPage("/login")
//.successHandler(authenticationSuccessHandler)
.permitAll())
.csrf(AbstractHttpConfigurer::disable)
.logout(l -> l
//.logoutSuccessHandler(logoutSuccessHandler)
.logoutSuccessUrl(Constants.LOGOUT_URL)
.invalidateHttpSession(false)
.clearAuthentication(true)
.deleteCookies(Constants.COOKIES_NAME)
.permitAll());
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/css/**", "/js/**", "/templates/**", "/webjars/**");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
} catch (Exception e) {
throw new BeanInitializationException("Security configuration failed", e);
}
}
}

View File

@ -0,0 +1,83 @@
package com.gipro.giprolab.core;
import jakarta.persistence.*;
import java.io.Serializable;
@MappedSuperclass
public abstract class BaseEntity implements Serializable, Comparable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
@Version
private Integer version;
public BaseEntity() {
}
public BaseEntity(Integer id, Integer version) {
this.id = id;
this.version = version;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getVersion() {
return version;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
return result;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"id=" + id +
", version=" + version +
'}';
}
@Override
public int compareTo(Object o) {
return id != null ? id.compareTo(((BaseEntity) o).getId()) : -1;
}
public void reset() {
this.id = null;
this.version = null;
}
}

View File

@ -0,0 +1,21 @@
package com.gipro.giprolab.core;
import java.util.Collection;
public class PageableItems<T> {
private final long count;
private final Collection<T> items;
public PageableItems(long count, Collection<T> items) {
this.count = count;
this.items = items;
}
public long getCount() {
return count;
}
public Collection<T> getItems() {
return items;
}
}

View File

@ -0,0 +1,6 @@
package com.gipro.giprolab.error;
public class EntityIdIsNullException extends RuntimeException {
public EntityIdIsNullException() {
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserActivationError extends RuntimeException {
public UserActivationError(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserEmailExistsException extends RuntimeException {
public UserEmailExistsException(String message) {
super(message);
}
}

View File

@ -0,0 +1,6 @@
package com.gipro.giprolab.error;
public class UserIdExistsException extends RuntimeException {
public UserIdExistsException() {
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserIsUndeadException extends RuntimeException {
public UserIsUndeadException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserLoginExistsException extends RuntimeException {
public UserLoginExistsException(String message) {
super(message);
}
}

View File

@ -0,0 +1,6 @@
package com.gipro.giprolab.error;
public class UserNotActivatedException extends RuntimeException {
public UserNotActivatedException() {
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,6 @@
package com.gipro.giprolab.error;
public class UserPasswordsNotValidOrNotMatchException extends RuntimeException {
public UserPasswordsNotValidOrNotMatchException() {
}
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.error;
public class UserResetKeyError extends RuntimeException {
public UserResetKeyError(String message) {
super(message);
}
}

View File

@ -0,0 +1,170 @@
package com.gipro.giprolab.models;
import com.gipro.giprolab.config.Constants;
import com.gipro.giprolab.core.BaseEntity;
import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "is_users")
public class User extends BaseEntity {
@NotNull
@Pattern(regexp = Constants.LOGIN_REGEX)
@Size(min = 1, max = 50)
@Column(length = 50, unique = true, nullable = false)
private String login;
@NotNull
@Size(min = 60, max = 60)
@Column(name = "password_hash", length = 60, nullable = false)
private String password;
@NotNull
@Size(max = 50)
@Column(name = "first_name", length = 50, nullable = false)
private String firstName;
@NotNull
@Size(max = 50)
@Column(name = "last_name", length = 50, nullable = false)
private String lastName;
@NotNull
@Email
@Size(min = 5, max = 100)
@Column(length = 100, nullable = false, unique = true)
private String email;
@NotNull
@Column(nullable = false)
private boolean activated;
@Size(max = 20)
@Column(name = "activation_key", length = 20)
private String activationKey;
@Column(name = "activation_date")
@Temporal(TemporalType.TIMESTAMP)
private Date activationDate;
@Size(max = 20)
@Column(name = "reset_key", length = 20)
private String resetKey;
@Column(name = "reset_date")
@Temporal(TemporalType.TIMESTAMP)
private Date resetDate;
@ManyToMany
@JoinTable(
name = "is_user_role",
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "user_role_name", referencedColumnName = "name")})
private Set<UserRole> roles;
public User() {
roles = new HashSet<>();
activated = false;
activationDate = new Date();
resetDate = null;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login.toLowerCase();
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean getActivated() {
return activated;
}
public String getActivationKey() {
return activationKey;
}
public void setActivationKey(String activationKey) {
this.activationKey = activationKey;
}
public Date getActivationDate() {
return activationDate;
}
public void setActivationDate(Date activationDate) {
this.activationDate = activationDate;
}
public String getResetKey() {
return resetKey;
}
public void setResetKey(String resetKey) {
this.resetKey = resetKey;
}
public Date getResetDate() {
return resetDate;
}
public void setResetDate(Date resetDate) {
this.resetDate = resetDate;
}
public Set<UserRole> getRoles() {
return roles;
}
public void setRoles(Set<UserRole> roles) {
this.roles = roles;
}
public boolean isActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
}

View File

@ -0,0 +1,159 @@
package com.gipro.giprolab.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.gipro.giprolab.config.Constants;
import jakarta.validation.constraints.*;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class UserDto {
private Integer id;
@NotEmpty
@Pattern(regexp = Constants.LOGIN_REGEX)
@Size(min = 4, max = 50)
private String login;
@NotBlank
@Size(min = 2, max = 50)
private String firstName;
@NotBlank
@Size(min = 2, max = 50)
private String lastName;
@Email
@NotBlank
@Size(min = 5, max = 100)
private String email;
private boolean activated;
private LinkedHashSet<UserRoleDto> roles;
@Size(max = 50)
private String oldPassword;
@Size(min = Constants.MIN_PASSWORD_LENGTH, max = 50)
private String password;
@Size(min = Constants.MIN_PASSWORD_LENGTH, max = 50)
private String passwordConfirm;
public UserDto() {
activated = false;
roles = new LinkedHashSet<>();
}
public UserDto(User user) {
this();
this.id = user.getId();
this.login = user.getLogin();
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
this.email = user.getEmail();
this.activated = user.getActivated();
this.roles.addAll(user.getRoles().stream()
.map(UserRoleDto::new)
.collect(Collectors.toList()));
}
public Integer getId() {
return id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
public Set<UserRoleDto> getRoles() {
return roles;
}
public void setRoles(Collection<UserRoleDto> roles) {
this.roles.clear();
this.roles.addAll(roles);
}
public String getOldPassword() {
return oldPassword;
}
public String getPassword() {
return password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
@JsonIgnore
public boolean isPasswordsValid() {
if (StringUtils.isEmpty(password) || StringUtils.isEmpty(passwordConfirm)) {
return false;
}
return Objects.equals(password, passwordConfirm);
}
@JsonIgnore
public boolean isOldPasswordValid() {
return !StringUtils.isEmpty(oldPassword);
}
@Override
public String toString() {
return getClass().getSimpleName() + " {" +
"id=" + id +
", login='" + login + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", activated=" + activated +
", roles=" + roles +
", password='" + password + '\'' +
", passwordConfirm='" + passwordConfirm + '\'' +
'}';
}
}

View File

@ -0,0 +1,29 @@
package com.gipro.giprolab.models;
import com.gipro.giprolab.config.Constants;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import java.util.Objects;
public class UserResetPasswordDto {
@NotEmpty
@Size(min = Constants.MIN_PASSWORD_LENGTH, max = 50)
private String password;
@NotEmpty
@Size(min = Constants.MIN_PASSWORD_LENGTH, max = 50)
private String passwordConfirm;
public String getPassword() {
return password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
public boolean isPasswordsValid() {
return Objects.equals(password, passwordConfirm);
}
}

View File

@ -0,0 +1,50 @@
package com.gipro.giprolab.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity
@Table(name = "is_user_roles")
public class UserRole {
@Id
@NotNull
@Size(max = 50)
@Column(length = 50, nullable = false)
private String name;
public UserRole() {
}
public UserRole(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UserRole role = (UserRole) o;
return !(name != null ? !name.equals(role.name) : role.name != null);
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}

View File

@ -0,0 +1,6 @@
package com.gipro.giprolab.models;
public class UserRoleConstants {
public static final String ADMIN = "ROLE_ADMIN";
public static final String USER = "ROLE_USER";
}

View File

@ -0,0 +1,20 @@
package com.gipro.giprolab.models;
public class UserRoleDto {
private String id;
public UserRoleDto() {
}
public UserRoleDto(UserRole role) {
this.id = role.getName();
}
public UserRoleDto(String name) {
this.id = name;
}
public String getId() {
return id;
}
}

View File

@ -0,0 +1,28 @@
package com.gipro.giprolab.repositories;
import com.gipro.giprolab.models.User;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Date;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Integer> {
User findOneByActivationKey(String activationKey);
List<User> findAllByActivatedIsFalseAndActivationDateBefore(Date date);
User findOneByResetKey(String resetKey);
List<User> findAllByResetKeyNotNullAndResetDateBefore(Date date);
User findOneByEmailIgnoreCase(String email);
User findOneByLoginIgnoreCase(String login);
@EntityGraph(attributePaths = "roles")
User findOneWithRolesById(int id);
@EntityGraph(attributePaths = "roles")
User findOneWithRolesByLogin(String login);
}

View File

@ -0,0 +1,7 @@
package com.gipro.giprolab.repositories;
import com.gipro.giprolab.models.UserRole;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRoleRepository extends JpaRepository<UserRole, String> {
}

View File

@ -0,0 +1,56 @@
package com.gipro.giprolab.services;
import com.gipro.giprolab.models.User;
import com.gipro.giprolab.models.UserDto;
import com.gipro.giprolab.models.UserRole;
import com.gipro.giprolab.models.UserRoleDto;
import com.gipro.giprolab.repositories.UserRoleRepository;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Service
public class UserMapper {
private final UserRoleRepository userRoleRepository;
public UserMapper(UserRoleRepository userRoleRepository) {
this.userRoleRepository = userRoleRepository;
}
public Set<UserRole> rolesFromDto(Set<UserRoleDto> strings) {
return Optional.ofNullable(strings).orElse(Collections.emptySet()).stream()
.filter(Objects::nonNull)
.map(role -> userRoleRepository.findById(role.getId()).orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
public UserDto userEntityToUserDto(User userEntity) {
if (userEntity == null) {
return null;
}
return new UserDto(userEntity);
}
public User userDtoToUserEntity(UserDto userDto) {
if (userDto == null) {
return null;
}
final User user = new User();
user.setId(userDto.getId());
user.setLogin(userDto.getLogin());
user.setFirstName(userDto.getFirstName());
user.setLastName(userDto.getLastName());
user.setEmail(userDto.getEmail());
user.setActivated(userDto.isActivated());
final Set<UserRole> roles = this.rolesFromDto(userDto.getRoles());
if (!roles.isEmpty()) {
user.setRoles(roles);
}
return user;
}
}

View File

@ -0,0 +1,262 @@
package com.gipro.giprolab.services;
import com.gipro.giprolab.core.BaseEntity;
import com.gipro.giprolab.core.PageableItems;
import com.gipro.giprolab.error.*;
import com.gipro.giprolab.models.*;
import com.gipro.giprolab.repositories.UserRepository;
import com.gipro.giprolab.repositories.UserRoleRepository;
import com.gipro.giprolab.util.UserUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional
public class UserService implements UserDetailsService {
private final Logger log = LoggerFactory.getLogger(UserService.class);
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final UserRoleRepository userRoleRepository;
private final UserMapper userMapper;
public UserService(UserRepository userRepository,
PasswordEncoder passwordEncoder,
UserRoleRepository userRoleRepository,
UserMapper userMapper) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.userRoleRepository = userRoleRepository;
this.userMapper = userMapper;
}
private User getUserByEmail(String email) {
return userRepository.findOneByEmailIgnoreCase(email);
}
private User getUserByActivationKey(String activationKey) {
return userRepository.findOneByActivationKey(activationKey);
}
public User getUserByLogin(String login) {
return userRepository.findOneByLoginIgnoreCase(login);
}
@Transactional(readOnly = true)
public UserDto getUserWithRolesById(Integer userId) {
final User userEntity = userRepository.findOneWithRolesById(userId);
if (userEntity == null) {
throw new UserNotFoundException(userId.toString());
}
return userMapper.userEntityToUserDto(userEntity);
}
@Transactional(readOnly = true)
public PageableItems<UserRole> getUserRoles() {
final List<UserRole> roles = userRoleRepository.findAll();
return new PageableItems<>(roles.size(), roles);
}
public UserDto createUser(UserDto userDto) {
if (userDto.getId() != null) {
throw new UserIdExistsException();
}
if (getUserByLogin(userDto.getLogin()) != null) {
throw new UserLoginExistsException(userDto.getLogin());
}
if (getUserByEmail(userDto.getEmail()) != null) {
throw new UserEmailExistsException(userDto.getEmail());
}
if (!userDto.isPasswordsValid()) {
throw new UserPasswordsNotValidOrNotMatchException();
}
User user = userMapper.userDtoToUserEntity(userDto);
user.setActivated(false);
user.setActivationKey(UserUtils.generateActivationKey());
user.setRoles(Collections.singleton(new UserRole(UserRoleConstants.USER)));
user.setPassword(passwordEncoder.encode(userDto.getPassword()));
user = userRepository.save(user);
//TODO: mailService.sendActivationEmail(user);
log.debug("Created Information for User: {}", user.getLogin());
return userMapper.userEntityToUserDto(user);
}
public UserDto activateUser(String activationKey) {
final User user = getUserByActivationKey(activationKey);
if (user == null) {
throw new UserActivationError(activationKey);
}
user.setActivated(true);
user.setActivationKey(null);
user.setActivationDate(null);
log.debug("Activated user: {}", user.getLogin());
return userMapper.userEntityToUserDto(userRepository.save(user));
}
public UserDto updateUser(UserDto userDto) {
if (userDto.getId() == null) {
throw new EntityIdIsNullException();
}
if (!Objects.equals(
Optional.ofNullable(getUserByEmail(userDto.getEmail()))
.map(BaseEntity::getId).orElse(userDto.getId()),
userDto.getId())) {
throw new UserEmailExistsException(userDto.getEmail());
}
if (!Objects.equals(
Optional.ofNullable(getUserByLogin(userDto.getLogin()))
.map(BaseEntity::getId).orElse(userDto.getId()),
userDto.getId())) {
throw new UserLoginExistsException(userDto.getLogin());
}
User user = userRepository.findById(userDto.getId()).orElse(null);
if (user == null) {
throw new UserNotFoundException(userDto.getId().toString());
}
user.setLogin(userDto.getLogin());
user.setFirstName(userDto.getFirstName());
user.setLastName(userDto.getLastName());
user.setEmail(userDto.getEmail());
if (userDto.isActivated() != user.getActivated()) {
if (userDto.isActivated()) {
user.setActivationKey(null);
user.setActivationDate(null);
} else {
user.setActivationKey(UserUtils.generateActivationKey());
user.setActivationDate(new Date());
}
}
user.setActivated(userDto.isActivated());
final Set<UserRole> roles = userMapper.rolesFromDto(userDto.getRoles());
user.setRoles(roles.isEmpty()
? Collections.singleton(new UserRole(UserRoleConstants.USER))
: roles);
if (!StringUtils.isEmpty(userDto.getOldPassword())) {
if (!userDto.isPasswordsValid() || !userDto.isOldPasswordValid()) {
throw new UserPasswordsNotValidOrNotMatchException();
}
if (!passwordEncoder.matches(userDto.getOldPassword(), user.getPassword())) {
throw new UserPasswordsNotValidOrNotMatchException();
}
user.setPassword(passwordEncoder.encode(userDto.getPassword()));
log.debug("Changed password for User: {}", user.getLogin());
}
user = userRepository.save(user);
log.debug("Changed Information for User: {}", user.getLogin());
return userMapper.userEntityToUserDto(user);
}
public UserDto updateUserInformation(UserDto userDto) {
if (userDto.getId() == null) {
throw new EntityIdIsNullException();
}
if (!Objects.equals(
Optional.ofNullable(getUserByEmail(userDto.getEmail()))
.map(BaseEntity::getId).orElse(userDto.getId()),
userDto.getId())) {
throw new UserEmailExistsException(userDto.getEmail());
}
User user = userRepository.findById(userDto.getId()).orElse(null);
if (user == null) {
throw new UserNotFoundException(userDto.getId().toString());
}
user.setFirstName(userDto.getFirstName());
user.setLastName(userDto.getLastName());
user.setEmail(userDto.getEmail());
user = userRepository.save(user);
log.debug("Updated Information for User: {}", user.getLogin());
return userMapper.userEntityToUserDto(user);
}
public UserDto changeUserPassword(UserDto userDto) {
if (userDto.getId() == null) {
throw new EntityIdIsNullException();
}
if (!userDto.isPasswordsValid() || !userDto.isOldPasswordValid()) {
throw new UserPasswordsNotValidOrNotMatchException();
}
final User user = getCurrentUser();
if (!passwordEncoder.matches(userDto.getOldPassword(), user.getPassword())) {
throw new UserPasswordsNotValidOrNotMatchException();
}
user.setPassword(passwordEncoder.encode(userDto.getPassword()));
log.debug("Changed password for User: {}", user.getLogin());
return userMapper.userEntityToUserDto(userRepository.save(user));
}
public User getCurrentUser() {
String login = UserUtils.getCurrentUserLogin();
User user = userRepository.findOneByLoginIgnoreCase(login);
if (user == null) {
throw new UserNotFoundException(login);
}
return user;
}
public boolean requestUserPasswordReset(String email) {
User user = userRepository.findOneByEmailIgnoreCase(email);
if (user == null) {
throw new UserNotFoundException(email);
}
if (!user.getActivated()) {
throw new UserNotActivatedException();
}
user.setResetKey(UserUtils.generateResetKey());
user.setResetDate(new Date());
user = userRepository.save(user);
// mailService.sendPasswordResetMail(user);
log.debug("Created Reset Password Request for User: {}", user.getLogin());
return true;
}
public boolean completeUserPasswordReset(String key, UserResetPasswordDto userResetPasswordDto) {
if (!userResetPasswordDto.isPasswordsValid()) {
throw new UserPasswordsNotValidOrNotMatchException();
}
User user = userRepository.findOneByResetKey(key);
if (user == null) {
throw new UserResetKeyError(key);
}
user.setPassword(passwordEncoder.encode(userResetPasswordDto.getPassword()));
user.setResetKey(null);
user.setResetDate(null);
user = userRepository.save(user);
log.debug("Reset Password for User: {}", user.getLogin());
return true;
}
public UserDto deleteUser(Integer userId) {
final User user = userRepository.findById(userId).orElse(null);
userRepository.delete(user);
log.debug("Deleted User: {}", user.getLogin());
return userMapper.userEntityToUserDto(user);
}
@Override
public UserDetails loadUserByUsername(String username) {
final User user = userRepository.findOneByLoginIgnoreCase(username);
if (user == null) {
throw new UserNotFoundException(username);
}
if (!user.getActivated()) {
throw new UserNotActivatedException();
}
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
Optional.ofNullable(user.getRoles()).orElse(Collections.emptySet()).stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,35 @@
package com.gipro.giprolab.util;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
public class UserUtils {
private static final int DEF_COUNT = 20;
public static String generateActivationKey() {
return RandomStringUtils.randomNumeric(DEF_COUNT);
}
public static String generateResetKey() {
return RandomStringUtils.randomNumeric(DEF_COUNT);
}
public static String getCurrentUserLogin() {
final SecurityContext securityContext = SecurityContextHolder.getContext();
if (securityContext == null) {
return null;
}
final Authentication authentication = securityContext.getAuthentication();
if (authentication.getPrincipal() instanceof UserDetails) {
final UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
return springSecurityUser.getUsername();
}
if (authentication.getPrincipal() instanceof String) {
return (String) authentication.getPrincipal();
}
return null;
}
}

View File

@ -1,6 +1,15 @@
spring.jpa.hibernate.ddl-auto=update #spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/giproclientsandfilesdb #spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/giproclientsandfilesdb
spring.datasource.username=root #spring.datasource.username=root
spring.datasource.password= #spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.jpa.show-sql: true #spring.jpa.show-sql: true
spring.main.allow-bean-definition-overriding=true
spring.jackson.serialization.fail-on-empty-beans=false
spring.datasource.url=jdbc:h2:file:./data/giproclientsandfilesdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update