diff --git a/pom.xml b/pom.xml
index 453ec3b..1c579ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.2.5
+ 3.3.0
@@ -24,7 +24,7 @@
${basedir}/target/site/jacoco/**
42.7.3
3.10.0
- 0.9.1
+ 0.12.5
1.18.32
1.19.8
3.1.0
@@ -34,8 +34,6 @@
5.1.0
1.4.9
0.8.9
- 2.16.0
- 9.37.3
@@ -59,13 +57,6 @@
spring-boot-starter-validation
-
-
- com.nimbusds
- nimbus-jose-jwt
- ${nimbus-jose-jwt.version}
-
-
org.springframework.boot
spring-boot-starter-cache
@@ -103,6 +94,11 @@
flyway-core
+
+ org.flywaydb
+ flyway-database-postgresql
+
+
commons-net
commons-net
@@ -111,20 +107,22 @@
io.jsonwebtoken
- jjwt
+ jjwt-api
+ ${jjwt.version}
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
${jjwt.version}
-
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
+ runtime
- com.fasterxml.jackson.core
- jackson-databind
- ${jackson-databind.version}
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+ runtime
@@ -133,6 +131,8 @@
${lombok.version}
+
+
org.springframework.security
spring-security-test
@@ -166,12 +166,6 @@
test
-
- javax.xml.bind
- jaxb-api
- ${jaxb-api.version}
-
-
diff --git a/postman-collection/ecordel.postman_collection.json b/postman-collection/ecordel.postman_collection.json
new file mode 100644
index 0000000..37052f0
--- /dev/null
+++ b/postman-collection/ecordel.postman_collection.json
@@ -0,0 +1,405 @@
+{
+ "info": {
+ "_postman_id": "6c24e3de-35cb-4bb2-8dd9-60f05eaffd0a",
+ "name": "ecordel",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "item": [
+ {
+ "name": "cordels",
+ "item": [
+ {
+ "name": "cordels",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{ecordel_url}}/cordels/summaries?size=30&page=0&authorId=3",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "cordels",
+ "summaries"
+ ],
+ "query": [
+ {
+ "key": "size",
+ "value": "30"
+ },
+ {
+ "key": "page",
+ "value": "0"
+ },
+ {
+ "key": "authorId",
+ "value": "3"
+ }
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ },
+ {
+ "name": "cordels/{id}",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{ecordel_url}}/cordels/39",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "cordels",
+ "39"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ },
+ {
+ "name": "new cordel",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n\t\"author\": {\"id\": 1},\n \"title\": \"Titulo\",\n \"xilogravura\": \"\",\n \"description\": \"Descrição\",\n \"content\":\"Conteúdo\\nConteúdo\"\n}"
+ },
+ "url": {
+ "raw": "{{ecordel_url}}/cordels",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ },
+ {
+ "name": "put xilogravura",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "PUT",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "formdata",
+ "formdata": [
+ {
+ "key": "file",
+ "type": "file",
+ "src": []
+ }
+ ]
+ },
+ "url": {
+ "raw": "{{ecordel_url}}/cordels/1/xilogravura",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "cordels",
+ "1",
+ "xilogravura"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "authors",
+ "item": [
+ {
+ "name": "new author",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n\t\"name\": \"Author Test\",\n \"about\": \"About author test\",\n \"email\": \"author.test@ecordel.com\"\n}"
+ },
+ "url": {
+ "raw": "{{ecordel_url}}/authors",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "authors"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ },
+ {
+ "name": "authors",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{ecordel_url}}/authors",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "authors"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "auth",
+ "item": [
+ {
+ "name": "login",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// set token collection variable\r",
+ "pm.collectionVariables.set(\"token\", pm.response.json().token);\r",
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n\t\"username\":\"admin\",\n\t\"password\":\"admin\"\n}"
+ },
+ "url": {
+ "raw": "{{ecordel_url}}/auth",
+ "host": [
+ "{{ecordel_url}}"
+ ],
+ "path": [
+ "auth"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Default",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{url}}/cordels",
+ "host": [
+ "{{url}}"
+ ],
+ "path": [
+ "cordels"
+ ]
+ }
+ },
+ "code": 200,
+ "_postman_previewlanguage": "Text",
+ "header": [],
+ "cookie": [],
+ "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "variable": [
+ {
+ "key": "token",
+ "value": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/postman-collection/local.postman_environment.json b/postman-collection/local.postman_environment.json
new file mode 100644
index 0000000..bc4b2f4
--- /dev/null
+++ b/postman-collection/local.postman_environment.json
@@ -0,0 +1,14 @@
+{
+ "id": "15cbdb92-e67d-4bfc-b3b3-fa908575573c",
+ "name": "local",
+ "values": [
+ {
+ "key": "ecordel_url",
+ "value": "http://localhost:5000/api/v1",
+ "enabled": true
+ }
+ ],
+ "_postman_variable_scope": "environment",
+ "_postman_exported_at": "2024-06-01T10:51:35.494Z",
+ "_postman_exported_using": "Postman/10.17.3"
+}
\ No newline at end of file
diff --git a/src/main/java/br/com/itsmemario/ecordel/EcordelApplication.java b/src/main/java/br/com/itsmemario/ecordel/EcordelApplication.java
index 2acba16..72fe597 100644
--- a/src/main/java/br/com/itsmemario/ecordel/EcordelApplication.java
+++ b/src/main/java/br/com/itsmemario/ecordel/EcordelApplication.java
@@ -17,7 +17,6 @@
package br.com.itsmemario.ecordel;
-import br.com.itsmemario.ecordel.security.jwt.JwtToken;
import br.com.itsmemario.ecordel.security.jwt.JwtTokenService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.SpringApplication;
@@ -39,11 +38,6 @@ public static void main(String[] args) {
SpringApplication.run(EcordelApplication.class, args);
}
- @Bean
- public JwtToken jwtToken() {
- return jwtTokenService.findTop();
- }
-
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
diff --git a/src/main/java/br/com/itsmemario/ecordel/exception/DefaultExceptionHandler.java b/src/main/java/br/com/itsmemario/ecordel/exception/DefaultExceptionHandler.java
index cee6051..5c46894 100644
--- a/src/main/java/br/com/itsmemario/ecordel/exception/DefaultExceptionHandler.java
+++ b/src/main/java/br/com/itsmemario/ecordel/exception/DefaultExceptionHandler.java
@@ -17,10 +17,7 @@
package br.com.itsmemario.ecordel.exception;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.springframework.beans.factory.annotation.Autowired;
+import lombok.AllArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
@@ -30,10 +27,12 @@
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
+import java.util.List;
+
@RestControllerAdvice
+@AllArgsConstructor
public class DefaultExceptionHandler {
- @Autowired
private MessageSource messageSource;
@ResponseStatus(code=HttpStatus.BAD_REQUEST)
@@ -46,7 +45,7 @@ public List handle(MethodArgumentNotValidException exception) {
String msg = messageSource.getMessage(err, LocaleContextHolder.getLocale());
return new FormError(err.getField(), msg);
}
- ) .collect(Collectors.toList());
+ ) .toList();
}
}
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 d0c92d8..798fd47 100644
--- a/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java
+++ b/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationController.java
@@ -48,14 +48,15 @@ public AuthenticationController(AuthenticationProvider provider, AuthenticationS
}
@PostMapping
- public ResponseEntity authenticate(@RequestBody @Valid LoginData data){
- logger.info("Login attempt");
+ public ResponseEntity authenticate(@RequestBody @Valid LoginData loginData){
+ logger.info("Login attempt, user: {}", loginData.getUsername());
try {
- UsernamePasswordAuthenticationToken authenticationToken = data.toAuthenticationToken();
+ UsernamePasswordAuthenticationToken authenticationToken = loginData.toAuthenticationToken();
Authentication authentication = provider.authenticate(authenticationToken);
TokenDto tokenDto = authenticationService.generateToken(authentication);
return ResponseEntity.ok(tokenDto);
} catch (AuthenticationException e) {
+ logger.info("Authentication failed for user: {}", loginData.getUsername());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
diff --git a/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationService.java b/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationService.java
index fa17b3d..98b5356 100644
--- a/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationService.java
+++ b/src/main/java/br/com/itsmemario/ecordel/security/AuthenticationService.java
@@ -17,10 +17,13 @@
package br.com.itsmemario.ecordel.security;
-import br.com.itsmemario.ecordel.security.jwt.JwtToken;
+import br.com.itsmemario.ecordel.security.jwt.JwtTokenService;
import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,6 +33,7 @@
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
+import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Optional;
@@ -39,12 +43,12 @@ public class AuthenticationService implements UserDetailsService {
public static final String BEARER = "Bearer";
public static final String ROLES = "roles";
-
private static final String ISSUER = "e-cordel";
+
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final UserRepository repository;
- private final JwtToken jwtToken;
+ private final JwtTokenService tokenService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -58,43 +62,54 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
public TokenDto generateToken(Authentication authentication) {
CordelUser principal = (CordelUser) authentication.getPrincipal();
-
- Date today = new Date();
- Date expiration = new Date(today.getTime() + jwtToken.getExpiration());
-
+ Date expiration = calculateExpiration();
+
String token = Jwts.builder()
- .setIssuer(ISSUER)
- .setSubject(principal.getId().toString())
+ .issuer(ISSUER)
+ .subject(principal.getId().toString())
.claim(ROLES, principal.getAuthorityNames())
- .setIssuedAt(today)
- .setExpiration(expiration)
- .signWith(SignatureAlgorithm.HS256, jwtToken.getSecretKey())
+ .issuedAt(new Date())
+ .expiration(expiration)
+ .signWith(decodeSecretKey())
.compact();
return new TokenDto(token, BEARER, expiration.getTime());
}
+ private Date calculateExpiration() {
+ return new Date(new Date().getTime() + tokenService.findTop().getExpiration());
+ }
+
public boolean isValidToken(String token) {
try {
- return Jwts.parser()
- .setSigningKey(jwtToken.getSecretKey())
- .requireIssuer(ISSUER)
- .parseClaimsJws(token)!=null;
- }catch(io.jsonwebtoken.SignatureException e) {
+ return parseToken(token) != null;
+ } catch (SignatureException e) {
return false;
}
}
public Optional getUserFromToken(String token) {
try {
- Claims body = Jwts.parser().setSigningKey(jwtToken.getSecretKey()).parseClaimsJws(token).getBody();
+ Claims body = parseToken(token).getPayload();
Long id = Long.parseLong(body.getSubject());
return repository.findById(id);
- } catch (io.jsonwebtoken.SignatureException e) {
- logger.warn("No possible to parser token: {}", e.getMessage());
+ } catch (SignatureException e) {
+ logger.error("No possible to parser token: {}", e.getMessage());
return Optional.empty();
}
}
-
-
+
+ private Jws parseToken(String token) throws SignatureException {
+ return Jwts.parser()
+ .verifyWith(decodeSecretKey())
+ .requireIssuer(ISSUER)
+ .build()
+ .parseSignedClaims(token);
+ }
+
+ private SecretKey decodeSecretKey() {
+ byte[] keyBytes = Decoders.BASE64.decode(tokenService.findTop().getSecretKey());
+ return Keys.hmacShaKeyFor(keyBytes);
+ }
+
}
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 02a1ca4..b28303b 100644
--- a/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java
+++ b/src/main/java/br/com/itsmemario/ecordel/security/SecurityConfig.java
@@ -81,7 +81,7 @@ public WebSecurityCustomizer webSecurityCustomizer() {
* @param args
*/
public static void main(String[] args) {
- //System.out.println(new BCryptPasswordEncoder().encode(""));
+ // System.out.println(new BCryptPasswordEncoder().encode("admin"));
}
@Bean
diff --git a/src/main/java/br/com/itsmemario/ecordel/security/jwt/JwtTokenService.java b/src/main/java/br/com/itsmemario/ecordel/security/jwt/JwtTokenService.java
index 68f4225..e030b8a 100644
--- a/src/main/java/br/com/itsmemario/ecordel/security/jwt/JwtTokenService.java
+++ b/src/main/java/br/com/itsmemario/ecordel/security/jwt/JwtTokenService.java
@@ -18,16 +18,29 @@
package br.com.itsmemario.ecordel.security.jwt;
import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
+import java.util.concurrent.TimeUnit;
+
@Service
@RequiredArgsConstructor
public class JwtTokenService {
+ public static final String SECRET_KEY = "secretKey";
private final JwtTokenRepository repository;
+ @Cacheable(cacheNames = {SECRET_KEY})
public JwtToken findTop() {
return repository.findFirstByOrderByIdDesc();
}
+ @CacheEvict(allEntries = true, cacheNames = { SECRET_KEY })
+ @Scheduled(fixedDelay = 30, timeUnit = TimeUnit.MINUTES)
+ public void cacheEvict() {
+ // spring will call this method to perform cache eviction
+ }
+
}
diff --git a/src/main/resources/db/migration/V1.0.1__update-secret-token.sql b/src/main/resources/db/migration/V1.0.1__update-secret-token.sql
new file mode 100644
index 0000000..b3fd68d
--- /dev/null
+++ b/src/main/resources/db/migration/V1.0.1__update-secret-token.sql
@@ -0,0 +1,4 @@
+-- update the initial value that has invalid characters for new jjwt version
+-- this used only for testing and to guarantee the server will be up and running locally without any issues in local dev
+-- the production value is not and MUST to be managed by flyway migrations
+update jwt_token set secret_key = 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU2VkIHRpbmNpZHVudCBhbnRlIGV0IG1hZ25hIHB1bHZpbmFyIGJpYmVuZHVtLiBEb25lYyBwdWx2aW5hciBkaWFtIGVnZXQgYXJjdSB2dWxwdXRhdGUgcG9zdWVyZS4gRHVpcyBzdXNjaXBpdCBpbiBmZWxpcyBldSB0ZW1wdXMuIERvbmVjIG5vbiBlZmZpY2l0dXIgb3JjaS4gU2VkIGFjIHNvbGxpY2l0dWRpbiBuaXNpLiBOYW0gbmliaCByaXN1cywgZmFjaWxpc2lzIHZpdGFlIGJpYmVuZHVtIHZpdGFlLCBlZmZpY2l0dXIgZXgu';
diff --git a/src/test/java/br/com/itsmemario/ecordel/AbstractIntegrationTest.java b/src/test/java/br/com/itsmemario/ecordel/AbstractIntegrationTest.java
index 6bc2d19..e633657 100644
--- a/src/test/java/br/com/itsmemario/ecordel/AbstractIntegrationTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/AbstractIntegrationTest.java
@@ -17,46 +17,36 @@
package br.com.itsmemario.ecordel;
-import org.springframework.context.ApplicationContextInitializer;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.MapPropertySource;
-import org.springframework.test.context.ContextConfiguration;
+import org.junit.jupiter.api.BeforeAll;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
-import org.testcontainers.lifecycle.Startables;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.stream.Stream;
-
-@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AbstractIntegrationTest {
- static class Initializer implements ApplicationContextInitializer {
-
- static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:12.8");
-
- private static void startContainers() {
- Startables.deepStart(Stream.of(postgres)).join();
- }
-
- private static Map createConnectionConfiguration() {
- Map map = new HashMap<>();
- map.put("spring.datasource.url", postgres.getJdbcUrl());
- map.put("spring.datasource.username", postgres.getUsername());
- map.put("spring.datasource.password", postgres.getPassword());
- return map;
- }
-
- @Override
- public void initialize(ConfigurableApplicationContext applicationContext) {
- startContainers();
- ConfigurableEnvironment environment = applicationContext.getEnvironment();
- MapPropertySource testcontainers = new MapPropertySource(
- "testcontainers",
- createConnectionConfiguration()
- );
- environment.getPropertySources().addFirst(testcontainers);
- }
+ static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:12.8").withReuse(true);
+
+ @LocalServerPort
+ protected int port;
+
+ @Autowired
+ protected TestRestTemplate restTemplate;
+
+ @BeforeAll
+ static void beforeAll() {
+ postgres.start();
}
+
+ @DynamicPropertySource
+ static void configureProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
+ registry.add("spring.datasource.username", postgres::getUsername);
+ registry.add("spring.datasource.password", postgres::getPassword);
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/br/com/itsmemario/ecordel/EcordelApplicationTests.java b/src/test/java/br/com/itsmemario/ecordel/EcordelApplicationTests.java
index bf61f7b..ec27538 100644
--- a/src/test/java/br/com/itsmemario/ecordel/EcordelApplicationTests.java
+++ b/src/test/java/br/com/itsmemario/ecordel/EcordelApplicationTests.java
@@ -19,22 +19,17 @@
import br.com.itsmemario.ecordel.cordel.CordelService;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
-public class EcordelApplicationTests extends AbstractIntegrationTest {
+class EcordelApplicationTests extends AbstractIntegrationTest {
@Autowired
CordelService service;
@Test
- public void contextLoads() {
+ void contextLoads() {
assertThat(service).isNotNull();
}
diff --git a/src/test/java/br/com/itsmemario/ecordel/author/AuthorControllerTest.java b/src/test/java/br/com/itsmemario/ecordel/author/AuthorControllerTest.java
index c9346d6..e327e8d 100644
--- a/src/test/java/br/com/itsmemario/ecordel/author/AuthorControllerTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/author/AuthorControllerTest.java
@@ -23,7 +23,6 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.context.jdbc.Sql;
@@ -34,7 +33,6 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-@SpringBootTest
@AutoConfigureMockMvc
class AuthorControllerTest extends AbstractIntegrationTest {
diff --git a/src/test/java/br/com/itsmemario/ecordel/author/AuthorRepositoryTest.java b/src/test/java/br/com/itsmemario/ecordel/author/AuthorRepositoryTest.java
index 4b14cbe..ac376f9 100644
--- a/src/test/java/br/com/itsmemario/ecordel/author/AuthorRepositoryTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/author/AuthorRepositoryTest.java
@@ -21,14 +21,12 @@
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
@Slf4j
-@SpringBootTest
class AuthorRepositoryTest extends AbstractIntegrationTest {
@Autowired
diff --git a/src/test/java/br/com/itsmemario/ecordel/cordel/CordelControllerTest.java b/src/test/java/br/com/itsmemario/ecordel/cordel/CordelControllerTest.java
index dbe9987..da93cf7 100644
--- a/src/test/java/br/com/itsmemario/ecordel/cordel/CordelControllerTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/cordel/CordelControllerTest.java
@@ -23,9 +23,6 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -34,15 +31,8 @@
import static br.com.itsmemario.ecordel.cordel.CordelUtil.newCordel;
import static org.assertj.core.api.Assertions.assertThat;
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class CordelControllerTest extends AbstractIntegrationTest {
- @LocalServerPort
- private int port;
-
- @Autowired
- private TestRestTemplate restTemplate;
-
@Autowired
CordelRepository cordelRepository;
diff --git a/src/test/java/br/com/itsmemario/ecordel/cordel/CordelRepositoryTest.java b/src/test/java/br/com/itsmemario/ecordel/cordel/CordelRepositoryTest.java
index 43397d5..d55f01e 100644
--- a/src/test/java/br/com/itsmemario/ecordel/cordel/CordelRepositoryTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/cordel/CordelRepositoryTest.java
@@ -3,15 +3,11 @@
import br.com.itsmemario.ecordel.AbstractIntegrationTest;
import br.com.itsmemario.ecordel.author.Author;
import br.com.itsmemario.ecordel.author.AuthorRepository;
-import org.checkerframework.checker.units.qual.A;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
import java.nio.file.Files;
@@ -23,8 +19,6 @@
import static br.com.itsmemario.ecordel.cordel.CordelUtil.newCordel;
import static org.assertj.core.api.Assertions.assertThat;
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
class CordelRepositoryTest extends AbstractIntegrationTest {
private static final Path BIG_FILE = Paths.get("src/test/resources/content.txt");
diff --git a/src/test/java/br/com/itsmemario/ecordel/file/FtpClientsTest.java b/src/test/java/br/com/itsmemario/ecordel/file/FtpClientsTest.java
index 36ac7f8..4a2e1f6 100644
--- a/src/test/java/br/com/itsmemario/ecordel/file/FtpClientsTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/file/FtpClientsTest.java
@@ -46,7 +46,7 @@ public class FtpClientsTest {
static final FakeFtpServer fakeFtpServer = new FakeFtpServer();
@BeforeAll
- public static void setup() throws IOException {
+ public static void setup() {
setUpMockServer();
}
diff --git a/src/test/java/br/com/itsmemario/ecordel/security/AuthenticationControllerTest.java b/src/test/java/br/com/itsmemario/ecordel/security/AuthenticationControllerTest.java
index 2ab910f..5e17f71 100644
--- a/src/test/java/br/com/itsmemario/ecordel/security/AuthenticationControllerTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/security/AuthenticationControllerTest.java
@@ -18,29 +18,23 @@
package br.com.itsmemario.ecordel.security;
import br.com.itsmemario.ecordel.AbstractIntegrationTest;
+import br.com.itsmemario.ecordel.security.jwt.JwtTokenService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import static org.assertj.core.api.Assertions.assertThat;
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class AuthenticationControllerTest extends AbstractIntegrationTest {
- @LocalServerPort
- private int port;
-
@Autowired
- private TestRestTemplate restTemplate;
+ UserRepository repository;
@Autowired
- UserRepository repository;
+ JwtTokenService tokenService;
@AfterEach
void tearDown() {
diff --git a/src/test/java/br/com/itsmemario/ecordel/xilogravura/XilogravuraServiceTest.java b/src/test/java/br/com/itsmemario/ecordel/xilogravura/XilogravuraServiceTest.java
index 2377e11..73893e3 100644
--- a/src/test/java/br/com/itsmemario/ecordel/xilogravura/XilogravuraServiceTest.java
+++ b/src/test/java/br/com/itsmemario/ecordel/xilogravura/XilogravuraServiceTest.java
@@ -4,7 +4,6 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
import org.mockftpserver.fake.FakeFtpServer;
import org.mockftpserver.fake.UserAccount;
import org.mockftpserver.fake.filesystem.DirectoryEntry;
@@ -12,16 +11,10 @@
import org.mockftpserver.fake.filesystem.FileSystem;
import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
public class XilogravuraServiceTest extends AbstractIntegrationTest {
public static final int PORT = 10021;
@@ -34,7 +27,7 @@ public class XilogravuraServiceTest extends AbstractIntegrationTest {
static final FakeFtpServer fakeFtpServer = new FakeFtpServer();
@BeforeAll
- public static void setup() throws IOException {
+ public static void setup() {
setUpMockServer();
}
@@ -49,12 +42,12 @@ private static void setUpMockServer() {
}
@AfterAll
- public static void afterClass() throws Exception {
+ public static void afterClass() {
fakeFtpServer.stop();
}
@Test
- public void createXilogravuraWithFile() {
+ void createXilogravuraWithFile() {
MockMultipartFile file = new MockMultipartFile("file.txt", "content".getBytes());
String xilogravuraUrl = service.createXilogravuraWithFile(file);
diff --git a/src/test/resources/ecordel.postman_collection.json b/src/test/resources/ecordel.postman_collection.json
deleted file mode 100644
index 9b37ac4..0000000
--- a/src/test/resources/ecordel.postman_collection.json
+++ /dev/null
@@ -1,279 +0,0 @@
-{
- "info": {
- "_postman_id": "e5e94a1a-5377-484d-9916-1d99afc58116",
- "name": "ecordel",
- "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
- },
- "item": [
- {
- "name": "cordels",
- "item": [
- {
- "name": "cordels",
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{ecordel_url}}/cordels?size=30&page=0",
- "host": [
- "{{ecordel_url}}"
- ],
- "path": [
- "cordels"
- ],
- "query": [
- {
- "key": "size",
- "value": "30"
- },
- {
- "key": "page",
- "value": "0"
- }
- ]
- }
- },
- "response": [
- {
- "name": "Default",
- "originalRequest": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{url}}/cordels",
- "host": [
- "{{url}}"
- ],
- "path": [
- "cordels"
- ]
- }
- },
- "code": 200,
- "_postman_previewlanguage": null,
- "header": null,
- "cookie": [],
- "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
- }
- ]
- },
- {
- "name": "new cordel",
- "request": {
- "auth": {
- "type": "bearer",
- "bearer": [
- {
- "key": "token",
- "value": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlLWNvcmRlbCIsInN1YiI6IjEiLCJpYXQiOjE1OTgwNDM4NjgsImV4cCI6MTU5ODEzMDI2OH0.X-giV2mOUr0A88cclVMsWEktI5uqV_8gV8YzBLGHb_Y",
- "type": "string"
- }
- ]
- },
- "method": "POST",
- "header": [
- {
- "key": "Content-Type",
- "name": "Content-Type",
- "type": "text",
- "value": "application/json"
- }
- ],
- "body": {
- "mode": "raw",
- "raw": "{\n\t\"author\": {\"id\": 1},\n \"title\": \"Some new cordel\",\n \"xilogravura\": \"https://i.pinimg.com/originals/25/9d/47/259d47304bf26a4678cb039b8d8ce7f9.jpg\",\n \"description\": \"Cordel descrition\",\n \"content\":\"asdfas asdfasdf asd fasdf çasdfasd fasdfa sdlkfa sdfaklsd faksdl faklsdfalksdfasd\"\n}"
- },
- "url": {
- "raw": "{{ecordel_url}}/cordels",
- "host": [
- "{{ecordel_url}}"
- ],
- "path": [
- "cordels"
- ]
- }
- },
- "response": [
- {
- "name": "Default",
- "originalRequest": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{url}}/cordels",
- "host": [
- "{{url}}"
- ],
- "path": [
- "cordels"
- ]
- }
- },
- "code": 200,
- "_postman_previewlanguage": null,
- "header": null,
- "cookie": [],
- "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
- }
- ]
- }
- ]
- },
- {
- "name": "authors",
- "item": [
- {
- "name": "new author",
- "request": {
- "auth": {
- "type": "bearer",
- "bearer": [
- {
- "key": "token",
- "value": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlLWNvcmRlbCIsInN1YiI6IjEiLCJpYXQiOjE1OTgwNDQ0ODAsImV4cCI6MTU5ODEzMDg4MH0.ugCv2Z3QW8eE7kLtkz6xr7EuNJhCHZ2o0kigw7Dc5kU",
- "type": "string"
- }
- ]
- },
- "method": "POST",
- "header": [
- {
- "key": "Content-Type",
- "name": "Content-Type",
- "type": "text",
- "value": "application/json"
- }
- ],
- "body": {
- "mode": "raw",
- "raw": "{\n\t\"name\": \"Author Test\",\n \"about\": \"About author test\",\n \"email\": \"author.test@ecordel.com\"\n}"
- },
- "url": {
- "raw": "{{ecordel_url}}/authors",
- "host": [
- "{{ecordel_url}}"
- ],
- "path": [
- "authors"
- ]
- }
- },
- "response": [
- {
- "name": "Default",
- "originalRequest": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{url}}/cordels",
- "host": [
- "{{url}}"
- ],
- "path": [
- "cordels"
- ]
- }
- },
- "code": 200,
- "_postman_previewlanguage": null,
- "header": null,
- "cookie": [],
- "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
- }
- ]
- },
- {
- "name": "authors",
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{ecordel_url}}/authors",
- "host": [
- "{{ecordel_url}}"
- ],
- "path": [
- "authors"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "auth",
- "request": {
- "method": "POST",
- "header": [
- {
- "key": "Content-Type",
- "name": "Content-Type",
- "type": "text",
- "value": "application/json"
- }
- ],
- "body": {
- "mode": "raw",
- "raw": "{\n\t\"username\":\"admin\",\n\t\"password\":\"admin\"\n}"
- },
- "url": {
- "raw": "{{ecordel_url}}/auth",
- "host": [
- "{{ecordel_url}}"
- ],
- "path": [
- "auth"
- ]
- }
- },
- "response": [
- {
- "name": "Default",
- "originalRequest": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": ""
- },
- "url": {
- "raw": "{{url}}/cordels",
- "host": [
- "{{url}}"
- ],
- "path": [
- "cordels"
- ]
- }
- },
- "code": 200,
- "_postman_previewlanguage": null,
- "header": null,
- "cookie": [],
- "body": "[\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 4.3\n },\n {\n xilogravura : 'https://img.elo7.com.br/product/original/1EF2F6C/xilogravura-carro-de-boi-xilogravura.jpg',\n text: 'loren ipson dolor',\n author: 'Mário Focking Santos',\n title: 'My first e-cordel',\n rating: 3\n }\n ]"
- }
- ]
- }
- ]
-}
\ No newline at end of file