diff --git a/pom.xml b/pom.xml
index 6e61d8e..9b710b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,11 @@
spring-boot-starter-validation-test
test
+
+ org.mapstruct
+ mapstruct
+ 1.6.3
+
org.springframework.boot
spring-boot-starter-webmvc-test
@@ -109,6 +114,11 @@
org.projectlombok
lombok
+
+ org.mapstruct
+ mapstruct-processor
+ 1.5.5.Final
+
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/in/controllers/IdentityController.java b/src/main/java/dev/idinaldo/auth_api/adapters/in/controllers/IdentityController.java
index b86d396..c1798bd 100644
--- a/src/main/java/dev/idinaldo/auth_api/adapters/in/controllers/IdentityController.java
+++ b/src/main/java/dev/idinaldo/auth_api/adapters/in/controllers/IdentityController.java
@@ -1,10 +1,11 @@
package dev.idinaldo.auth_api.adapters.in.controllers;
-import dev.idinaldo.auth_api.adapters.in.dtos.ClientIdentityRegisterDTO;
+import dev.idinaldo.auth_api.adapters.in.dtos.IdentityRequestDTO;
import dev.idinaldo.auth_api.application.services.IdentityService;
import dev.idinaldo.auth_api.domain.models.Identity;
-import dev.idinaldo.auth_api.infrastructure.mappers.IdentityMapper;
+import dev.idinaldo.auth_api.infrastructure.mappers.IdentityMapperFacade;
import jakarta.validation.Valid;
+import org.apache.coyote.BadRequestException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
@@ -20,17 +21,22 @@
public class IdentityController {
private final IdentityService identityService;
- private final IdentityMapper identityMapper;
+ private final IdentityMapperFacade identityMapper;
- public IdentityController(IdentityService identityService, IdentityMapper identityMapper) {
+ public IdentityController(IdentityService identityService, IdentityMapperFacade identityMapper) {
this.identityService = identityService;
this.identityMapper = identityMapper;
}
@PostMapping("/register")
- public ResponseEntity registerClient(@RequestBody @Valid ClientIdentityRegisterDTO identityRegisterDTO) {
- Identity identity = this.identityMapper.registerDtoToDomain(identityRegisterDTO);
+ public ResponseEntity registerClient(@RequestBody @Valid IdentityRequestDTO identityRegisterDTO) {
+ Identity identity = this.identityMapper.requestDtoToDomain(identityRegisterDTO);
UUID id = this.identityService.registerClient(identity);
return ResponseEntity.status(HttpStatus.CREATED).body("Credentials registered successfully with ID: " + id);
}
+
+ @PostMapping("/signin")
+ public ResponseEntity signIn(@RequestBody @Valid IdentityRequestDTO identityRequestDTO) throws BadRequestException {
+ return ResponseEntity.ok(this.identityService.signIn(identityRequestDTO));
+ }
}
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/ClientIdentityRegisterDTO.java b/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/ClientIdentityRegisterDTO.java
deleted file mode 100644
index 98d33fa..0000000
--- a/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/ClientIdentityRegisterDTO.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package dev.idinaldo.auth_api.adapters.in.dtos;
-
-import dev.idinaldo.auth_api.domain.valueObject.Username;
-
-public record ClientIdentityRegisterDTO(Username username, String password) {
-}
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/IdentityRequestDTO.java b/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/IdentityRequestDTO.java
new file mode 100644
index 0000000..2ad87df
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/adapters/in/dtos/IdentityRequestDTO.java
@@ -0,0 +1,25 @@
+package dev.idinaldo.auth_api.adapters.in.dtos;
+
+
+import dev.idinaldo.auth_api.infrastructure.exceptions.InvalidUsernameException;
+import dev.idinaldo.auth_api.infrastructure.exceptions.WeakPasswordException;
+
+public record IdentityRequestDTO(String username, String password) {
+
+ public IdentityRequestDTO(String username, String password) {
+ if (this.isUsernameValid(username)) {
+ if (this.isPasswordValid(password)) {
+ this.username = username;
+ this.password = password;
+ } else throw new WeakPasswordException();
+ } else throw new InvalidUsernameException();
+ }
+
+ public boolean isUsernameValid(String username) {
+ return true;
+ }
+
+ public boolean isPasswordValid(String password) {
+ return true;
+ }
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/out/JwtGeneratorImpl.java b/src/main/java/dev/idinaldo/auth_api/adapters/out/JwtGeneratorImpl.java
new file mode 100644
index 0000000..f358dc4
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/adapters/out/JwtGeneratorImpl.java
@@ -0,0 +1,14 @@
+package dev.idinaldo.auth_api.adapters.out;
+
+import dev.idinaldo.auth_api.domain.models.Identity;
+import dev.idinaldo.auth_api.ports.JwtGenerator;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JwtGeneratorImpl implements JwtGenerator {
+
+ @Override
+ public String generateToken(Identity identity) {
+ return "token";
+ }
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityJpaRepository.java b/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityJpaRepository.java
index 0318ece..0bd1ab5 100644
--- a/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityJpaRepository.java
+++ b/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityJpaRepository.java
@@ -1,11 +1,14 @@
package dev.idinaldo.auth_api.adapters.out.persistence;
+import dev.idinaldo.auth_api.domain.models.Identity;
import dev.idinaldo.auth_api.infrastructure.entities.JpaIdentity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
+import java.util.Optional;
import java.util.UUID;
@Repository
public interface IdentityJpaRepository extends JpaRepository {
+ Optional findByUsername(String username);
}
diff --git a/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityRepositoryImpl.java b/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityRepositoryImpl.java
index 0e1038a..1a4e316 100644
--- a/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityRepositoryImpl.java
+++ b/src/main/java/dev/idinaldo/auth_api/adapters/out/persistence/IdentityRepositoryImpl.java
@@ -2,19 +2,22 @@
import dev.idinaldo.auth_api.domain.models.Identity;
import dev.idinaldo.auth_api.infrastructure.entities.JpaIdentity;
-import dev.idinaldo.auth_api.infrastructure.mappers.IdentityMapper;
+import dev.idinaldo.auth_api.infrastructure.mappers.IdentityMapperFacade;
import dev.idinaldo.auth_api.ports.IdentityRepository;
+import org.apache.coyote.BadRequestException;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
+import java.util.Optional;
import java.util.UUID;
@Component
public class IdentityRepositoryImpl implements IdentityRepository {
private final IdentityJpaRepository identityJpaRepository;
- private final IdentityMapper identityMapper;
+ private final IdentityMapperFacade identityMapper;
- public IdentityRepositoryImpl(IdentityJpaRepository identityJpaRepository, IdentityMapper identityMapper) {
+ public IdentityRepositoryImpl(IdentityJpaRepository identityJpaRepository, IdentityMapperFacade identityMapper) {
this.identityJpaRepository = identityJpaRepository;
this.identityMapper = identityMapper;
}
@@ -24,4 +27,10 @@ public UUID save(Identity identity) {
JpaIdentity jpaIdentity = this.identityMapper.domainToEntity(identity);
return this.identityJpaRepository.save(jpaIdentity).getId();
}
+
+ @Override
+ public Identity findByUsername(String username) throws BadRequestException {
+ JpaIdentity jpaIdentity = this.identityJpaRepository.findByUsername(username).orElseThrow(BadRequestException::new);
+ return this.identityMapper.entityToDomain(jpaIdentity);
+ }
}
diff --git a/src/main/java/dev/idinaldo/auth_api/application/services/IdentityService.java b/src/main/java/dev/idinaldo/auth_api/application/services/IdentityService.java
index 437ee7d..d770dc3 100644
--- a/src/main/java/dev/idinaldo/auth_api/application/services/IdentityService.java
+++ b/src/main/java/dev/idinaldo/auth_api/application/services/IdentityService.java
@@ -1,24 +1,44 @@
package dev.idinaldo.auth_api.application.services;
-import dev.idinaldo.auth_api.adapters.in.dtos.ClientIdentityRegisterDTO;
+import dev.idinaldo.auth_api.adapters.in.dtos.IdentityRequestDTO;
import dev.idinaldo.auth_api.application.usecases.ClientRegisterUseCase;
+import dev.idinaldo.auth_api.application.usecases.SignInUseCase;
import dev.idinaldo.auth_api.domain.models.Identity;
import dev.idinaldo.auth_api.ports.IdentityRepository;
+import dev.idinaldo.auth_api.ports.JwtGenerator;
+import org.apache.coyote.BadRequestException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
-public class IdentityService implements ClientRegisterUseCase {
+public class IdentityService implements ClientRegisterUseCase, SignInUseCase {
private final IdentityRepository identityRepository;
+ private final JwtGenerator jwtGenerator;
+ private final PasswordEncoder passwordEncoder;
+ private final String SIGN_IN_ERROR_MESSAGE = "Please verify your request.";
+ private final Logger logger = LoggerFactory.getLogger(IdentityService.class);
- public IdentityService(IdentityRepository identityRepository) {
+ public IdentityService(IdentityRepository identityRepository, JwtGenerator jwtGenerator, PasswordEncoder passwordEncoder) {
this.identityRepository = identityRepository;
+ this.jwtGenerator = jwtGenerator;
+ this.passwordEncoder = passwordEncoder;
}
@Override
public UUID registerClient(Identity identity) {
return this.identityRepository.save(identity);
}
+
+ @Override
+ public String signIn(IdentityRequestDTO identityRequestDTO) throws BadRequestException {
+ Identity persistedIdentity = identityRepository.findByUsername(identityRequestDTO.username());
+ if (passwordEncoder.matches(identityRequestDTO.password(), persistedIdentity.getPasswordHash())) {
+ return this.jwtGenerator.generateToken(persistedIdentity);
+ } else throw new BadRequestException(SIGN_IN_ERROR_MESSAGE);
+ }
}
diff --git a/src/main/java/dev/idinaldo/auth_api/application/usecases/ClientRegisterUseCase.java b/src/main/java/dev/idinaldo/auth_api/application/usecases/ClientRegisterUseCase.java
index c6d3a09..c926359 100644
--- a/src/main/java/dev/idinaldo/auth_api/application/usecases/ClientRegisterUseCase.java
+++ b/src/main/java/dev/idinaldo/auth_api/application/usecases/ClientRegisterUseCase.java
@@ -1,6 +1,5 @@
package dev.idinaldo.auth_api.application.usecases;
-import dev.idinaldo.auth_api.adapters.in.dtos.ClientIdentityRegisterDTO;
import dev.idinaldo.auth_api.domain.models.Identity;
import java.util.UUID;
diff --git a/src/main/java/dev/idinaldo/auth_api/application/usecases/SignInUseCase.java b/src/main/java/dev/idinaldo/auth_api/application/usecases/SignInUseCase.java
new file mode 100644
index 0000000..3dd774a
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/application/usecases/SignInUseCase.java
@@ -0,0 +1,8 @@
+package dev.idinaldo.auth_api.application.usecases;
+
+import dev.idinaldo.auth_api.adapters.in.dtos.IdentityRequestDTO;
+import org.apache.coyote.BadRequestException;
+
+public interface SignInUseCase {
+ String signIn(IdentityRequestDTO identityRequestDTO) throws BadRequestException;
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/domain/models/Identity.java b/src/main/java/dev/idinaldo/auth_api/domain/models/Identity.java
index 6d16389..3960f7b 100644
--- a/src/main/java/dev/idinaldo/auth_api/domain/models/Identity.java
+++ b/src/main/java/dev/idinaldo/auth_api/domain/models/Identity.java
@@ -1,22 +1,20 @@
package dev.idinaldo.auth_api.domain.models;
-import dev.idinaldo.auth_api.domain.valueObject.Username;
-
import java.util.UUID;
public class Identity {
private UUID id;
- private Username username;
+ private String username;
private String passwordHash;
- public Identity(UUID id, Username username, String passwordHash) {
+ public Identity(UUID id, String username, String passwordHash) {
this.id = id;
this.username = username;
this.passwordHash = passwordHash;
}
- public Identity(Username username, String passwordHash) {
+ public Identity(String username, String passwordHash) {
this.username = username;
this.passwordHash = passwordHash;
}
@@ -32,11 +30,11 @@ public void setId(UUID id) {
this.id = id;
}
- public Username getUsername() {
+ public String getUsername() {
return username;
}
- public void setUsername(Username username) {
+ public void setUsername(String username) {
this.username = username;
}
diff --git a/src/main/java/dev/idinaldo/auth_api/domain/valueObject/Username.java b/src/main/java/dev/idinaldo/auth_api/domain/valueObject/Username.java
index ac5138f..6708426 100644
--- a/src/main/java/dev/idinaldo/auth_api/domain/valueObject/Username.java
+++ b/src/main/java/dev/idinaldo/auth_api/domain/valueObject/Username.java
@@ -4,25 +4,24 @@
import com.fasterxml.jackson.annotation.JsonValue;
import dev.idinaldo.auth_api.infrastructure.exceptions.InvalidUsernameException;
-public record Username(String username) {
+public record Username(String value) {
+
@JsonCreator
- public Username(String username) {
- if (this.isValid(username)) {
- this.username = username;
+ public Username(String value) {
+ if (this.isValid(value)) {
+ this.value = value;
} else {
throw new InvalidUsernameException();
}
}
private boolean isValid(String value) {
- System.out.println("[" + value + "]");
- System.out.println(value.matches("\\w{6,16}"));
return value.matches("\\w{6,16}");
}
@JsonValue
public String getValue() {
- return this.username;
+ return this.value;
}
}
diff --git a/src/main/java/dev/idinaldo/auth_api/infrastructure/exceptions/WeakPasswordException.java b/src/main/java/dev/idinaldo/auth_api/infrastructure/exceptions/WeakPasswordException.java
new file mode 100644
index 0000000..b885fbd
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/infrastructure/exceptions/WeakPasswordException.java
@@ -0,0 +1,12 @@
+package dev.idinaldo.auth_api.infrastructure.exceptions;
+
+public class WeakPasswordException extends RuntimeException {
+
+ public WeakPasswordException() {
+ super("Please make sure your password is at least 6-characters long and contains letters, numbers and special symbols.");
+ }
+
+ public WeakPasswordException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapper.java b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapper.java
index cba87c0..db1fec7 100644
--- a/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapper.java
+++ b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapper.java
@@ -1,8 +1,7 @@
package dev.idinaldo.auth_api.infrastructure.mappers;
-import dev.idinaldo.auth_api.adapters.in.dtos.ClientIdentityRegisterDTO;
+import dev.idinaldo.auth_api.adapters.in.dtos.IdentityRequestDTO;
import dev.idinaldo.auth_api.domain.models.Identity;
-import dev.idinaldo.auth_api.infrastructure.entities.JpaIdentity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@@ -15,21 +14,11 @@ public IdentityMapper(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
- public JpaIdentity domainToEntity(Identity identity) {
- JpaIdentity jpaIdentity = new JpaIdentity();
-
- jpaIdentity.setUsername(identity.getUsername().getValue());
- jpaIdentity.setPasswordHash(identity.getPasswordHash());
-
- return jpaIdentity;
+ public Identity requestDtoToDomain(IdentityRequestDTO identityRegisterDTO) {
+ return new Identity(
+ identityRegisterDTO.username(),
+ this.passwordEncoder.encode(identityRegisterDTO.password())
+ );
}
- public Identity registerDtoToDomain(ClientIdentityRegisterDTO identityRegisterDTO) {
- Identity identity = new Identity();
-
- identity.setUsername(identityRegisterDTO.username());
- identity.setPasswordHash(passwordEncoder.encode(identityRegisterDTO.password()));
-
- return identity;
- }
}
diff --git a/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapperFacade.java b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapperFacade.java
new file mode 100644
index 0000000..eb9474a
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/IdentityMapperFacade.java
@@ -0,0 +1,31 @@
+package dev.idinaldo.auth_api.infrastructure.mappers;
+
+import dev.idinaldo.auth_api.adapters.in.dtos.IdentityRequestDTO;
+import dev.idinaldo.auth_api.domain.models.Identity;
+import dev.idinaldo.auth_api.infrastructure.entities.JpaIdentity;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IdentityMapperFacade {
+
+ private final SimpleIdentityMapper simpleMapper;
+ private final IdentityMapper complexMapper;
+
+ public IdentityMapperFacade(SimpleIdentityMapper simpleMapper, IdentityMapper complexMapper) {
+ this.simpleMapper = simpleMapper;
+ this.complexMapper = complexMapper;
+ }
+
+ public Identity requestDtoToDomain(IdentityRequestDTO requestDTO) {
+ return this.complexMapper.requestDtoToDomain(requestDTO);
+ }
+
+ public Identity entityToDomain(JpaIdentity jpaIdentity) {
+ return this.simpleMapper.entityToDomain(jpaIdentity);
+ }
+
+ public JpaIdentity domainToEntity(Identity identity) {
+ return this.simpleMapper.domainToEntity(identity);
+ }
+
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/SimpleIdentityMapper.java b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/SimpleIdentityMapper.java
new file mode 100644
index 0000000..1232c20
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/infrastructure/mappers/SimpleIdentityMapper.java
@@ -0,0 +1,12 @@
+package dev.idinaldo.auth_api.infrastructure.mappers;
+
+import dev.idinaldo.auth_api.domain.models.Identity;
+import dev.idinaldo.auth_api.infrastructure.entities.JpaIdentity;
+import org.mapstruct.Mapper;
+
+@Mapper(componentModel = "spring")
+public interface SimpleIdentityMapper {
+
+ Identity entityToDomain(JpaIdentity jpaIdentity);
+ JpaIdentity domainToEntity(Identity identity);
+}
diff --git a/src/main/java/dev/idinaldo/auth_api/ports/IdentityRepository.java b/src/main/java/dev/idinaldo/auth_api/ports/IdentityRepository.java
index 1b0c375..6552cdd 100644
--- a/src/main/java/dev/idinaldo/auth_api/ports/IdentityRepository.java
+++ b/src/main/java/dev/idinaldo/auth_api/ports/IdentityRepository.java
@@ -1,11 +1,14 @@
package dev.idinaldo.auth_api.ports;
import dev.idinaldo.auth_api.domain.models.Identity;
+import org.apache.coyote.BadRequestException;
import org.springframework.stereotype.Repository;
+import java.util.Optional;
import java.util.UUID;
@Repository
public interface IdentityRepository {
UUID save(Identity identity);
+ Identity findByUsername(String username) throws BadRequestException;
}
diff --git a/src/main/java/dev/idinaldo/auth_api/ports/JwtGenerator.java b/src/main/java/dev/idinaldo/auth_api/ports/JwtGenerator.java
new file mode 100644
index 0000000..74bc28f
--- /dev/null
+++ b/src/main/java/dev/idinaldo/auth_api/ports/JwtGenerator.java
@@ -0,0 +1,9 @@
+package dev.idinaldo.auth_api.ports;
+
+import dev.idinaldo.auth_api.domain.models.Identity;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface JwtGenerator {
+ String generateToken(Identity identity);
+}