Refactor and restructure - No API Breakage (#49)

* Renames Project GroupId

* Correcting Naming Conventions

* Initial Restructuring

* Altera Formato Application Config

* Removes Auth for ReImplementation

* Changes Project Structure

* Restructure Microservice

* Fixes Tests

* Initial Authentication and Authorization ReImplementation

* Optimize Imports and Reformats Code

* Implements ResourceGuard Mapping and Automatic Security Configuration

* First Refactored Feature Complete Version - OAuth2 Implementation

* Moves All Enums to the Correct Dir

* Reimplements Authentication with Providers and JWTFilters
This commit is contained in:
2024-05-25 21:48:21 -03:00
committed by GitHub
parent 0ecc1f3127
commit ffc35c2f5e
68 changed files with 713 additions and 753 deletions

View File

@@ -8,7 +8,7 @@
<version>2.7.17</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hideyoshi</groupId>
<groupId>br.com.hideyoshi</groupId>
<artifactId>auth-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>auth-api</name>
@@ -76,6 +76,13 @@
<optional>true</optional>
</dependency>
<!-- support for "Java 8 date time api" -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -0,0 +1,13 @@
package br.com.hideyoshi.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AuthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
}

View File

@@ -1,10 +1,10 @@
package com.hideyoshi.auth.base.config;
package br.com.hideyoshi.auth.config;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.base.auth.repo.UserRepository;
import com.hideyoshi.auth.base.auth.service.UserService;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.repository.UserRepository;
import br.com.hideyoshi.auth.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
@@ -15,16 +15,16 @@ import java.util.ArrayList;
@Configuration
public class DefaultUserConfig {
@Value("${com.hideyoshi.defaultUser.fullName}")
@Value("${br.com.hideyoshi.defaultUser.fullName}")
private String ADMIN_NAME;
@Value("${com.hideyoshi.defaultUser.email}")
@Value("${br.com.hideyoshi.defaultUser.email}")
private String ADMIN_EMAIL;
@Value("${com.hideyoshi.defaultUser.username}")
@Value("${br.com.hideyoshi.defaultUser.username}")
private String ADMIN_USERNAME;
@Value("${com.hideyoshi.defaultUser.password}")
@Value("${br.com.hideyoshi.defaultUser.password}")
private String ADMIN_PASSWORD;
@Bean
@@ -53,4 +53,4 @@ public class DefaultUserConfig {
};
}
}
}

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.microservice.storageService.config;
package br.com.hideyoshi.auth.config;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
@@ -8,6 +8,6 @@ import org.springframework.context.annotation.Configuration;
@Getter
@Configuration
public class StorageServiceConfig {
@Value("${com.hideyoshi.microservice.storageServicePath}")
@Value("${br.com.hideyoshi.microservice.storageServicePath}")
private String fileServicePath;
}

View File

