diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b480548..3cfe413 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ { "name": "Java", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/java:0-17", + "image": "mcr.microsoft.com/devcontainers/java:1-21", "features": { "ghcr.io/devcontainers/features/java:1": { diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85d31fc..9d2d8ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,10 +19,10 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: "temurin" - name: Cache SonarCloud packages diff --git a/README.md b/README.md index ccfda96..e3a789c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ In this project you can find an openapi [specification](./openapi.yaml) with all ## Dependencies You need -- java 17 installed +- java 21 installed - docker 20+ installed - maven 3.8.5+ installed diff --git a/openapi.yaml b/openapi.yaml index 68425a0..b20b1e3 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: description: "Rest API to perform operations on e-cordels" - version: "1.0.0" + version: "1.6.0" title: "E-cordel API" contact: url: https://ecordel.com.br diff --git a/pom.xml b/pom.xml index f893cce..453ec3b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,18 +5,18 @@ org.springframework.boot spring-boot-starter-parent - 3.1.11 + 3.2.5 br.com.itsmemario ecordel - 1.5.2 + 1.6.0 e-cordel e-reader for cordels - 17 + 21 itsmemario e-cordel_ecordel-restapi e-cordel @@ -26,7 +26,7 @@ 3.10.0 0.9.1 1.18.32 - 1.19.7 + 1.19.8 3.1.0 2.6 2.3.1 diff --git a/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java b/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java index 69cf1d9..d0c92d8 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java @@ -17,12 +17,12 @@ package br.com.itsmemario.ecordel.security; +import jakarta.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -32,16 +32,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import jakarta.validation.Valid; - @RestController @RequestMapping("/auth") public class AuthenticationController { - private Logger logger = LoggerFactory.getLogger(AuthenticationController.class); + private final Logger logger = LoggerFactory.getLogger(AuthenticationController.class); - private AuthenticationProvider provider; - private AuthenticationService authenticationService; + private final AuthenticationProvider provider; + private final AuthenticationService authenticationService; @Autowired public AuthenticationController(AuthenticationProvider provider, AuthenticationService authenticationService) { diff --git a/src/main/java/br/com/itsmemario/ecordel/security/CordelAuthority.java b/src/main/java/br/com/itsmemario/ecordel/security/CordelAuthority.java index 28df161..cb4f322 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/CordelAuthority.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/CordelAuthority.java @@ -17,9 +17,13 @@ package br.com.itsmemario.ecordel.security; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.springframework.security.core.GrantedAuthority; -import jakarta.persistence.*; @Entity @Table(name = "cordel_authority") @@ -31,7 +35,7 @@ public class CordelAuthority implements GrantedAuthority{ public static final String AUTHOR = "AUTHOR"; @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy= GenerationType.IDENTITY) private Long id; private String authority; diff --git a/src/main/java/br/com/itsmemario/ecordel/security/CordelUser.java b/src/main/java/br/com/itsmemario/ecordel/security/CordelUser.java index ea646b5..0742577 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/CordelUser.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/CordelUser.java @@ -1,9 +1,18 @@ package br.com.itsmemario.ecordel.security; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; +import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import jakarta.persistence.*; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -16,20 +25,21 @@ public class CordelUser implements UserDetails { public static final String USER_AUTHORITY_TABLE = "user_authority"; - @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @Id + @Getter + @GeneratedValue(strategy= GenerationType.IDENTITY) private Long id; private String username; private String password; private boolean enabled = true; - @ManyToMany(fetch=FetchType.EAGER) + @ManyToMany(fetch= FetchType.EAGER) @JoinTable( name = USER_AUTHORITY_TABLE, joinColumns = @JoinColumn(name="user_id"), inverseJoinColumns = @JoinColumn(name="authority_id") ) - private Set authorities = new HashSet<>(); + private final Set authorities = new HashSet<>(); CordelUser() {} @@ -72,12 +82,8 @@ public boolean isEnabled() { return enabled; } - public Long getId() { - return id; - } - - public List getAuthorityNames(){ - return authorities.stream().map(CordelAuthority::getAuthority).collect(Collectors.toList()); + public List getAuthorityNames(){ + return authorities.stream().map(CordelAuthority::getAuthority).toList(); } diff --git a/src/main/java/br/com/itsmemario/ecordel/security/LoginData.java b/src/main/java/br/com/itsmemario/ecordel/security/LoginData.java index 8ab2aa9..c6abb27 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/LoginData.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/LoginData.java @@ -17,8 +17,10 @@ package br.com.itsmemario.ecordel.security; +import lombok.Getter; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +@Getter public class LoginData { private String username; @@ -32,15 +34,7 @@ public LoginData(String username, String password) { this.password = password; } - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public UsernamePasswordAuthenticationToken toAuthenticationToken() { + public UsernamePasswordAuthenticationToken toAuthenticationToken() { return new UsernamePasswordAuthenticationToken(username, password); } diff --git a/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java b/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java index acb67a0..02a1ca4 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java @@ -27,6 +27,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @@ -52,25 +53,26 @@ public SecurityConfig(BCryptPasswordEncoder encoder, AuthenticationService authe @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.cors().and() - .csrf().disable()// TODO review - .authorizeHttpRequests() - .requestMatchers(HttpMethod.POST, "/auth").permitAll() - .requestMatchers(HttpMethod.GET, "/**").permitAll() - .requestMatchers(HttpMethod.POST, "/cordels/**").hasAnyAuthority(CordelAuthority.ADMIN, CordelAuthority.AUTHOR, CordelAuthority.EDITOR) - .requestMatchers(HttpMethod.PUT, "/cordels/**").hasAnyAuthority(CordelAuthority.ADMIN, CordelAuthority.AUTHOR, CordelAuthority.EDITOR) - .requestMatchers(HttpMethod.POST, "/authors/**").hasAnyAuthority(CordelAuthority.ADMIN) - .requestMatchers(HttpMethod.PUT, "/authors/**").hasAnyAuthority(CordelAuthority.ADMIN) - .anyRequest().authenticated().and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and().addFilterBefore(new TokenAuthenticationFilter(authenticationService), UsernamePasswordAuthenticationFilter.class); + http.cors(cors -> corsConfigurationSource()) + .csrf(AbstractHttpConfigurer::disable) + .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(req -> { + req.requestMatchers(HttpMethod.POST, "/auth").permitAll(); + req.requestMatchers(HttpMethod.GET, "/**").permitAll(); + req.requestMatchers(HttpMethod.POST, "/cordels/**").hasAnyAuthority(CordelAuthority.ADMIN, CordelAuthority.AUTHOR, CordelAuthority.EDITOR); + req.requestMatchers(HttpMethod.PUT, "/cordels/**").hasAnyAuthority(CordelAuthority.ADMIN, CordelAuthority.AUTHOR, CordelAuthority.EDITOR); + req.requestMatchers(HttpMethod.POST, "/authors/**").hasAnyAuthority(CordelAuthority.ADMIN); + req.requestMatchers(HttpMethod.PUT, "/authors/**").hasAnyAuthority(CordelAuthority.ADMIN); + req.anyRequest().authenticated(); + }) + .addFilterBefore(new TokenAuthenticationFilter(authenticationService), UsernamePasswordAuthenticationFilter.class); return http.build(); } - + @Bean public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring() + return web -> web.ignoring() .requestMatchers("/**.html", "/v2/api-docs", "/webjars/**", "/configuration/**", "/swagger-resources/**"); } diff --git a/src/main/java/br/com/itsmemario/ecordel/security/TokenAuthenticationFilter.java b/src/main/java/br/com/itsmemario/ecordel/security/TokenAuthenticationFilter.java index 2a96bcf..34f7720 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/TokenAuthenticationFilter.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/TokenAuthenticationFilter.java @@ -32,10 +32,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter{ - private final Logger logger = LoggerFactory.getLogger(TokenAuthenticationFilter.class); + private final Logger tokenAuthLogger = LoggerFactory.getLogger(TokenAuthenticationFilter.class); public static final String AUTHORIZATION = "Authorization"; - private AuthenticationService authenticationService; + private final AuthenticationService authenticationService; TokenAuthenticationFilter(AuthenticationService authenticationService) { super(); @@ -76,7 +76,7 @@ private void authorizeRequestWithToken(String token) { Optional userFromToken = authenticationService.getUserFromToken(token); if(userFromToken.isPresent()) { CordelUser user = userFromToken.get(); - logger.info("authorizing {}",user.getUsername()); + tokenAuthLogger.info("authorizing {}",user.getUsername()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/src/main/java/br/com/itsmemario/ecordel/security/TokenDto.java b/src/main/java/br/com/itsmemario/ecordel/security/TokenDto.java index b13f745..1dfe176 100644 --- a/src/main/java/br/com/itsmemario/ecordel/security/TokenDto.java +++ b/src/main/java/br/com/itsmemario/ecordel/security/TokenDto.java @@ -17,36 +17,7 @@ package br.com.itsmemario.ecordel.security; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class TokenDto { - - private final String token; - private final String authenticationMethod; - private final Long expiresAt; - - @JsonCreator - public TokenDto(@JsonProperty("token") String token, - @JsonProperty("authenticationMethod") String authenticationMethod, - @JsonProperty("expiresAt") Long expiresAt) { - super(); - this.token = token; - this.authenticationMethod = authenticationMethod; - this.expiresAt = expiresAt; - } - - public String getToken() { - return token; - } - - public String getAuthenticationMethod() { - return authenticationMethod; - } - - public Long getExpiresAt() { - return expiresAt; - } +public record TokenDto(String token, String authenticationMethod, Long expiresAt) { @Override public String toString() {