userList = userService.findAllUsers();
35 | return new ResponseEntity<>(userList, HttpStatus.OK);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/AuthoritiesConstants.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security;
2 |
3 | /**
4 | * Constants for Spring Security authorities.
5 | */
6 | public final class AuthoritiesConstants {
7 |
8 | public static final String ADMIN = "ROLE_ADMIN";
9 |
10 | public static final String USER = "ROLE_USER";
11 |
12 | public static final String ANONYMOUS = "ROLE_ANONYMOUS";
13 |
14 | private AuthoritiesConstants() { }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/SecurityUtils.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security;
2 |
3 | import org.springframework.security.core.Authentication;
4 | import org.springframework.security.core.GrantedAuthority;
5 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
6 | import org.springframework.security.core.context.SecurityContext;
7 | import org.springframework.security.core.context.SecurityContextHolder;
8 | import org.springframework.security.core.userdetails.UserDetails;
9 |
10 | import java.util.Collection;
11 |
12 | /**
13 | * Utility class for Spring Security.
14 | */
15 | public final class SecurityUtils {
16 |
17 | /**
18 | * Get the login of the current user.
19 | *
20 | * @return the login of the current user
21 | */
22 | public static String getCurrentUserLogin()
23 | {
24 | SecurityContext securityContext = SecurityContextHolder.getContext();
25 | Authentication authentication = securityContext.getAuthentication();
26 | String userName = null;
27 | if (authentication != null)
28 | {
29 | if (authentication.getPrincipal() instanceof UserDetails)
30 | {
31 | UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
32 | userName = springSecurityUser.getUsername();
33 | }
34 | else if (authentication.getPrincipal() instanceof String){
35 | userName = (String) authentication.getPrincipal();
36 | }
37 | }
38 | return userName;
39 | }
40 |
41 | /**
42 | * Check if a user is authenticated.
43 | *
44 | * @return true if the user is authenticated, false otherwise
45 | */
46 | public static boolean isAuthenticated()
47 | {
48 | SecurityContext securityContext = SecurityContextHolder.getContext();
49 | Collection extends GrantedAuthority> authorities = securityContext.getAuthentication().getAuthorities();
50 | if (authorities != null)
51 | {
52 | for (GrantedAuthority authority : authorities)
53 | {
54 | if (authority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS))
55 | return false;
56 | }
57 | }
58 | return true;
59 | }
60 |
61 | /**
62 | * If the current user has a specific authority (security role).
63 | *
64 | * The name of this method comes from the isUserInRole() method in the Servlet API
65 | *
66 | * @param authority the authorithy to check
67 | * @return true if the current user has the authority, false otherwise
68 | */
69 | public static boolean isCurrentUserInRole(String authority)
70 | {
71 | SecurityContext securityContext = SecurityContextHolder.getContext();
72 | Authentication authentication = securityContext.getAuthentication();
73 | if (authentication != null)
74 | {
75 | if (authentication.getPrincipal() instanceof UserDetails)
76 | {
77 | UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
78 | return springSecurityUser.getAuthorities().contains(new SimpleGrantedAuthority(authority));
79 | }
80 | }
81 | return false;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/UserDetailsService.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security;
2 |
3 |
4 | import com.starter.springboot.domain.User;
5 | import com.starter.springboot.exceptions.UserNotActivatedException;
6 | import com.starter.springboot.repositories.UserRepository;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.security.core.GrantedAuthority;
11 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
12 | import org.springframework.security.core.userdetails.UserDetails;
13 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
14 | import org.springframework.stereotype.Component;
15 | import org.springframework.transaction.annotation.Transactional;
16 |
17 | import java.util.List;
18 | import java.util.Optional;
19 | import java.util.stream.Collectors;
20 |
21 | /**
22 | * Authenticate a user from the database.
23 | */
24 | @Component("userDetailsService")
25 | public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
26 |
27 | private final Logger log = LoggerFactory.getLogger(UserDetailsService.class);
28 |
29 | @Autowired
30 | private UserRepository userRepository;
31 |
32 | @Override
33 | @Transactional
34 | public UserDetails loadUserByUsername(final String login)
35 | {
36 | log.debug("Authenticating {}", login);
37 | String lowercaseLogin = login.toLowerCase();
38 | Optional userFromDatabase = userRepository.findByUsername(lowercaseLogin);
39 | return userFromDatabase.map(user -> {
40 | if (user.getEnabled() == null || !user.getEnabled()) {
41 | throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
42 | }
43 | List grantedAuthorities = user.getRoles().stream()
44 | .map(role -> new SimpleGrantedAuthority(role.getId().toString()))
45 | .collect(Collectors.toList());
46 |
47 | return new org.springframework.security.core.userdetails.User(lowercaseLogin,
48 | user.getPassword(),
49 | grantedAuthorities);
50 | }).orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " +
51 | "database"));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/jwt/JWTConfigurer.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security.jwt;
2 |
3 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5 | import org.springframework.security.web.DefaultSecurityFilterChain;
6 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
7 |
8 |
9 | public class JWTConfigurer extends SecurityConfigurerAdapter {
10 |
11 | public final static String AUTHORIZATION_HEADER = "Authorization";
12 |
13 | public final static String AUTHORIZATION_TOKEN = "access_token";
14 |
15 | private TokenProvider tokenProvider;
16 |
17 | public JWTConfigurer(TokenProvider tokenProvider) {
18 | this.tokenProvider = tokenProvider;
19 | }
20 |
21 | @Override
22 | public void configure(HttpSecurity http) throws Exception {
23 | JWTFilter customFilter = new JWTFilter(tokenProvider);
24 | http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/jwt/JWTFilter.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security.jwt;
2 |
3 | import io.jsonwebtoken.ExpiredJwtException;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.security.core.Authentication;
7 | import org.springframework.security.core.context.SecurityContextHolder;
8 | import org.springframework.util.StringUtils;
9 | import org.springframework.web.filter.GenericFilterBean;
10 |
11 | import javax.servlet.FilterChain;
12 | import javax.servlet.ServletException;
13 | import javax.servlet.ServletRequest;
14 | import javax.servlet.ServletResponse;
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 |
19 | /**
20 | * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
21 | * found.
22 | */
23 | public class JWTFilter extends GenericFilterBean {
24 |
25 | private final Logger log = LoggerFactory.getLogger(JWTFilter.class);
26 |
27 | private TokenProvider tokenProvider;
28 |
29 | public JWTFilter(TokenProvider tokenProvider) {
30 | this.tokenProvider = tokenProvider;
31 | }
32 |
33 | /**
34 | * Method for filtering JWT Token.
35 | *
36 | * @param servletRequest - Http request
37 | * @param servletResponse - Http response
38 | * @param filterChain - filter chain
39 | * @throws IOException - Input/Output exception
40 | * @throws ServletException - Servlet exception
41 | */
42 | @Override
43 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
44 | throws IOException, ServletException
45 | {
46 | try
47 | {
48 | HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
49 | String jwt = resolveToken(httpServletRequest);
50 | if (StringUtils.hasText(jwt))
51 | {
52 | if (this.tokenProvider.validateToken(jwt))
53 | {
54 | Authentication authentication = this.tokenProvider.getAuthentication(jwt);
55 | SecurityContextHolder.getContext().setAuthentication(authentication);
56 | }
57 | }
58 | filterChain.doFilter(servletRequest, servletResponse);
59 | }
60 | catch (ExpiredJwtException eje) {
61 | log.info("Security exception for user {} - {}", eje.getClaims().getSubject(), eje.getMessage());
62 | ((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
63 | }
64 | }
65 |
66 | /**
67 | * Method for resolving token
68 | *
69 | * @param request - Http request
70 | * @return Token string | null
71 | */
72 | private String resolveToken(HttpServletRequest request)
73 | {
74 | String bearerToken = request.getHeader(JWTConfigurer.AUTHORIZATION_HEADER);
75 | if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")){
76 | return bearerToken.substring(7, bearerToken.length());
77 | }
78 | String jwt = request.getParameter(JWTConfigurer.AUTHORIZATION_TOKEN);
79 | if (StringUtils.hasText(jwt)) {
80 | return jwt;
81 | }
82 | return null;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/jwt/JWTToken.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security.jwt;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 |
5 |
6 | public class JWTToken {
7 |
8 | private String idToken;
9 |
10 | public JWTToken(String idToken) {
11 | this.idToken = idToken;
12 | }
13 |
14 | @JsonProperty("id_token")
15 | public String getIdToken() {
16 | return idToken;
17 | }
18 |
19 | public void setIdToken(String idToken) {
20 | this.idToken = idToken;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/security/jwt/TokenProvider.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.security.jwt;
2 |
3 | import com.starter.springboot.domain.User;
4 | import com.starter.springboot.repositories.UserRepository;
5 | import com.starter.springboot.services.OtpService;
6 | import io.jsonwebtoken.Claims;
7 | import io.jsonwebtoken.Jwts;
8 | import io.jsonwebtoken.SignatureAlgorithm;
9 | import io.jsonwebtoken.SignatureException;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
15 | import org.springframework.security.core.Authentication;
16 | import org.springframework.security.core.GrantedAuthority;
17 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
18 | import org.springframework.stereotype.Component;
19 |
20 | import javax.persistence.EntityNotFoundException;
21 | import java.util.Arrays;
22 | import java.util.Collection;
23 | import java.util.Date;
24 | import java.util.List;
25 | import java.util.stream.Collectors;
26 |
27 | @Component
28 | public class TokenProvider {
29 |
30 | private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
31 |
32 | private static final String AUTHORITIES_KEY = "auth";
33 |
34 | @Value("${jwt.secret}")
35 | private String secretKey;
36 |
37 | @Value("${jwt.expiration}")
38 | private long tokenValidityInSeconds;
39 |
40 | @Value("${jwt.expiration}")
41 | private long tokenValidityInSecondsForRememberMe;
42 |
43 | @Autowired
44 | private OtpService otpService;
45 |
46 | @Autowired
47 | private UserRepository userRepository;
48 |
49 |
50 | /**
51 | * Create token from authentication
52 | *
53 | * @param authentication authentication object
54 | * @param rememberMe remember me indicator
55 | * @return String as token
56 | */
57 | public String createToken(Authentication authentication, Boolean rememberMe)
58 | {
59 | String username = authentication.getName();
60 | User user = userRepository
61 | .findByUsername(username)
62 | .orElseThrow(() -> new EntityNotFoundException("User with username " + username + " not found!"));
63 |
64 | if (user.getIsOtpRequired())
65 | {
66 | otpService.generateOtp(user.getUsername());
67 | return null;
68 | }
69 | return generateToken(authentication, rememberMe);
70 | }
71 |
72 | /**
73 | * Create token after verified OTP code
74 | *
75 | * @param username provided username
76 | * @param rememberMe remember me indicator
77 | * @return String token value
78 | */
79 | public String createTokenAfterVerifiedOtp(String username, Boolean rememberMe)
80 | {
81 | User user = userRepository
82 | .findByUsername(username)
83 | .orElseThrow(() -> new EntityNotFoundException("User not found!"));
84 |
85 | List authorities = user.getRoles()
86 | .stream()
87 | .map(role -> new SimpleGrantedAuthority(role.getName()))
88 | .collect(Collectors.toList());
89 |
90 | Authentication authentication = new UsernamePasswordAuthenticationToken(
91 | user.getUsername(), user.getPassword(), authorities
92 | );
93 |
94 | return generateToken(authentication, rememberMe);
95 | }
96 |
97 | /**
98 | * Method for getting authentication context.
99 | *
100 | * @param token provided token
101 | * @return Authentication Object
102 | */
103 | public Authentication getAuthentication(String token)
104 | {
105 | Claims claims = Jwts.parser()
106 | .setSigningKey(secretKey)
107 | .parseClaimsJws(token)
108 | .getBody();
109 |
110 | String principal = claims.getSubject();
111 | Collection extends GrantedAuthority> authorities = Arrays
112 | .stream(claims.get(AUTHORITIES_KEY).toString().split(","))
113 | .map(SimpleGrantedAuthority::new)
114 | .collect(Collectors.toList());
115 |
116 | return new UsernamePasswordAuthenticationToken(principal, "", authorities);
117 | }
118 |
119 | /**
120 | * Method for validate token.
121 | *
122 | * @param authToken - JWT token
123 | * @return true | false
124 | */
125 | public boolean validateToken(String authToken)
126 | {
127 | try
128 | {
129 | Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
130 | return true;
131 | }
132 | catch (SignatureException e)
133 | {
134 | log.error("Invalid JWT signature: {}", e.getMessage());
135 | return false;
136 | }
137 | }
138 |
139 | /**
140 | * Generating token from authentication object
141 | *
142 | * @param authentication provided authentication
143 | * @param rememberMe remember me indicator
144 | * @return String value of jwt token
145 | */
146 | private String generateToken(Authentication authentication, Boolean rememberMe)
147 | {
148 | String authorities = authentication.getAuthorities().stream()
149 | .map(GrantedAuthority::getAuthority)
150 | .collect(Collectors.joining(","));
151 |
152 | long now = new Date().getTime();
153 | Date validity;
154 | if (Boolean.TRUE.equals(rememberMe)) {
155 | validity = new Date(now + this.tokenValidityInSecondsForRememberMe * 1000);
156 | }
157 | else {
158 | validity = new Date(now + this.tokenValidityInSeconds * 1000);
159 | }
160 |
161 | return Jwts.builder()
162 | .setSubject(authentication.getName())
163 | .claim(AUTHORITIES_KEY, authorities)
164 | .signWith(SignatureAlgorithm.HS512, secretKey)
165 | .setExpiration(validity)
166 | .compact();
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/services/EmailService.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.services;
2 |
3 | import com.starter.springboot.rest.dto.EmailDTO;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.mail.SimpleMailMessage;
8 | import org.springframework.mail.javamail.JavaMailSender;
9 | import org.springframework.stereotype.Service;
10 |
11 | import java.util.stream.Collectors;
12 |
13 | @Service
14 | public class EmailService {
15 |
16 | private final Logger LOGGER = LoggerFactory.getLogger(EmailService.class);
17 |
18 | @Autowired
19 | private JavaMailSender emailSender;
20 |
21 | /**
22 | * Method for sending simple e-mail message.
23 | * @param emailDTO - data to be send.
24 | */
25 | public Boolean sendSimpleMessage(EmailDTO emailDTO)
26 | {
27 | SimpleMailMessage mailMessage = new SimpleMailMessage();
28 | mailMessage.setTo(emailDTO.getRecipients().stream().collect(Collectors.joining(",")));
29 | mailMessage.setSubject(emailDTO.getSubject());
30 | mailMessage.setText(emailDTO.getBody());
31 |
32 | Boolean isSent = false;
33 | try
34 | {
35 | emailSender.send(mailMessage);
36 | isSent = true;
37 | }
38 | catch (Exception e) {
39 | LOGGER.error("Sending e-mail error: {}", e.getMessage());
40 | }
41 | return isSent;
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/services/OtpGenerator.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.services;
2 |
3 | import com.google.common.cache.CacheBuilder;
4 | import com.google.common.cache.CacheLoader;
5 | import com.google.common.cache.LoadingCache;
6 | import org.springframework.context.annotation.Description;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.Random;
10 | import java.util.concurrent.ExecutionException;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | @Description(value = "Service for generating and validating OTP.")
14 | @Service
15 | public class OtpGenerator {
16 |
17 | private static final Integer EXPIRE_MIN = 5;
18 | private LoadingCache otpCache;
19 |
20 | /**
21 | * Constructor configuration.
22 | */
23 | public OtpGenerator()
24 | {
25 | super();
26 | otpCache = CacheBuilder.newBuilder()
27 | .expireAfterWrite(EXPIRE_MIN, TimeUnit.MINUTES)
28 | .build(new CacheLoader() {
29 | @Override
30 | public Integer load(String s) throws Exception {
31 | return 0;
32 | }
33 | });
34 | }
35 |
36 | /**
37 | * Method for generating OTP and put it in cache.
38 | *
39 | * @param key - cache key
40 | * @return cache value (generated OTP number)
41 | */
42 | public Integer generateOTP(String key)
43 | {
44 | Random random = new Random();
45 | int OTP = 100000 + random.nextInt(900000);
46 | otpCache.put(key, OTP);
47 |
48 | return OTP;
49 | }
50 |
51 | /**
52 | * Method for getting OTP value by key.
53 | *
54 | * @param key - target key
55 | * @return OTP value
56 | */
57 | public Integer getOPTByKey(String key)
58 | {
59 | return otpCache.getIfPresent(key);
60 | }
61 |
62 | /**
63 | * Method for removing key from cache.
64 | *
65 | * @param key - target key
66 | */
67 | public void clearOTPFromCache(String key) {
68 | otpCache.invalidate(key);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/services/OtpService.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.services;
2 |
3 | import com.starter.springboot.rest.dto.EmailDTO;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.context.annotation.Description;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | @Description(value = "Service responsible for handling OTP related functionality.")
13 | @Service
14 | public class OtpService {
15 |
16 | private final Logger LOGGER = LoggerFactory.getLogger(OtpService.class);
17 |
18 | private OtpGenerator otpGenerator;
19 | private EmailService emailService;
20 | private UserService userService;
21 |
22 | /**
23 | * Constructor dependency injector
24 | * @param otpGenerator - otpGenerator dependency
25 | * @param emailService - email service dependency
26 | * @param userService - user service dependency
27 | */
28 | public OtpService(OtpGenerator otpGenerator, EmailService emailService, UserService userService)
29 | {
30 | this.otpGenerator = otpGenerator;
31 | this.emailService = emailService;
32 | this.userService = userService;
33 | }
34 |
35 | /**
36 | * Method for generate OTP number
37 | *
38 | * @param key - provided key (username in this case)
39 | * @return boolean value (true|false)
40 | */
41 | public Boolean generateOtp(String key)
42 | {
43 | // generate otp
44 | Integer otpValue = otpGenerator.generateOTP(key);
45 | if (otpValue == -1)
46 | {
47 | LOGGER.error("OTP generator is not working...");
48 | return false;
49 | }
50 |
51 | LOGGER.info("Generated OTP: {}", otpValue);
52 |
53 | // fetch user e-mail from database
54 | String userEmail = userService.findEmailByUsername(key);
55 | List recipients = new ArrayList<>();
56 | recipients.add(userEmail);
57 |
58 | // generate emailDTO object
59 | EmailDTO emailDTO = new EmailDTO();
60 | emailDTO.setSubject("Spring Boot OTP Password.");
61 | emailDTO.setBody("OTP Password: " + otpValue);
62 | emailDTO.setRecipients(recipients);
63 |
64 | // send generated e-mail
65 | return emailService.sendSimpleMessage(emailDTO);
66 | }
67 |
68 | /**
69 | * Method for validating provided OTP
70 | *
71 | * @param key - provided key
72 | * @param otpNumber - provided OTP number
73 | * @return boolean value (true|false)
74 | */
75 | public Boolean validateOTP(String key, Integer otpNumber)
76 | {
77 | // get OTP from cache
78 | Integer cacheOTP = otpGenerator.getOPTByKey(key);
79 | if (cacheOTP!=null && cacheOTP.equals(otpNumber))
80 | {
81 | otpGenerator.clearOTPFromCache(key);
82 | return true;
83 | }
84 | return false;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/services/UserService.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.services;
2 |
3 | import com.starter.springboot.domain.User;
4 | import com.starter.springboot.repositories.UserRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.List;
9 | import java.util.Optional;
10 |
11 | @Service
12 | public class UserService {
13 |
14 | @Autowired
15 | private UserRepository userRepository;
16 |
17 | /**
18 | * Method for getting all users
19 | *
20 | * @return List of user objects.
21 | */
22 | public List findAllUsers() {
23 | return this.userRepository.findAll();
24 | }
25 |
26 | /**
27 | * Method for getting e-mail by username (key)
28 | *
29 | * @param username - provided username
30 | * @return e-mail
31 | */
32 | public String findEmailByUsername(String username)
33 | {
34 | Optional user = userRepository.findByUsername(username);
35 | if (user.isPresent()) {
36 | return user.get().getEmail();
37 | }
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/utils/JSR310DateConverters.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.utils;
2 |
3 | import org.springframework.core.convert.converter.Converter;
4 |
5 | import java.time.LocalDate;
6 | import java.time.LocalDateTime;
7 | import java.time.ZoneId;
8 | import java.time.ZonedDateTime;
9 | import java.util.Date;
10 |
11 | public final class JSR310DateConverters {
12 |
13 | private JSR310DateConverters() {}
14 |
15 | public static class LocalDateToDateConverter implements Converter {
16 |
17 | public static final LocalDateToDateConverter INSTANCE = new LocalDateToDateConverter();
18 |
19 | private LocalDateToDateConverter() {}
20 |
21 | @Override
22 | public Date convert(LocalDate source) {
23 | return source == null ? null : Date.from(source.atStartOfDay(ZoneId.systemDefault()).toInstant());
24 | }
25 | }
26 |
27 | public static class DateToLocalDateConverter implements Converter {
28 | public static final DateToLocalDateConverter INSTANCE = new DateToLocalDateConverter();
29 | private DateToLocalDateConverter() {}
30 |
31 | @Override
32 | public LocalDate convert(Date source) {
33 | return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault()).toLocalDate();
34 | }
35 | }
36 |
37 | public static class ZonedDateTimeToDateConverter implements Converter {
38 | public static final ZonedDateTimeToDateConverter INSTANCE = new ZonedDateTimeToDateConverter();
39 | private ZonedDateTimeToDateConverter() {}
40 |
41 | @Override
42 | public Date convert(ZonedDateTime source) {
43 | return source == null ? null : Date.from(source.toInstant());
44 | }
45 | }
46 |
47 | public static class DateToZonedDateTimeConverter implements Converter {
48 | public static final DateToZonedDateTimeConverter INSTANCE = new DateToZonedDateTimeConverter();
49 | private DateToZonedDateTimeConverter() {}
50 |
51 | @Override
52 | public ZonedDateTime convert(Date source) {
53 | return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
54 | }
55 | }
56 |
57 | public static class LocalDateTimeToDateConverter implements Converter {
58 | public static final LocalDateTimeToDateConverter INSTANCE = new LocalDateTimeToDateConverter();
59 | private LocalDateTimeToDateConverter() {}
60 |
61 | @Override
62 | public Date convert(LocalDateTime source) {
63 | return source == null ? null : Date.from(source.atZone(ZoneId.systemDefault()).toInstant());
64 | }
65 | }
66 |
67 | public static class DateToLocalDateTimeConverter implements Converter {
68 | public static final DateToLocalDateTimeConverter INSTANCE = new DateToLocalDateTimeConverter();
69 | private DateToLocalDateTimeConverter() {}
70 |
71 | @Override
72 | public LocalDateTime convert(Date source) {
73 | return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/utils/JSR310DateTimeSerializer.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.utils;
2 |
3 | import com.fasterxml.jackson.core.JsonGenerator;
4 | import com.fasterxml.jackson.databind.JsonSerializer;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 |
7 | import java.io.IOException;
8 | import java.time.ZoneId;
9 | import java.time.format.DateTimeFormatter;
10 | import java.time.temporal.TemporalAccessor;
11 |
12 | public final class JSR310DateTimeSerializer extends JsonSerializer {
13 |
14 | private static final DateTimeFormatter ISOFormatter =
15 | DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(ZoneId.of("Z"));
16 |
17 | public static final JSR310DateTimeSerializer INSTANCE = new JSR310DateTimeSerializer();
18 |
19 | private JSR310DateTimeSerializer() {}
20 |
21 | @Override
22 | public void serialize(TemporalAccessor value, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException {
23 | generator.writeString(ISOFormatter.format(value));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/utils/JSR310LocalDateDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.utils;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonToken;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 |
8 | import java.io.IOException;
9 | import java.time.LocalDate;
10 | import java.time.format.DateTimeFormatter;
11 | import java.time.format.DateTimeFormatterBuilder;
12 |
13 | /**
14 | * Custom Jackson deserializer for transforming a JSON object (using the ISO 8601 date formatwith optional time)
15 | * to a JSR310 LocalDate object.
16 | */
17 | public class JSR310LocalDateDeserializer extends JsonDeserializer {
18 |
19 | public static final JSR310LocalDateDeserializer INSTANCE = new JSR310LocalDateDeserializer();
20 |
21 | private JSR310LocalDateDeserializer() {}
22 |
23 | private static final DateTimeFormatter ISO_DATE_OPTIONAL_TIME;
24 |
25 | static {
26 | ISO_DATE_OPTIONAL_TIME = new DateTimeFormatterBuilder()
27 | .append(DateTimeFormatter.ISO_LOCAL_DATE)
28 | .optionalStart()
29 | .appendLiteral('T')
30 | .append(DateTimeFormatter.ISO_OFFSET_TIME)
31 | .toFormatter();
32 | }
33 |
34 | @Override
35 | public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
36 | switch(parser.getCurrentToken()) {
37 | case START_ARRAY:
38 | if(parser.nextToken() == JsonToken.END_ARRAY) {
39 | return null;
40 | }
41 | int year = parser.getIntValue();
42 |
43 | parser.nextToken();
44 | int month = parser.getIntValue();
45 |
46 | parser.nextToken();
47 | int day = parser.getIntValue();
48 |
49 | if(parser.nextToken() != JsonToken.END_ARRAY) {
50 | throw context.wrongTokenException(parser, JsonToken.END_ARRAY, "Expected array to end.");
51 | }
52 | return LocalDate.of(year, month, day);
53 |
54 | case VALUE_STRING:
55 | String string = parser.getText().trim();
56 | if(string.length() == 0) {
57 | return null;
58 | }
59 | return LocalDate.parse(string, ISO_DATE_OPTIONAL_TIME);
60 | }
61 | throw context.wrongTokenException(parser, JsonToken.START_ARRAY, "Expected array or string.");
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/utils/JSR310PersistenceConverters.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.utils;
2 |
3 |
4 | import javax.persistence.AttributeConverter;
5 | import javax.persistence.Converter;
6 | import java.time.LocalDate;
7 | import java.time.LocalDateTime;
8 | import java.time.ZonedDateTime;
9 | import java.util.Date;
10 |
11 | public final class JSR310PersistenceConverters {
12 |
13 | private JSR310PersistenceConverters() {}
14 |
15 | @Converter(autoApply = true)
16 | public static class LocalDateConverter implements AttributeConverter {
17 |
18 | @Override
19 | public java.sql.Date convertToDatabaseColumn(LocalDate date) {
20 | return date == null ? null : java.sql.Date.valueOf(date);
21 | }
22 |
23 | @Override
24 | public LocalDate convertToEntityAttribute(java.sql.Date date) {
25 | return date == null ? null : date.toLocalDate();
26 | }
27 | }
28 |
29 | @Converter(autoApply = true)
30 | public static class ZonedDateTimeConverter implements AttributeConverter {
31 |
32 | @Override
33 | public Date convertToDatabaseColumn(ZonedDateTime zonedDateTime) {
34 | return JSR310DateConverters.ZonedDateTimeToDateConverter.INSTANCE.convert(zonedDateTime);
35 | }
36 |
37 | @Override
38 | public ZonedDateTime convertToEntityAttribute(Date date) {
39 | return JSR310DateConverters.DateToZonedDateTimeConverter.INSTANCE.convert(date);
40 | }
41 | }
42 |
43 | @Converter(autoApply = true)
44 | public static class LocalDateTimeConverter implements AttributeConverter {
45 |
46 | @Override
47 | public Date convertToDatabaseColumn(LocalDateTime localDateTime) {
48 | return JSR310DateConverters.LocalDateTimeToDateConverter.INSTANCE.convert(localDateTime);
49 | }
50 |
51 | @Override
52 | public LocalDateTime convertToEntityAttribute(Date date) {
53 | return JSR310DateConverters.DateToLocalDateTimeConverter.INSTANCE.convert(date);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/starter/springboot/utils/RunningState.java:
--------------------------------------------------------------------------------
1 | package com.starter.springboot.utils;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.http.ResponseEntity;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RequestMethod;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | @RestController
10 | public class RunningState {
11 |
12 | @RequestMapping(value = "/", method = RequestMethod.GET)
13 | public ResponseEntity rootPageCheck()
14 | {
15 | return new ResponseEntity<>("Application is running!", HttpStatus.OK);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | devtools:
3 | restart:
4 | enabled: true
5 | datasource:
6 | url: jdbc:mysql://localhost/otp?useUnicode=true&characterEncoding=utf8&useSSL=false # URL for MySQL 5.7
7 | # url: jdbc:mysql://localhost/otp9?useSSL=false&serverTimezone=CET&allowPublicKeyRetrieval=true&useUnicode=true # URL for MySQL 8.X
8 | name: MySQL Local Connection
9 | username: root
10 | password: root
11 | driver-class-name: com.mysql.jdbc.Driver # MySQL 5.7.X / 6.X.X
12 | # driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8
13 | hikari:
14 | data-source-properties:
15 | cachePrepStmts: true
16 | prepStmtCacheSize: 250
17 | prepStmtCacheSqlLimit: 2048
18 | useServerPrepStmts: true
19 | jpa:
20 | database-platform: org.hibernate.dialect.MySQLInnoDBDialect
21 | database: MYSQL
22 | show_sql: false
23 | open-in-view: false
24 | factory-class: org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean
25 | properties:
26 | hibernate.cache.use_second_level_cache: false
27 | hibernate.cache.use_query_cache: false
28 | hibernate.generate_statistics: true
29 |
30 | liquibase:
31 | contexts: dev
32 |
33 | jwt:
34 | header: Authorization
35 | secret: SpringBootSecretKey
36 | expiration: 300
37 |
38 | server:
39 | port: 8080
40 |
41 | debug: true
42 |
43 | email:
44 | host: smtp.gmail.com
45 | port: 587
46 | username: your_username
47 | password: your_password
48 | debug: true
49 |
--------------------------------------------------------------------------------
/src/main/resources/application-prod.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | devtools:
3 | restart:
4 | enabled: false
5 | datasource:
6 | url: jdbc:mysql://localhost/production?useUnicode=true&characterEncoding=utf8&useSSL=false
7 | name:
8 | username: root
9 | password: prod
10 | hikari:
11 | data-source-properties:
12 | cachePrepStmts: true
13 | prepStmtCacheSize: 250
14 | prepStmtCacheSqlLimit: 2048
15 | useServerPrepStmts: true
16 | jpa:
17 | database-platform: org.hibernate.dialect.MySQLInnoDBDialect
18 | database: MYSQL
19 | show_sql: false
20 | open-in-view: false
21 | factory-class: org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean
22 | properties:
23 | hibernate.cache.use_second_level_cache: false
24 | hibernate.cache.use_query_cache: false
25 | hibernate.generate_statistics: false
26 |
27 | liquibase:
28 | contexts: prod
29 |
30 | jwt:
31 | header: Authorization
32 | secret: SpringBootSecretKey
33 | expiration: 300
34 |
35 | server:
36 | port: 8080
37 | compression:
38 | enabled: true
39 | mime-types: text/html, text/xml, text/plain, text/css, application/javascript, application/json
40 |
41 | debug: false
42 |
43 | email:
44 | host: smtp.gmail.com
45 | port: 587
46 | username: your_username
47 | password: your_password
48 | debug: false
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: Starter Project
4 | profiles:
5 | active: dev
6 |
7 | liquibase:
8 | change-log: classpath:liquibase/db.changelog-master.xml
--------------------------------------------------------------------------------
/src/main/resources/liquibase.properties:
--------------------------------------------------------------------------------
1 | changeLogFile=/src/main/resources/changelog/db.changelog-master.xml
2 | url=${spring.datasource.url}
3 | username=${spring.datasource.username}
4 | password=${spring.datasource.password}
5 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/changelog/added_entity_Authority.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/changelog/added_entity_Role.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/changelog/added_entity_User.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/changelog/added_entity_UserAuthority.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/changelog/added_entity_UserRole.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/db.changelog-master.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/seeds/authority.csv:
--------------------------------------------------------------------------------
1 | name
2 | ROLE_ADMIN
3 | ROLE_USER
4 |
--------------------------------------------------------------------------------
/src/main/resources/liquibase/seeds/role.csv:
--------------------------------------------------------------------------------
1 | "id";"name";"description"
2 | "1";"ROLE_ADMIN";"Rola administrator"
3 | "2";"ROLE_USER";"Rola korisnik"
--------------------------------------------------------------------------------
/src/main/resources/liquibase/seeds/user.csv:
--------------------------------------------------------------------------------
1 | "id";"first_name";"last_name";"username";"email";"password";"enabled";"last_password_reset_date"
2 | "1";"Administrator";"";"admin";"heril.muratovic@logate.com";"$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC";true;NULL
--------------------------------------------------------------------------------
/src/main/resources/liquibase/seeds/user_authority.csv:
--------------------------------------------------------------------------------
1 | "user_id";"authority_name"
2 | "1";"ROLE_ADMIN"
--------------------------------------------------------------------------------
/src/main/resources/liquibase/seeds/user_role.csv:
--------------------------------------------------------------------------------
1 | "role_id";"user_id"
2 | "1";"1"
--------------------------------------------------------------------------------
/src/test/java/config/TestUtil.java:
--------------------------------------------------------------------------------
1 | package config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6 | import com.starter.springboot.utils.JSR310DateTimeSerializer;
7 | import com.starter.springboot.utils.JSR310LocalDateDeserializer;
8 | import org.springframework.http.MediaType;
9 |
10 | import java.io.IOException;
11 | import java.nio.charset.Charset;
12 | import java.time.*;
13 |
14 | /**
15 | * Utility class for testing REST controllers.
16 | */
17 | public class TestUtil {
18 |
19 | /** MediaType for JSON UTF8 */
20 | public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(
21 | MediaType.APPLICATION_JSON.getType(),
22 | MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
23 |
24 | /**
25 | * Convert an object to JSON byte array.
26 | *
27 | * @param object
28 | * the object to convert
29 | * @return the JSON byte array
30 | * @throws IOException
31 | */
32 | public static byte[] convertObjectToJsonBytes(Object object)
33 | throws IOException
34 | {
35 | ObjectMapper mapper = new ObjectMapper();
36 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
37 |
38 | JavaTimeModule module = new JavaTimeModule();
39 | module.addSerializer(OffsetDateTime.class, JSR310DateTimeSerializer.INSTANCE);
40 | module.addSerializer(ZonedDateTime.class, JSR310DateTimeSerializer.INSTANCE);
41 | module.addSerializer(LocalDateTime.class, JSR310DateTimeSerializer.INSTANCE);
42 | module.addSerializer(Instant.class, JSR310DateTimeSerializer.INSTANCE);
43 | module.addDeserializer(LocalDate.class, JSR310LocalDateDeserializer.INSTANCE);
44 | mapper.registerModule(module);
45 |
46 | return mapper.writeValueAsBytes(object);
47 | }
48 |
49 | /**
50 | * Create a byte array with a specific size filled with specified data.
51 | *
52 | * @param size the size of the byte array
53 | * @param data the data to put in the byte array
54 | */
55 | public static byte[] createByteArray(int size, String data)
56 | {
57 | byte[] byteArray = new byte[size];
58 | for (int i = 0; i < size; i++) {
59 | byteArray[i] = Byte.parseByte(data, 2);
60 | }
61 | return byteArray;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/security/SecurityUtilsUnitTest.java:
--------------------------------------------------------------------------------
1 | package security;
2 |
3 | import com.starter.springboot.security.AuthoritiesConstants;
4 | import com.starter.springboot.security.SecurityUtils;
5 | import org.junit.Test;
6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7 | import org.springframework.security.core.GrantedAuthority;
8 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
9 | import org.springframework.security.core.context.SecurityContext;
10 | import org.springframework.security.core.context.SecurityContextHolder;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Collection;
14 |
15 | import static org.assertj.core.api.Assertions.assertThat;
16 |
17 | /**
18 | * Test class for the SecurityUtils utility class.
19 | */
20 | public class SecurityUtilsUnitTest {
21 |
22 | @Test
23 | public void getCurrentUserLogin()
24 | {
25 | SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
26 | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"));
27 | SecurityContextHolder.setContext(securityContext);
28 | String login = SecurityUtils.getCurrentUserLogin();
29 | assertThat(login).isEqualTo("admin");
30 | }
31 |
32 | @Test
33 | public void isAuthenticated()
34 | {
35 | SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
36 | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"));
37 | SecurityContextHolder.setContext(securityContext);
38 | boolean isAuthenticated = SecurityUtils.isAuthenticated();
39 | assertThat(isAuthenticated).isTrue();
40 | }
41 |
42 | @Test
43 | public void anonymousIsNotAuthenticated()
44 | {
45 | SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
46 | Collection authorities = new ArrayList<>();
47 | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
48 | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities));
49 | SecurityContextHolder.setContext(securityContext);
50 | boolean isAuthenticated = SecurityUtils.isAuthenticated();
51 | assertThat(isAuthenticated).isFalse();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------