@@ -1,23 +1,18 @@
package com.hideyoshi.auth.healthChecker.api;
package br.com.hideyoshi.auth.controller;
import com.hideyoshi.auth.util.guard.UserResourceGuard;
import com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
import lombok.RequiredArgsConstructor;
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
import br.com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Log4j2
@Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/health")
public class HealthCheckerController {
@RequestMapping
@RequestMapping("/health")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<String> healthCheck() {
log.info("Health check requested");

View File

@@ -1,7 +1,9 @@
package com.hideyoshi.auth.base.session.api;
package br.com.hideyoshi.auth.controller;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import com.hideyoshi.auth.base.session.service.SessionManagerService;
import br.com.hideyoshi.auth.model.UserAuthDTO;
import br.com.hideyoshi.auth.service.SessionManagerService;
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
import br.com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -16,17 +18,19 @@ import javax.servlet.http.HttpSession;
@Controller
@RestController
@RequiredArgsConstructor
@RequestMapping(path = "/session")
@RequestMapping("/session")
public class SessionController {
private final SessionManagerService sessionManagerService;
@GetMapping(path = "/validate")
public ResponseEntity<AuthDTO> validateCurrentSession(HttpSession session) {
@GetMapping("/validate")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<UserAuthDTO> validateCurrentSession(HttpSession session) {
return ResponseEntity.ok(this.sessionManagerService.validateSession(session));
}
@DeleteMapping(path = "/destroy")
@DeleteMapping("/destroy")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<Void> destroyCurrentSession(HttpSession session) {
this.sessionManagerService.destroySession(session);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);

View File

@@ -1,16 +1,17 @@
package com.hideyoshi.auth.base.auth.api;
package br.com.hideyoshi.auth.controller;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import com.hideyoshi.auth.base.auth.service.AuthService;
import com.hideyoshi.auth.base.auth.model.TokenDTO;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.base.auth.service.UserService;
import com.hideyoshi.auth.microservice.storageService.enums.FileTypeEnum;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceUploadResponse;
import com.hideyoshi.auth.microservice.storageService.service.StorageService;
import com.hideyoshi.auth.util.exception.BadRequestException;
import com.hideyoshi.auth.util.guard.UserResourceGuard;
import com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
import br.com.hideyoshi.auth.enums.FileTypeEnum;
import br.com.hideyoshi.auth.model.UserAuthDTO;
import br.com.hideyoshi.auth.model.TokenDTO;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.model.microservice.StorageServiceUploadResponse;
import br.com.hideyoshi.auth.security.service.AuthService;
import br.com.hideyoshi.auth.service.UserService;
import br.com.hideyoshi.auth.service.microservice.StorageService;
import br.com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
import br.com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
@@ -20,13 +21,14 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.URI;
import java.util.List;
@Log4j2
@Controller
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
@@ -45,7 +47,7 @@ public class UserController {
@PostMapping("/signup")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<AuthDTO> signupUser(@RequestBody @Valid UserDTO user, HttpServletRequest request) {
public ResponseEntity<UserAuthDTO> signupUser(@RequestBody @Valid UserDTO user, HttpServletRequest request) {
URI uri = URI.create(
ServletUriComponentsBuilder
.fromCurrentContextPath()
@@ -56,7 +58,7 @@ public class UserController {
@PostMapping("/login/refresh")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<AuthDTO> refreshAccessToken(
public ResponseEntity<UserAuthDTO> refreshAccessToken(
@RequestBody @Valid TokenDTO refreshToken,
HttpServletRequest request) {
return ResponseEntity.ok(this.authService.refreshAccessToken(refreshToken.getToken(), request));
@@ -64,7 +66,7 @@ public class UserController {
@PostMapping("/login/validate")
@UserResourceGuard(accessType = UserResourceGuardEnum.USER)
public ResponseEntity<AuthDTO> validateAccessToken(HttpServletRequest request) {
public ResponseEntity<UserAuthDTO> validateAccessToken(HttpServletRequest request) {
return ResponseEntity.ok(this.authService.validateAccessToken(request));
}

View File

@@ -1,5 +1,6 @@
package com.hideyoshi.auth.base.auth.entity;
package br.com.hideyoshi.auth.entity;
import br.com.hideyoshi.auth.enums.Role;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

View File

@@ -1,7 +1,7 @@
package com.hideyoshi.auth.microservice.storageService.enums;
package br.com.hideyoshi.auth.enums;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.hideyoshi.auth.util.exception.BadRequestException;
import lombok.Getter;
@Getter

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.microservice.storageService.enums;
package br.com.hideyoshi.auth.enums;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.entity;
package br.com.hideyoshi.auth.enums;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.entity;
package br.com.hideyoshi.auth.enums;
import com.fasterxml.jackson.annotation.JsonValue;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.model;
package br.com.hideyoshi.auth.model;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.model;
package br.com.hideyoshi.auth.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View File

@@ -1,9 +1,9 @@
package com.hideyoshi.auth.base.auth.model;
package br.com.hideyoshi.auth.model;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -16,7 +16,7 @@ import java.util.List;
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthDTO implements Serializable {
public class UserAuthDTO implements Serializable {
private Long id;
@@ -36,7 +36,7 @@ public class AuthDTO implements Serializable {
private TokenDTO refreshToken;
public AuthDTO(UserDTO user, TokenDTO accessToken, TokenDTO refreshToken) {
public UserAuthDTO(UserDTO user, TokenDTO accessToken, TokenDTO refreshToken) {
this.id = user.getId();
this.name = user.getName();
this.email = user.getEmail();

View File

@@ -1,14 +1,14 @@
package com.hideyoshi.auth.base.auth.model;
package br.com.hideyoshi.auth.model;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.entity.User;
import br.com.hideyoshi.auth.util.validator.email.unique.UniqueEmail;
import br.com.hideyoshi.auth.util.validator.email.valid.ValidEmail;
import br.com.hideyoshi.auth.util.validator.password.ValidPassword;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.entity.User;
import com.hideyoshi.auth.util.validator.email.unique.UniqueEmail;
import com.hideyoshi.auth.util.validator.email.valid.ValidEmail;
import com.hideyoshi.auth.util.validator.password.ValidPassword;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.microservice.storageService.model;
package br.com.hideyoshi.auth.model.microservice;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.microservice.storageService.model;
package br.com.hideyoshi.auth.model.microservice;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.base.auth.repo;
package br.com.hideyoshi.auth.repository;
import com.hideyoshi.auth.base.auth.entity.User;
import br.com.hideyoshi.auth.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.config;
package br.com.hideyoshi.auth.security.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -14,7 +14,7 @@ import java.util.List;
@Configuration
public class CorsConfig {
@Value("${com.hideyoshi.frontendPath}")
@Value("${br.com.hideyoshi.frontendPath}")
private String FRONTEND_PATH;
@Bean
@@ -35,4 +35,4 @@ public class CorsConfig {
return source;
}
}
}

View File

@@ -0,0 +1,16 @@
package br.com.hideyoshi.auth.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordEncoderConfig {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@@ -0,0 +1,153 @@
package br.com.hideyoshi.auth.security.config;
import br.com.hideyoshi.auth.model.UserAuthDTO;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.security.filter.JWTAuthenticationFilter;
import br.com.hideyoshi.auth.security.oauth2.repository.OAuthRequestRepository;
import br.com.hideyoshi.auth.security.service.AuthService;
import br.com.hideyoshi.auth.service.UserService;
import br.com.hideyoshi.auth.util.exception.AuthenticationInvalidExceptionDetails;
import br.com.hideyoshi.auth.util.guard.UserResourceHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final PasswordEncoder passwordEncoder;
private final AuthService authService;
private final UserService userService;
private final OAuthRequestRepository oAuthRequestRepository;
private final UserResourceHandler userResourceHandler;
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(this.userService);
provider.setPasswordEncoder(this.passwordEncoder);
return provider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.httpBasic().disable()
.cors().and().csrf().disable();
this.addEndpointSecurityToHttp(http);
this.addOAuthSecurityToHttp(http);
this.configureEndpoints(http);
return http.build();
}
private void configureEndpoints(HttpSecurity http) throws Exception {
for (String endpoint : this.userResourceHandler.getOpenPaths()) {
http.authorizeRequests().antMatchers(endpoint).permitAll();
}
for (String endpoint : this.userResourceHandler.getGuardedPaths()) {
http.authorizeRequests().antMatchers(endpoint).hasAnyAuthority("ROLE_USER", "ROLE_ADMIN");
}
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
http.addFilterBefore(
new JWTAuthenticationFilter(this.authService),
UsernamePasswordAuthenticationFilter.class
);
}
private void addEndpointSecurityToHttp(HttpSecurity http) throws Exception {
http.formLogin(form -> form
.loginProcessingUrl("/user/login")
.successHandler(this::successFormHandler)
.failureHandler(this::failureHandler)
);
http.authorizeRequests().antMatchers("/login").denyAll();
}
private void addOAuthSecurityToHttp(HttpSecurity http) throws Exception {
http.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(this.oAuthRequestRepository)
.and().successHandler(this::successOAuth2Handler)
.failureHandler(this::failureHandler);
}
private void successFormHandler(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
UserAuthDTO authUser = this.authService.loginUser(
request,
(UserDTO) authentication.getPrincipal()
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authUser);
}
private void successOAuth2Handler(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
UserAuthDTO authUser = this.authService.loginOAuthUser(
request,
(OAuth2User) authentication.getPrincipal()
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authUser);
}
private void failureHandler(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e) throws IOException {
response.setHeader("error", e.getMessage());
response.setStatus(FORBIDDEN.value());
AuthenticationInvalidExceptionDetails error = new AuthenticationInvalidExceptionDetails("Authentication Failed. Check your credentials.",
HttpStatus.FORBIDDEN.value(), e.getMessage(),
e.getClass().getName(), LocalDateTime.now());
response.setContentType(APPLICATION_JSON_VALUE);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.writeValue(response.getOutputStream(), error);
}
}

View File

@@ -0,0 +1,58 @@
package br.com.hideyoshi.auth.security.filter;
import br.com.hideyoshi.auth.security.service.AuthService;
import br.com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
public class JWTAuthenticationFilter extends OncePerRequestFilter {
private static final String AUTHORIZATION_TYPE_STRING = "Bearer ";
private final AuthService authService;
public JWTAuthenticationFilter(AuthService authService) {
this.authService = authService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
try {
this.setUserContext(request);
} catch (Exception ignored) {
// ignored
}
filterChain.doFilter(request, response);
}
private void setUserContext(HttpServletRequest request) {
if (SecurityContextHolder.getContext().getAuthentication() != null) {
return;
}
String authorizationHeader = request.getHeader(AUTHORIZATION);
Authentication loggedUserInfo = this.validateUserAccess(authorizationHeader);
SecurityContextHolder.getContext().setAuthentication(loggedUserInfo);
}
private Authentication validateUserAccess(String authorizationHeader) {
if (Objects.nonNull(authorizationHeader) && authorizationHeader.startsWith(AUTHORIZATION_TYPE_STRING)) {
String accessToken = authorizationHeader.substring(AUTHORIZATION_TYPE_STRING.length());
return this.authService.extractAccessTokenInfo(accessToken);
} else {
throw new AuthenticationInvalidException("Access denied");
}
}
}

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.interceptor;
package br.com.hideyoshi.auth.security.interceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@@ -7,12 +7,12 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
@RequiredArgsConstructor
public class ConfigInterceptor implements WebMvcConfigurer {
public class InterceptorConfigurer implements WebMvcConfigurer {
private final UserResourceAccessInterceptor userResourceAccessInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userResourceAccessInterceptor);
registry.addInterceptor(this.userResourceAccessInterceptor);
}
}
}

View File

@@ -1,9 +1,10 @@
package com.hideyoshi.auth.base.auth.interceptor;
package br.com.hideyoshi.auth.security.interceptor;
import br.com.hideyoshi.auth.service.UserService;
import br.com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import br.com.hideyoshi.auth.util.exception.AuthorizationException;
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.base.auth.service.UserService;
import com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import com.hideyoshi.auth.util.guard.UserResourceGuard;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
@@ -21,8 +22,6 @@ public class UserResourceAccessInterceptor implements HandlerInterceptor {
private final UserService userService;
private final ObjectMapper objectMapper;
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
if (!(handler instanceof HandlerMethod)) {
@@ -34,12 +33,12 @@ public class UserResourceAccessInterceptor implements HandlerInterceptor {
if (Objects.nonNull(annotation)) {
Boolean accessPermission =
annotation.accessType().hasAccess(this.userService, this.objectMapper, request);
annotation.accessType().hasAccess(this.userService, request);
if (!accessPermission) {
throw new AuthenticationInvalidException(annotation.denialMessage());
throw new AuthorizationException(annotation.denialMessage());
}
}
return true;
}
}
}

View File

@@ -0,0 +1,43 @@
package br.com.hideyoshi.auth.security.oauth2.handler;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.security.oauth2.model.OAuthDTO;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
@Component
public class OAuthHandler {
public Provider getProviderFromURL(String url) {
String[] urlPartition = url.split("/");
return Provider.byValue(urlPartition[urlPartition.length - 1]);
}
public OAuthDTO parseOAuth2User(OAuth2User user, Provider provider) {
return switch (provider) {
case GITHUB -> parseFromGithub(user);
case GOOGLE -> parseFromGoogle(user);
default -> throw new BadRequestException("Provider not supported.");
};
}
private OAuthDTO parseFromGithub(OAuth2User user) {
return new OAuthDTO(
user.getAttribute("name"),
user.getAttribute("login"),
user.getAttribute("email"),
user.getAttribute("avatar_url"),
Provider.GITHUB
);
}
private OAuthDTO parseFromGoogle(OAuth2User user) {
return new OAuthDTO(
user.getAttribute("name"),
user.getAttribute("given_name"),
user.getAttribute("email"),
user.getAttribute("picture"),
Provider.GOOGLE
);
}
}

View File

@@ -0,0 +1,19 @@
package br.com.hideyoshi.auth.security.oauth2.model;
import br.com.hideyoshi.auth.enums.Provider;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class OAuthDTO {
private String name;
private String username;
private String email;
private String profilePictureUrl;
private Provider provider;
}

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.base.auth.oauth.repo;
package br.com.hideyoshi.auth.security.oauth2.repository;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
@@ -64,4 +64,4 @@ public class OAuthRequestRepository implements AuthorizationRequestRepository<OA
);
}
}
}

View File

@@ -1,23 +1,25 @@
package com.hideyoshi.auth.base.auth.service;
package br.com.hideyoshi.auth.security.service;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.model.UserAuthDTO;
import br.com.hideyoshi.auth.model.TokenDTO;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.model.microservice.StorageServiceDownloadResponse;
import br.com.hideyoshi.auth.security.oauth2.handler.OAuthHandler;
import br.com.hideyoshi.auth.security.oauth2.model.OAuthDTO;
import br.com.hideyoshi.auth.service.UserService;
import br.com.hideyoshi.auth.service.microservice.StorageService;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import com.hideyoshi.auth.base.auth.oauth.mapper.OAuthMap;
import com.hideyoshi.auth.base.auth.oauth.mapper.OAuthMapper;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.model.TokenDTO;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceDownloadResponse;
import com.hideyoshi.auth.microservice.storageService.service.StorageService;
import com.hideyoshi.auth.util.exception.BadRequestException;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -44,16 +46,18 @@ public class AuthService {
private final StorageService storageService;
@Value("${com.hideyoshi.tokenSecret}")
private final OAuthHandler oAuthHandler;
@Value("${br.com.hideyoshi.tokenSecret}")
private String TOKEN_SECRET;
@Value("${com.hideyoshi.accessTokenDuration}")
@Value("${br.com.hideyoshi.accessTokenDuration}")
private Integer ACCESS_TOKEN_DURATION;
@Value("${com.hideyoshi.refreshTokenDuration}")
@Value("${br.com.hideyoshi.refreshTokenDuration}")
private Integer REFRESH_TOKEN_DURATION;
public AuthDTO signupUser(@Valid UserDTO user, HttpServletRequest request) {
public UserAuthDTO signupUser(@Valid UserDTO user, HttpServletRequest request) {
user.setProvider(Provider.LOCAL);
UserDTO authenticatedUser = this.userService.saveUser(user);
@@ -66,7 +70,7 @@ public class AuthService {
}
public AuthDTO loginUser(HttpServletRequest request, HttpServletResponse response, @Valid UserDTO user) throws IOException {
public UserAuthDTO loginUser(HttpServletRequest request, @Valid UserDTO user) throws IOException {
user.setProfilePictureUrl(this.extractProfilePictureUrl(user));
return this.generateNewAuthenticatedUser(
@@ -75,20 +79,16 @@ public class AuthService {
);
}
public AuthDTO loginOAuthUser(OAuth2User oauthUser, HttpServletRequest request) {
Provider clientProvider = Provider.byValue(
this.getClientFromUrl(request.getRequestURL().toString())
);
public UserAuthDTO loginOAuthUser(HttpServletRequest request, OAuth2User oAuth2User) {
Provider provider = this.oAuthHandler.getProviderFromURL(request.getRequestURL().toString());
OAuthDTO oAuthDTO = this.oAuthHandler.parseOAuth2User(oAuth2User, provider);
OAuthMap oauthMap = this.generateOAuthMap(clientProvider, oauthUser);
UserDTO user = this.getUserFromOAuth2User(oAuthDTO);
return this.processOAuthPostLogin(
this.generateAuthenticatedUserFromOAuth(oauthMap, oauthUser),
request
);
return this.processOAuthPostLogin(user, request);
}
public AuthDTO refreshAccessToken(String requestToken, HttpServletRequest request) {
public UserAuthDTO refreshAccessToken(String requestToken, HttpServletRequest request) {
DecodedJWT decodedJWT = this.decodeToken(requestToken)
.orElseThrow(() -> new BadRequestException("Invalid Token"));
@@ -100,7 +100,7 @@ public class AuthService {
return this.refreshAuthenticatedUser(user, request, new TokenDTO(requestToken, decodedJWT.getExpiresAt()));
}
public AuthDTO validateAccessToken(HttpServletRequest request) {
public UserAuthDTO validateAccessToken(HttpServletRequest request) {
UserDTO user = this.getLoggedUser();
user.setProfilePictureUrl(this.extractProfilePictureUrl(user));
@@ -109,23 +109,20 @@ public class AuthService {
}
public UserDTO getLoggedUser() {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userService.getUser(username);
return (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public UsernamePasswordAuthenticationToken extractAccessTokenInfo(String accessToken) {
public Authentication extractAccessTokenInfo(String accessToken) {
DecodedJWT decodedJWT = this.decodeToken(accessToken)
.orElseThrow(() -> new BadRequestException("Invalid Token"));
String username = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role));
});
return new UsernamePasswordAuthenticationToken(username, null, authorities);
return new UsernamePasswordAuthenticationToken(
this.userService.getUser(decodedJWT.getSubject()),
null,
stream(decodedJWT.getClaim("roles").asArray(String.class))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList())
);
}
private Optional<DecodedJWT> decodeToken(String token) {
@@ -139,7 +136,26 @@ public class AuthService {
return Optional.empty();
}
private AuthDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request) {
private UserDTO getUserFromOAuth2User(OAuthDTO oAuth2User) {
UserDTO user;
try {
user = this.userService.getUser(oAuth2User.getUsername());
} catch (BadRequestException e) {
user = UserDTO.builder()
.name(oAuth2User.getName())
.username(oAuth2User.getUsername())
.email(oAuth2User.getEmail())
.roles(List.of(Role.USER))
.provider(oAuth2User.getProvider())
.profilePictureUrl(oAuth2User.getProfilePictureUrl())
.build();
}
return user;
}
private UserAuthDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request) {
if (Objects.nonNull(user.getId())) {
this.userService.alterUser(user.getId(), user);
@@ -150,47 +166,15 @@ public class AuthService {
return this.generateNewAuthenticatedUser(user, request);
}
private String getClientFromUrl(String url) {
String[] urlPartition = url.split("/");
return urlPartition[urlPartition.length - 1];
}
private OAuthMap generateOAuthMap(Provider clientProvider, OAuth2User oauthUser) {
try {
return OAuthMapper.byValue(clientProvider).getMap()
.getDeclaredConstructor(OAuth2User.class).newInstance(oauthUser);
} catch (Exception e) {
throw new BadRequestException("Unsupported OAuth Client.");
}
}
private String extractProfilePictureUrl(UserDTO user) {
return this.storageService.getFileUrl(user.getUsername(), "profile")
.map(StorageServiceDownloadResponse::getPresignedUrl)
.orElse(null);
}
private UserDTO generateAuthenticatedUserFromOAuth(OAuthMap oauthMap, OAuth2User oauthUser) {
UserDTO user;
try {
user = this.userService.getUser(oauthMap.getPrincipal());
} catch (BadRequestException e) {
user = UserDTO.builder()
.name(oauthUser.getAttribute("name"))
.username(oauthMap.getPrincipal())
.email(oauthUser.getAttribute("email"))
.roles(List.of(Role.USER))
.provider(oauthMap.getProvider())
.build();
}
user.setProfilePictureUrl(oauthMap.getProfilePicture());
return user;
}
private AuthDTO generateNewAuthenticatedUser(UserDTO user, HttpServletRequest request) {
private UserAuthDTO generateNewAuthenticatedUser(UserDTO user, HttpServletRequest request) {
HttpSession httpSession = request.getSession();
AuthDTO authObject = new AuthDTO(
UserAuthDTO authObject = new UserAuthDTO(
user,
this.generateToken(user, request, ACCESS_TOKEN_DURATION),
this.generateToken(user, request, REFRESH_TOKEN_DURATION)
@@ -201,9 +185,9 @@ public class AuthService {
return authObject;
}
private AuthDTO refreshAuthenticatedUser(UserDTO user, HttpServletRequest request, TokenDTO refreshToken) {
private UserAuthDTO refreshAuthenticatedUser(UserDTO user, HttpServletRequest request, TokenDTO refreshToken) {
HttpSession httpSession = request.getSession();
AuthDTO authObject = new AuthDTO(
UserAuthDTO authObject = new UserAuthDTO(
user,
this.generateToken(user, request, ACCESS_TOKEN_DURATION),
refreshToken

View File

@@ -0,0 +1,21 @@
package br.com.hideyoshi.auth.service;
import br.com.hideyoshi.auth.model.UserAuthDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
@Service
@RequiredArgsConstructor
public class SessionManagerService {
public UserAuthDTO validateSession(HttpSession session) {
return (UserAuthDTO) session.getAttribute("user");
}
public void destroySession(HttpSession session) {
session.invalidate();
}
}

View File

@@ -1,15 +1,16 @@
package com.hideyoshi.auth.base.auth.service;
package br.com.hideyoshi.auth.service;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.entity.User;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.base.auth.repo.UserRepository;
import com.hideyoshi.auth.util.exception.BadRequestException;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.entity.User;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.repository.UserRepository;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@@ -132,7 +133,11 @@ public class UserService implements UserDetailsService {
}
public UserDetails loadUserByUsername(String username) {
return this.getUser(username);
try {
return this.getUser(username);
} catch (BadRequestException e) {
throw new UsernameNotFoundException("User not found.");
}
}
private String validatePassword(UserDTO user) {

View File

@@ -1,11 +1,11 @@
package com.hideyoshi.auth.microservice.storageService.service;
package br.com.hideyoshi.auth.service.microservice;
import br.com.hideyoshi.auth.config.StorageServiceConfig;
import br.com.hideyoshi.auth.enums.FileTypeEnum;
import br.com.hideyoshi.auth.model.microservice.StorageServiceDownloadResponse;
import br.com.hideyoshi.auth.model.microservice.StorageServiceUploadResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.microservice.storageService.config.StorageServiceConfig;
import com.hideyoshi.auth.microservice.storageService.enums.FileTypeEnum;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceDownloadResponse;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceUploadResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.methods.HttpDelete;
@@ -20,9 +20,9 @@ import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Optional;
@@ -137,11 +137,7 @@ public class StorageService {
HttpPost request = new HttpPost(requestURI);
request.setHeader("Content-Type", "application/json");
try {
request.setEntity(new ByteArrayEntity(requestBody.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
request.setEntity(new ByteArrayEntity(requestBody.getBytes(StandardCharsets.UTF_8)));
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setRedirectStrategy(new LaxRedirectStrategy()).build();

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import java.time.LocalDateTime;

View File

@@ -0,0 +1,12 @@
package br.com.hideyoshi.auth.util.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.FORBIDDEN)
public class AuthorizationException extends RuntimeException {
public AuthorizationException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,9 @@
package br.com.hideyoshi.auth.util.exception;
import java.time.LocalDateTime;
public class AuthorizationExceptionDetails extends ExceptionDetails {
public AuthorizationExceptionDetails(String title, Integer status, String details, String developerMessage, LocalDateTime timestamp) {
super(title, status, details, developerMessage, timestamp);
}
}

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import java.time.LocalDateTime;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import lombok.Getter;
import lombok.Setter;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.exception;
package br.com.hideyoshi.auth.util.exception;
import lombok.Getter;
import lombok.Setter;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.guard;
package br.com.hideyoshi.auth.util.guard;
import java.lang.annotation.*;

View File

@@ -1,9 +1,9 @@
package com.hideyoshi.auth.util.guard;
package br.com.hideyoshi.auth.util.guard;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.base.auth.service.UserService;
import lombok.Getter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -19,9 +19,8 @@ public enum UserResourceGuardEnum {
@Override
public Boolean hasAccess(
UserService userService,
ObjectMapper objectMapper,
HttpServletRequest request) {
return justUser(userService, objectMapper, request);
return UserResourceGuardEnum.justUser(userService, request);
}
},
@@ -29,9 +28,8 @@ public enum UserResourceGuardEnum {
@Override
public Boolean hasAccess(
UserService userService,
ObjectMapper objectMapper,
HttpServletRequest request) {
return sameUser(userService, objectMapper, request);
return UserResourceGuardEnum.sameUser(userService, request);
}
},
@@ -39,9 +37,8 @@ public enum UserResourceGuardEnum {
@Override
public Boolean hasAccess(
UserService userService,
ObjectMapper objectMapper,
HttpServletRequest request) {
return adminUser(userService, objectMapper, request);
return UserResourceGuardEnum.adminUser(userService, request);
}
},
@@ -49,9 +46,8 @@ public enum UserResourceGuardEnum {
@Override
public Boolean hasAccess(
UserService userService,
ObjectMapper objectMapper,
HttpServletRequest request) {
return openAccess(userService, objectMapper, request);
return openAccess(userService, request);
}
};
@@ -70,19 +66,18 @@ public enum UserResourceGuardEnum {
throw new IllegalArgumentException("Argument not valid.");
}
private static boolean justUser(UserService userService, ObjectMapper objectMapper, HttpServletRequest request) {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDTO userLogged = userService.getUser(username);
private static boolean justUser(UserService userService, HttpServletRequest request) {
UserDTO userLogged = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userLogged.getAuthorities().contains(new SimpleGrantedAuthority(Role.USER.getDescription()));
}
private static boolean sameUser(UserService userService, ObjectMapper objectMapper, HttpServletRequest request) {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDTO userLogged = userService.getUser(username);
private static boolean sameUser(UserService userService, HttpServletRequest request) {
UserDTO userLogged = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Object requestPathVariable = request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, String> pathVariable = objectMapper.convertValue(requestPathVariable, HashMap.class);
UserDTO userInfo = userService.getUser(Long.parseLong(pathVariable.get("id")));
@@ -90,20 +85,17 @@ public enum UserResourceGuardEnum {
}
private static boolean adminUser(UserService userService, ObjectMapper objectMapper, HttpServletRequest request) {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDTO userLogged = userService.getUser(username);
private static boolean adminUser(UserService userService, HttpServletRequest request) {
UserDTO userLogged = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userLogged.getAuthorities().contains(new SimpleGrantedAuthority(Role.ADMIN.getDescription()));
}
private static Boolean openAccess(UserService userService, ObjectMapper objectMapper, HttpServletRequest request) {
private static Boolean openAccess(UserService userService, HttpServletRequest request) {
return true;
}
public abstract Boolean hasAccess(
UserService userService,
ObjectMapper objectMapper,
HttpServletRequest request);
}

View File

@@ -0,0 +1,113 @@
package br.com.hideyoshi.auth.util.guard;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@RequiredArgsConstructor
public class UserResourceHandler {
private final ListableBeanFactory beanFactory;
public List<String> getGuardedPaths() {
return this.extractPathsFromMethods(this.getGuardedResources());
}
public List<String> getOpenPaths() {
return this.extractPathsFromMethods(this.getOpenResources());
}
private List<String> extractPathsFromMethods(List<Method> methods) {
final List<String> paths = new ArrayList<>();
for (final Method method : methods) {
String[] parentPath = new String[0];
RequestMapping classAnnotation = method.getDeclaringClass().getAnnotation(RequestMapping.class);
if (classAnnotation != null) {
parentPath = this.getPathFromAnnotation(classAnnotation);
}
List<Annotation> annotations = List.of(method.getAnnotations());
for (Annotation annotation : annotations) {
final String[] path = this.getPathFromAnnotation(annotation);
if (path != null)
paths.add(String.join("/", parentPath) + String.join("/", path));
}
}
return paths;
}
private List<Method> getGuardedResources() {
final List<UserResourceGuardEnum> guardedAccessTypes = Arrays.asList(
UserResourceGuardEnum.USER,
UserResourceGuardEnum.SAME_USER,
UserResourceGuardEnum.ADMIN_USER
);
final List<Method> methods = new ArrayList<>();
for (final Class<?> controllerClass : this.getControllerClasses()) {
methods.addAll(this.getMethodsByAccessType(controllerClass, guardedAccessTypes));
}
return methods;
}
private List<Method> getOpenResources() {
final List<UserResourceGuardEnum> openAccessTypes = List.of(UserResourceGuardEnum.OPEN);
final List<Method> methods = new ArrayList<>();
for (final Class<?> controllerClass : this.getControllerClasses()) {
methods.addAll(this.getMethodsByAccessType(controllerClass, openAccessTypes));
}
return methods;
}
private List<Method> getMethodsByAccessType(final Class<?> controllerClass, List<UserResourceGuardEnum> accessTypes) {
final List<Method> methods = new ArrayList<>();
for (final Method method : controllerClass.getDeclaredMethods()) {
if (!method.isAnnotationPresent(UserResourceGuard.class)) {
continue;
}
UserResourceGuard annotation = method.getAnnotation(UserResourceGuard.class);
if (!accessTypes.contains(annotation.accessType())) {
continue;
}
methods.add(method);
}
return methods;
}
private List<Class<?>> getControllerClasses() {
final List<Class<?>> controllerClasses = new ArrayList<>();
for (final String beanName : this.beanFactory.getBeanNamesForAnnotation(Controller.class)) {
controllerClasses.add(this.beanFactory.getType(beanName));
}
return controllerClasses;
}
private String[] getPathFromAnnotation(Annotation annotation) {
String[] path; String[] value;
try {
value = (String[]) annotation.annotationType().getMethod("value").invoke(annotation);
path = (String[]) annotation.annotationType().getMethod("path").invoke(annotation);
} catch (Exception e) {
return null;
}
return value.length > 0 ? value : path;
}
}

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.util.guard;
package br.com.hideyoshi.auth.util.guard;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import br.com.hideyoshi.auth.model.UserDTO;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.validation.ConstraintValidator;

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.util.handler;
package br.com.hideyoshi.auth.util.handler;
import com.hideyoshi.auth.util.exception.*;
import br.com.hideyoshi.auth.util.exception.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -40,6 +40,15 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler {
HttpStatus.FORBIDDEN);
}
@ExceptionHandler(AuthorizationException.class)
public ResponseEntity<AuthorizationExceptionDetails> handleBadRequest(final AuthorizationException exception) {
return new ResponseEntity<>(
new AuthorizationExceptionDetails("Authorization Failed. Check your permissions.",
HttpStatus.FORBIDDEN.value(), exception.getMessage(),
exception.getClass().getName(), LocalDateTime.now()),
HttpStatus.FORBIDDEN);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
final MethodArgumentNotValidException exception, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.util.validator.email.unique;
package br.com.hideyoshi.auth.util.validator.email.unique;
import com.hideyoshi.auth.base.auth.repo.UserRepository;
import br.com.hideyoshi.auth.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import javax.validation.ConstraintValidator;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.validator.email.unique;
package br.com.hideyoshi.auth.util.validator.email.unique;
import javax.validation.Constraint;
import javax.validation.Payload;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.validator.email.valid;
package br.com.hideyoshi.auth.util.validator.email.valid;
import lombok.RequiredArgsConstructor;

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth.util.validator.email.valid;
package br.com.hideyoshi.auth.util.validator.email.valid;
import javax.validation.Constraint;
import javax.validation.Payload;

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.util.validator.password;
package br.com.hideyoshi.auth.util.validator.password;
import com.hideyoshi.auth.base.auth.entity.Provider;
import br.com.hideyoshi.auth.enums.Provider;
import lombok.RequiredArgsConstructor;
import javax.validation.ConstraintValidator;

View File

@@ -1,6 +1,6 @@
package com.hideyoshi.auth.util.validator.password;
package br.com.hideyoshi.auth.util.validator.password;
import com.hideyoshi.auth.base.auth.entity.Provider;
import br.com.hideyoshi.auth.enums.Provider;
import javax.validation.Constraint;
import javax.validation.Payload;

View File

@@ -1,21 +0,0 @@
package com.hideyoshi.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootApplication
public class AuthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@@ -1,122 +0,0 @@
package com.hideyoshi.auth.base.auth.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.base.config.RestAuthenticationEntryPointConfig;
import com.hideyoshi.auth.base.auth.filter.CustomAuthenticationFilter;
import com.hideyoshi.auth.base.auth.filter.CustomAuthorizationFilter;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import com.hideyoshi.auth.base.auth.oauth.repo.OAuthRequestRepository;
import com.hideyoshi.auth.base.auth.service.AuthService;
import com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@Log4j2
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthService authService;
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder passwordEncoder;
private final OAuthRequestRepository oAuthRequestRepository;
private final RestAuthenticationEntryPointConfig restAuthenticationEntryPointConfig;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
this.addSecurityToHttp(http);
this.addOAuthSecurityToHttp(http);
}
private void addSecurityToHttp(HttpSecurity http) throws Exception {
CustomAuthenticationFilter customAuthenticationFilter =
new CustomAuthenticationFilter(this.authenticationManager(), this.authService, this.restAuthenticationEntryPointConfig);
customAuthenticationFilter.setFilterProcessesUrl("/user/login");
http.authorizeRequests()
.antMatchers("/session/**").permitAll()
.and().authorizeRequests().antMatchers("/health").permitAll()
.and().authorizeRequests().antMatchers("/user/signup").permitAll()
.and().authorizeRequests().antMatchers("/user/oauth/**").permitAll()
.and().authorizeRequests().antMatchers("/user/login/**").permitAll()
.and().authorizeRequests().antMatchers("/**").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and().addFilter(customAuthenticationFilter)
.addFilterBefore(new CustomAuthorizationFilter(this.authService), UsernamePasswordAuthenticationFilter.class);
}
private void addOAuthSecurityToHttp(HttpSecurity http) throws Exception {
http.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(this.oAuthRequestRepository)
.and().successHandler(this::successHandler)
.failureHandler(this::failureHandler);
}
private void successHandler(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
AuthDTO authUser = this.authService.loginOAuthUser(oauthUser, request);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authUser);
}
private void failureHandler(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e) {
throw new AuthenticationInvalidException("Invalid Authentication Attempt.");
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

View File

@@ -1,69 +0,0 @@
package com.hideyoshi.auth.base.auth.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.base.config.RestAuthenticationEntryPointConfig;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import com.hideyoshi.auth.base.auth.service.AuthService;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@Log4j2
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthService authService;
private final AuthenticationManager authenticationManager;
private final RestAuthenticationEntryPointConfig restAuthenticationEntryPointConfig;
public CustomAuthenticationFilter(AuthenticationManager authenticationManager, AuthService authService, RestAuthenticationEntryPointConfig restAuthenticationEntryPointConfig) {
this.authService = authService;
this.authenticationManager = authenticationManager;
this.restAuthenticationEntryPointConfig = restAuthenticationEntryPointConfig;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
Authentication userAuthentication = null;
try {
userAuthentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)
);
} catch (AuthenticationException e) {
restAuthenticationEntryPointConfig.commence(request, response, e);
}
return userAuthentication;
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException {
AuthDTO authUser = this.authService.loginUser(
request,
response,
(UserDTO) authentication.getPrincipal()
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authUser);
}
}

View File

@@ -1,86 +0,0 @@
package com.hideyoshi.auth.base.auth.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.base.auth.service.AuthService;
import com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import com.hideyoshi.auth.util.exception.AuthenticationInvalidExceptionDetails;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
public class CustomAuthorizationFilter extends OncePerRequestFilter {
private static final List<String> notProtectedPaths = Arrays.asList(
"/health",
"/user/login",
"/user/signup",
"/user/login/refresh",
"/session/validate",
"/session/destroy"
);
private static final String AUTHORIZATION_TYPE_STRING = "Bearer ";
private final AuthService authService;
public CustomAuthorizationFilter(AuthService authService) {
this.authService = authService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.isPathNotProtected(request.getServletPath())) {
filterChain.doFilter(request, response);
return;
}
String authorizationHeader = request.getHeader(AUTHORIZATION);
try {
UsernamePasswordAuthenticationToken authenticationToken =
this.validateUserAccess(authorizationHeader);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
} catch (Exception e) {
response.setHeader("error", e.getMessage());
response.setStatus(FORBIDDEN.value());
AuthenticationInvalidExceptionDetails error = new AuthenticationInvalidExceptionDetails("Authentication Failed. Check your credentials.",
HttpStatus.FORBIDDEN.value(), e.getMessage(),
e.getClass().getName(), LocalDateTime.now());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), error);
}
}
private Boolean isPathNotProtected(String path) {
return notProtectedPaths.contains(path);
}
private UsernamePasswordAuthenticationToken validateUserAccess(String authorizationHeader) {
if (Objects.nonNull(authorizationHeader) && authorizationHeader.startsWith(AUTHORIZATION_TYPE_STRING)) {
String accessToken = authorizationHeader.substring(AUTHORIZATION_TYPE_STRING.length());
return this.authService.extractAccessTokenInfo(accessToken);
} else {
throw new AuthenticationInvalidException("Access denied");
}
}
}

View File

@@ -1,27 +0,0 @@
package com.hideyoshi.auth.base.auth.oauth.mapper;
import com.hideyoshi.auth.base.auth.entity.Provider;
import lombok.AllArgsConstructor;
import org.springframework.security.oauth2.core.user.OAuth2User;
@AllArgsConstructor
public class GithubOAuthMap implements OAuthMap {
private OAuth2User oAuth2User;
@Override
public String getPrincipal() {
return oAuth2User.getAttribute("login");
}
@Override
public String getProfilePicture() {
return this.oAuth2User.getAttribute("avatar_url");
}
@Override
public Provider getProvider() {
return Provider.GITHUB;
}
}

View File

@@ -1,27 +0,0 @@
package com.hideyoshi.auth.base.auth.oauth.mapper;
import com.hideyoshi.auth.base.auth.entity.Provider;
import lombok.AllArgsConstructor;
import org.springframework.security.oauth2.core.user.OAuth2User;
@AllArgsConstructor
public class GoogleOAuthMap implements OAuthMap {
private OAuth2User oAuth2User;
@Override
public String getPrincipal() {
return this.oAuth2User.getAttribute("given_name");
}
@Override
public String getProfilePicture() {
return this.oAuth2User.getAttribute("picture");
}
@Override
public Provider getProvider() {
return Provider.GOOGLE;
}
}

View File

@@ -1,13 +0,0 @@
package com.hideyoshi.auth.base.auth.oauth.mapper;
import com.hideyoshi.auth.base.auth.entity.Provider;
public interface OAuthMap {
String getPrincipal();
String getProfilePicture();
Provider getProvider();
}

View File

@@ -1,35 +0,0 @@
package com.hideyoshi.auth.base.auth.oauth.mapper;
import com.hideyoshi.auth.base.auth.entity.Provider;
import lombok.Getter;
public enum OAuthMapper {
GOOGLE(GoogleOAuthMap.class, Provider.GOOGLE),
GITHUB(GithubOAuthMap.class, Provider.GITHUB);
private final Class<? extends OAuthMap> oAuthMap;
@Getter
private final Provider provider;
private OAuthMapper(Class<? extends OAuthMap> oAuthMap, Provider provider) {
this.oAuthMap = oAuthMap;
this.provider = provider;
}
public static OAuthMapper byValue(Provider provider) {
for (OAuthMapper e : values()) {
if (e.getProvider().equals(provider)) {
return e;
}
}
throw new IllegalArgumentException("Argument not valid.");
}
public Class<? extends OAuthMap> getMap() {
return oAuthMap;
}
}

View File

@@ -1,33 +0,0 @@
package com.hideyoshi.auth.base.config;
import com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Log4j2
@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPointConfig implements AuthenticationEntryPoint {
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) {
resolver.resolveException(
request,
response,
null,
new AuthenticationInvalidException("Authentication Failed. Check your credentials.")
);
}
}

View File

@@ -1,22 +0,0 @@
package com.hideyoshi.auth.base.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
public class SessionConfig {
@Value("${com.hideyoshi.frontEndPath}")
private String frontEndPath;
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("(^.+)?(\\.)?(" + frontEndPath + ")((/#!)?(/\\w+)+)?");
return serializer;
}
}

View File

@@ -1,13 +0,0 @@
package com.hideyoshi.auth.base.session.service;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import javax.servlet.http.HttpSession;
public interface SessionManagerService {
AuthDTO validateSession(HttpSession session);
void destroySession(HttpSession session);
}

View File

@@ -1,23 +0,0 @@
package com.hideyoshi.auth.base.session.service;
import com.hideyoshi.auth.base.auth.model.AuthDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
@Service
@RequiredArgsConstructor
public class SessionManagerServiceImpl implements SessionManagerService {
@Override
public AuthDTO validateSession(HttpSession session) {
return (AuthDTO) session.getAttribute("user");
}
@Override
public void destroySession(HttpSession session) {
session.invalidate();
}
}

View File

@@ -1,17 +1,18 @@
com:
hideyoshi:
frontendPath: ${FRONTEND_PATH}
tokenSecret: ${TOKEN_SECRET}
accessTokenDuration: ${ACCESS_TOKEN_DURATION}
refreshTokenDuration: ${REFRESH_TOKEN_DURATION}
defaultUser:
fullName: ${DEFAULT_USER_FULLNAME}
email: ${DEFAULT_USER_EMAIL}
username: ${DEFAULT_USER_USERNAME}
password: ${DEFAULT_USER_PASSWORD}
br:
com:
hideyoshi:
frontendPath: ${FRONTEND_PATH}
tokenSecret: ${TOKEN_SECRET}
accessTokenDuration: ${ACCESS_TOKEN_DURATION}
refreshTokenDuration: ${REFRESH_TOKEN_DURATION}
defaultUser:
fullName: ${DEFAULT_USER_FULLNAME}
email: ${DEFAULT_USER_EMAIL}
username: ${DEFAULT_USER_USERNAME}
password: ${DEFAULT_USER_PASSWORD}
microservice:
storageServicePath: ${STORAGE_SERVICE_PATH}
microservice:
storageServicePath: ${STORAGE_SERVICE_PATH}
server:

View File

@@ -1,4 +1,4 @@
package com.hideyoshi.auth;
package br.com.hideyoshi.auth;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

View File

@@ -1,10 +1,9 @@
package com.hideyoshi.auth.base.user.repo;
package br.com.hideyoshi.auth.repository;
import com.hideyoshi.auth.base.auth.repo.UserRepository;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.entity.User;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.entity.User;
import br.com.hideyoshi.auth.model.UserDTO;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -1,12 +1,11 @@
package com.hideyoshi.auth.base.user.service;
package br.com.hideyoshi.auth.service;
import com.hideyoshi.auth.base.auth.service.UserService;
import com.hideyoshi.auth.base.auth.entity.Provider;
import com.hideyoshi.auth.base.auth.entity.Role;
import com.hideyoshi.auth.base.auth.entity.User;
import com.hideyoshi.auth.base.auth.model.UserDTO;
import com.hideyoshi.auth.base.auth.repo.UserRepository;
import com.hideyoshi.auth.util.exception.BadRequestException;
import br.com.hideyoshi.auth.enums.Provider;
import br.com.hideyoshi.auth.enums.Role;
import br.com.hideyoshi.auth.entity.User;
import br.com.hideyoshi.auth.model.UserDTO;
import br.com.hideyoshi.auth.repository.UserRepository;
import br.com.hideyoshi.auth.util.exception.BadRequestException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -17,6 +16,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.annotation.DirtiesContext;
@@ -387,7 +387,7 @@ class UserServiceTest {
// When
//Then
assertThrows(
BadRequestException.class,
UsernameNotFoundException.class,
() -> {
this.underTest.loadUserByUsername(user.getUsername());
},

View File

@@ -1,10 +1,10 @@
package com.hideyoshi.auth.microservice.storageService.service;
package br.com.hideyoshi.auth.service.microservice;
import br.com.hideyoshi.auth.config.StorageServiceConfig;
import br.com.hideyoshi.auth.enums.FileTypeEnum;
import br.com.hideyoshi.auth.model.microservice.StorageServiceDownloadResponse;
import br.com.hideyoshi.auth.model.microservice.StorageServiceUploadResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.auth.microservice.storageService.config.StorageServiceConfig;
import com.hideyoshi.auth.microservice.storageService.enums.FileTypeEnum;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceDownloadResponse;
import com.hideyoshi.auth.microservice.storageService.model.StorageServiceUploadResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;