diff --git a/.run/Run Cucumber Tests.run.xml b/.run/Run Cucumber Tests.run.xml
new file mode 100644
index 00000000..c7ced12e
--- /dev/null
+++ b/.run/Run Cucumber Tests.run.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java
index f68d0571..44529719 100644
--- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java
+++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java
@@ -1,21 +1,53 @@
package de.filefighter.rest.configuration;
import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository;
+import de.filefighter.rest.domain.token.business.AccessTokenBusinessService;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import de.filefighter.rest.domain.user.data.persistance.UserEntity;
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
+import java.time.Instant;
+
@Configuration
public class PrepareDataBase {
+ @Value("${server.port}")
+ int serverPort;
+
private static final Logger LOG = LoggerFactory.getLogger(PrepareDataBase.class);
+ @Bean
+ @Profile({"dev", "prod"})
+ CommandLineRunner veryImportantFileFighterStartScript() {
+ return args -> {
+ System.out.println();
+ System.out.println("-------------------------------< REST API >-------------------------------");
+ System.out.println();
+ System.out.println(" _____ _ _ _____ _ _ _ ");
+ System.out.println(" | ___| (_) | | ___ | ___| (_) __ _ | |__ | |_ ___ _ __ ");
+ System.out.println(" | |_ | | | | / _ \\ | |_ | | / _ | | '_ \\ | __| / _ \\ | '__|");
+ System.out.println(" | _| | | | | | __/ | _| | | | (_| | | | | | | |_ | __/ | | ");
+ System.out.println(" |_| |_| |_| \\___| |_| |_| \\__, | |_| |_| \\__| \\___| |_| ");
+ System.out.println(" |___/ ");
+ System.out.println(" Version 0.2 Last updated at 03.11.20 ");
+ System.out.println(" Developed by Gimleux, Valentin, Open-Schnick. ");
+ System.out.println(" Development Blog: https://filefighter.github.io ");
+ System.out.println(" The code can be found at: https://www.github.com/filefighter ");
+ System.out.println(" Running on http://localhost:" + serverPort);
+ System.out.println();
+ System.out.println("-------------------------------< REST API >-------------------------------");
+ System.out.println();
+ };
+ }
+
@Bean
CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
@@ -32,7 +64,7 @@ CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemReposit
@Bean
@Profile("prod")
- CommandLineRunner initUserDataBase(UserRepository repository) {
+ CommandLineRunner initUserDataBaseProd(UserRepository repository) {
//Note: when the admin user changes his/her password, a new refreshToken will be created.
return args -> {
@@ -42,9 +74,57 @@ CommandLineRunner initUserDataBase(UserRepository repository) {
.username("admin")
.password("admin")
.refreshToken("refreshToken1234")
- .roleIds(new long[]{0, 1})
+ .groupIds(new long[]{0, 1})
.build()));
- LOG.info("Loading Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
+ LOG.info("Inserting Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
+ };
+ }
+
+ @Bean
+ @Profile("dev")
+ CommandLineRunner initUserDataBaseDev(UserRepository repository) {
+
+ return args -> {
+ LOG.info("Preloading default users: " +
+ repository.save(UserEntity
+ .builder()
+ .userId(0)
+ .username("user")
+ .password("1234")
+ .refreshToken("rft1234")
+ .groupIds(new long[]{0})
+ .build()) +
+ repository.save(UserEntity
+ .builder()
+ .userId(1)
+ .username("user1")
+ .password("12345")
+ .refreshToken("rft")
+ .groupIds(new long[]{-1})
+ .build()));
+ LOG.info("Inserting Users" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
+ };
+ }
+
+ @Bean
+ @Profile("dev")
+ CommandLineRunner initAccessTokenDataBaseDev(AccessTokenRepository repository) {
+
+ return args -> {
+ LOG.info("Preloading default tokens: " +
+ repository.save(AccessTokenEntity
+ .builder()
+ .userId(0)
+ .value("token")
+ .validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
+ .build()) +
+ repository.save(AccessTokenEntity
+ .builder()
+ .userId(1)
+ .value("token1234")
+ .validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
+ .build()));
+ LOG.info("Inserting token" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
};
}
}
\ No newline at end of file
diff --git a/src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java b/src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java
new file mode 100644
index 00000000..06605dbb
--- /dev/null
+++ b/src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java
@@ -0,0 +1,6 @@
+package de.filefighter.rest.domain.common;
+
+public interface DtoServiceInterface {
+ D createDto(E entity);
+ E findEntity(D dto);
+}
diff --git a/src/main/java/de/filefighter/rest/domain/common/Utils.java b/src/main/java/de/filefighter/rest/domain/common/Utils.java
new file mode 100644
index 00000000..4e81e622
--- /dev/null
+++ b/src/main/java/de/filefighter/rest/domain/common/Utils.java
@@ -0,0 +1,8 @@
+package de.filefighter.rest.domain.common;
+
+public class Utils {
+
+ public static boolean stringIsValid(String s){
+ return !(null == s || s.isEmpty() || s.isBlank());
+ }
+}
diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java
index 77bf6390..1e7a6d24 100644
--- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java
+++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java
@@ -5,7 +5,7 @@
import lombok.Data;
@Data
-@Builder(builderMethodName = "create")
+@Builder
public class FileSystemItemUpdate {
private String name;
private FileSystemType type;
diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java
index f144c5c2..153821da 100644
--- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java
+++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java
@@ -4,7 +4,7 @@
import lombok.Getter;
@Getter
-@Builder(buildMethodName = "create")
+@Builder
public class FolderContents {
private final Folder[] folders;
private final File[] files;
diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistance/FileSystemEntity.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistance/FileSystemEntity.java
index 925edc29..febd46a2 100644
--- a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistance/FileSystemEntity.java
+++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistance/FileSystemEntity.java
@@ -7,7 +7,7 @@
@Data
@Document(collection = "file")
-@Builder(buildMethodName = "create")
+@Builder
public class FileSystemEntity {
@MongoId private String _id;
private long id;
diff --git a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java
index 86721846..314bc04e 100644
--- a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java
+++ b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java
@@ -22,7 +22,7 @@ public SystemHealth getCurrentSystemHealthInfo(){
return SystemHealth.builder()
.uptimeInSeconds(currentEpoch - serverStartedAt)
.userCount(userBusinessService.getUserCount())
- .create();
+ .build();
}
public long getCurrentEpochSeconds(){
diff --git a/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java b/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java
index ceff106c..e98ada97 100644
--- a/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java
+++ b/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java
@@ -8,7 +8,7 @@
*/
@Getter
-@Builder(buildMethodName = "create")
+@Builder
public class SystemHealth {
private final long uptimeInSeconds;
private final long userCount;
diff --git a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java
index 18b9fc61..88135d5e 100644
--- a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java
+++ b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java
@@ -1,8 +1,80 @@
package de.filefighter.rest.domain.token.business;
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
+import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
import org.springframework.stereotype.Service;
+import java.time.Instant;
+import java.util.UUID;
+
+import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX;
+import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX;
+import static de.filefighter.rest.domain.common.Utils.stringIsValid;
+
@Service
public class AccessTokenBusinessService {
+
+ private final AccessTokenRepository accessTokenRepository;
+ private final AccessTokenDtoService accessTokenDtoService;
+
public static final long ACCESS_TOKEN_DURATION_IN_SECONDS = 3600L;
+ public static final long ACCESS_TOKEN_SAFETY_MARGIN = 5L;
+
+ public AccessTokenBusinessService(AccessTokenRepository accessTokenRepository, AccessTokenDtoService accessTokenDtoService) {
+ this.accessTokenRepository = accessTokenRepository;
+ this.accessTokenDtoService = accessTokenDtoService;
+ }
+
+ public AccessToken getValidAccessTokenForUser(User user) {
+ AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserId(user.getId());
+ long currentTimeSeconds = Instant.now().getEpochSecond();
+
+ if (null == accessTokenEntity) {
+ accessTokenEntity = AccessTokenEntity
+ .builder()
+ .validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
+ .value(this.generateRandomTokenValue())
+ .userId(user.getId())
+ .build();
+ accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
+ } else {
+ if (currentTimeSeconds + ACCESS_TOKEN_SAFETY_MARGIN > accessTokenEntity.getValidUntil()) {
+ accessTokenRepository.delete(accessTokenEntity);
+ accessTokenEntity = AccessTokenEntity
+ .builder()
+ .validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
+ .value(this.generateRandomTokenValue())
+ .userId(user.getId())
+ .build();
+ accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
+ }
+ }
+
+ return accessTokenDtoService.createDto(accessTokenEntity);
+ }
+
+ public AccessToken findAccessTokenByValueAndUserId(String accessTokenValue, long userId) {
+ if (!stringIsValid(accessTokenValue))
+ throw new IllegalArgumentException("Value of AccessToken was not valid.");
+
+ AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(userId, accessTokenValue);
+ if (null == accessTokenEntity)
+ throw new UserNotAuthenticatedException(userId);
+
+ return accessTokenDtoService.createDto(accessTokenEntity);
+ }
+
+ public String generateRandomTokenValue() {
+ return UUID.randomUUID().toString();
+ }
+
+ public String checkBearerHeader(String accessTokenValue) {
+ if (!accessTokenValue.matches("^" + AUTHORIZATION_BEARER_PREFIX + "[^\\s](.*)$"))
+ throw new UserNotAuthenticatedException("Header does not contain '" + AUTHORIZATION_BEARER_PREFIX + "', or format is invalid.");
+ return accessTokenValue.split(AUTHORIZATION_BEARER_PREFIX)[1];
+ }
}
diff --git a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDtoService.java b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDtoService.java
new file mode 100644
index 00000000..f889297d
--- /dev/null
+++ b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDtoService.java
@@ -0,0 +1,37 @@
+package de.filefighter.rest.domain.token.business;
+
+import de.filefighter.rest.domain.common.DtoServiceInterface;
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
+import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AccessTokenDtoService implements DtoServiceInterface {
+
+ private final AccessTokenRepository accessTokenRepository;
+
+ public AccessTokenDtoService(AccessTokenRepository accessTokenRepository) {
+ this.accessTokenRepository = accessTokenRepository;
+ }
+
+ @Override
+ public AccessToken createDto(AccessTokenEntity entity) {
+ return AccessToken
+ .builder()
+ .token(entity.getValue())
+ .userId(entity.getUserId())
+ .validUntil(entity.getValidUntil())
+ .build();
+ }
+
+ @Override
+ public AccessTokenEntity findEntity(AccessToken dto) {
+ AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(dto.getUserId(), dto.getToken());
+ if (null == accessTokenEntity)
+ throw new AccessTokenNotFoundException("AccessTokenEntity does not exist for AccessToken: "+ dto);
+
+ return accessTokenEntity;
+ }
+}
diff --git a/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenEntity.java b/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenEntity.java
index 172ca570..3c7dea5a 100644
--- a/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenEntity.java
+++ b/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenEntity.java
@@ -15,5 +15,5 @@ public class AccessTokenEntity {
private String value;
private long userId;
private long validUntil;
-
+
}
\ No newline at end of file
diff --git a/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenRepository.java b/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenRepository.java
index 4bf99bb7..92f49f4f 100644
--- a/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenRepository.java
+++ b/src/main/java/de/filefighter/rest/domain/token/data/persistance/AccessTokenRepository.java
@@ -7,5 +7,5 @@
public interface AccessTokenRepository extends MongoRepository {
AccessTokenEntity findByUserId(long userId);
AccessTokenEntity findByValue(String value);
- void deleteByUserId(long userId);
+ AccessTokenEntity findByUserIdAndValue(long userId, String value);
}
diff --git a/src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundAdvise.java b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java
similarity index 75%
rename from src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundAdvise.java
rename to src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java
index 443253fd..c5e3c583 100644
--- a/src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundAdvise.java
+++ b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java
@@ -11,13 +11,13 @@
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
-public class TokenNotFoundAdvise {
+public class AccessTokenNotFoundAdvise {
@ResponseBody
- @ExceptionHandler(TokenNotFoundException.class)
+ @ExceptionHandler(AccessTokenNotFoundException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- ResponseEntity tokenNotFoundAdvise(TokenNotFoundException ex) {
+ ResponseEntity tokenNotFoundAdvise(AccessTokenNotFoundException ex) {
LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage());
- return new ResponseEntity<>(new ServerResponse("Denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
+ return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
}
}
diff --git a/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java
new file mode 100644
index 00000000..adecc922
--- /dev/null
+++ b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java
@@ -0,0 +1,8 @@
+package de.filefighter.rest.domain.token.exceptions;
+
+public class AccessTokenNotFoundException extends RuntimeException {
+
+ public AccessTokenNotFoundException(String reason) {
+ super(reason);
+ }
+}
diff --git a/src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundException.java b/src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundException.java
deleted file mode 100644
index 3437b430..00000000
--- a/src/main/java/de/filefighter/rest/domain/token/exceptions/TokenNotFoundException.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package de.filefighter.rest.domain.token.exceptions;
-
-public class TokenNotFoundException extends RuntimeException {
-
- public TokenNotFoundException(String reason) {
- super(reason);
- }
-}
diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java
index 7d2851c0..538f84c0 100644
--- a/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java
+++ b/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java
@@ -1,17 +1,113 @@
package de.filefighter.rest.domain.user.business;
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.dto.RefreshToken;
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.data.persistance.UserEntity;
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
+import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
+import de.filefighter.rest.domain.user.exceptions.UserNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.sql.Ref;
+import java.util.Base64;
+import java.util.UUID;
+
+import static de.filefighter.rest.configuration.RestConfiguration.*;
+import static de.filefighter.rest.domain.common.Utils.stringIsValid;
+
@Service
public class UserBusinessService {
+
private final UserRepository userRepository;
+ private final UserDtoService userDtoService;
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserBusinessService.class);
- public UserBusinessService(UserRepository userRepository) {
+ public UserBusinessService(UserRepository userRepository, UserDtoService userDtoService) {
this.userRepository = userRepository;
+ this.userDtoService = userDtoService;
}
- public long getUserCount(){
+ public long getUserCount() {
return userRepository.count();
}
+
+ public User getUserByUsernameAndPassword(String base64encodedUserAndPasswordWithHeaderPrefix) {
+ if (!stringIsValid(base64encodedUserAndPasswordWithHeaderPrefix))
+ throw new UserNotAuthenticatedException("Header was empty.");
+
+ //TODO: maybe filter unsupported characters?
+ if (!base64encodedUserAndPasswordWithHeaderPrefix.matches("^" + AUTHORIZATION_BASIC_PREFIX + "[^\\s](.*)$"))
+ throw new UserNotAuthenticatedException("Header does not contain '" + AUTHORIZATION_BASIC_PREFIX + "', or format is invalid.");
+
+ String[] split = base64encodedUserAndPasswordWithHeaderPrefix.split(AUTHORIZATION_BASIC_PREFIX);
+
+ base64encodedUserAndPasswordWithHeaderPrefix = split[1];
+ String decodedUsernameUndPassword;
+ try {
+ byte[] decodedValue = Base64.getDecoder().decode(base64encodedUserAndPasswordWithHeaderPrefix);
+ decodedUsernameUndPassword = new String(decodedValue, StandardCharsets.UTF_8.toString());
+ } catch (UnsupportedEncodingException | IllegalArgumentException ex) {
+ LOG.warn("Found UnsupportedEncodingException in {}", base64encodedUserAndPasswordWithHeaderPrefix);
+ throw new RuntimeException(ex);
+ }
+
+ split = decodedUsernameUndPassword.strip().split(":");
+
+ if (split.length != 2)
+ throw new UserNotAuthenticatedException("Credentials didnt meet formal requirements.");
+
+ String username = split[0];
+ String password = split[1];
+
+ UserEntity userEntity = userRepository.findByUsernameAndPassword(username, password);
+ if (null == userEntity)
+ throw new UserNotFoundException("No User found with this username and password.");
+
+ return userDtoService.createDto(userEntity);
+ }
+
+ public RefreshToken getRefreshTokenForUser(User user) {
+ UserEntity userEntity = userRepository.findByUserIdAndUsername(user.getId(), user.getUsername());
+ if (null == userEntity)
+ throw new UserNotFoundException();
+
+ String refreshTokenValue = userEntity.getRefreshToken();
+
+ if (!stringIsValid(refreshTokenValue))
+ throw new IllegalStateException("RefreshToken was empty in db.");
+
+ return RefreshToken
+ .builder()
+ .refreshToken(refreshTokenValue)
+ .user(user)
+ .build();
+ }
+
+ public User getUserByRefreshTokenAndUserId(String refreshToken, long userId) {
+ if (!stringIsValid(refreshToken))
+ throw new UserNotAuthenticatedException("RefreshToken was not valid.");
+
+ UserEntity userEntity = userRepository.findByRefreshTokenAndUserId(refreshToken, userId);
+ if (null == userEntity)
+ throw new UserNotFoundException(userId);
+
+ return userDtoService.createDto(userEntity);
+ }
+
+ public User getUserByAccessTokenAndUserId(AccessToken accessToken, long userId) {
+ if (accessToken.getUserId() != userId)
+ throw new UserNotAuthenticatedException(userId);
+
+ UserEntity userEntity = userRepository.findByUserId(userId);
+ if (null == userEntity)
+ throw new UserNotFoundException(userId);
+
+ return userDtoService.createDto(userEntity);
+ }
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java
new file mode 100644
index 00000000..ccbebf39
--- /dev/null
+++ b/src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java
@@ -0,0 +1,40 @@
+package de.filefighter.rest.domain.user.business;
+
+import de.filefighter.rest.domain.common.DtoServiceInterface;
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.data.persistance.UserEntity;
+import de.filefighter.rest.domain.user.data.persistance.UserRepository;
+import de.filefighter.rest.domain.user.exceptions.UserNotFoundException;
+import de.filefighter.rest.domain.user.role.GroupRepository;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserDtoService implements DtoServiceInterface {
+
+ private final GroupRepository groupRepository;
+ private final UserRepository userRepository;
+
+ public UserDtoService(GroupRepository groupRepository, UserRepository userRepository) {
+ this.groupRepository = groupRepository;
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ public User createDto(UserEntity entity) {
+ return User
+ .builder()
+ .id(entity.getUserId())
+ .username(entity.getUsername())
+ .groups(groupRepository.getRolesByIds(entity.getGroupIds()))
+ .build();
+ }
+
+ @Override
+ public UserEntity findEntity(User dto) {
+ UserEntity userEntity = userRepository.findByUserIdAndUsername(dto.getId(), dto.getUsername());
+ if (null == userEntity)
+ throw new UserNotFoundException(dto.getId());
+
+ return userEntity;
+ }
+}
diff --git a/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java b/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java
index b1c5bb80..d70e6bb0 100644
--- a/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java
+++ b/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java
@@ -4,16 +4,16 @@
import lombok.Data;
-@Builder(builderClassName = "UserBuilder", buildMethodName = "create")
@Data
+@Builder
public class User {
private long id;
private String username;
- private Groups[] roles;
+ private Groups[] groups;
public User(long id, String username, Groups... roles) {
this.id = id;
this.username = username;
- this.roles = roles;
+ this.groups = roles;
}
}
\ No newline at end of file
diff --git a/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java b/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java
index e36029c6..af076c41 100644
--- a/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java
+++ b/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java
@@ -4,7 +4,7 @@
import lombok.Data;
@Data
-@Builder(buildMethodName = "create", builderClassName = "UserRegistrationFormBuilder")
+@Builder
public class UserRegisterForm {
private String username;
private String password;
diff --git a/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserEntity.java b/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserEntity.java
index db28695c..a4604180 100644
--- a/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserEntity.java
+++ b/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserEntity.java
@@ -16,7 +16,6 @@ public class UserEntity {
private String username;
private String password;
private String refreshToken; //TODO: add valid_until for refreshToken
- private long[] roleIds;
-
+ private long[] groupIds;
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserRepository.java b/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserRepository.java
index aafc05be..27d51680 100644
--- a/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserRepository.java
+++ b/src/main/java/de/filefighter/rest/domain/user/data/persistance/UserRepository.java
@@ -5,7 +5,8 @@
@Service
public interface UserRepository extends MongoRepository {
- UserEntity findByUserId(long userId);
+ UserEntity findByUserIdAndUsername(long userId, String username);
UserEntity findByUsernameAndPassword(String username, String password);
- UserEntity findByRefreshToken(String refreshToken);
+ UserEntity findByRefreshTokenAndUserId(String refreshToken, long userId);
+ UserEntity findByUserId(long userId);
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserAlreadyExistsAdvise.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserAlreadyExistsAdvise.java
index e5d89cb6..bd9cfbde 100644
--- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserAlreadyExistsAdvise.java
+++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserAlreadyExistsAdvise.java
@@ -17,6 +17,6 @@ public class UserAlreadyExistsAdvise {
ResponseEntity userAlreadyExistsAdvise(UserAlreadyExistsException ex) {
LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage());
- return new ResponseEntity<>(new ServerResponse("Denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
+ return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
}
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedAdvise.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedAdvise.java
index 8f65bb53..3fb11dbb 100644
--- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedAdvise.java
+++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedAdvise.java
@@ -17,6 +17,6 @@ public class UserNotAuthenticatedAdvise {
@ResponseStatus(HttpStatus.UNAUTHORIZED)
ResponseEntity userNotAuthenticatedHandler(UserNotAuthenticatedException ex) {
LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage());
- return new ResponseEntity<>(new ServerResponse("Denied", ex.getMessage()), HttpStatus.UNAUTHORIZED);
+ return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.UNAUTHORIZED);
}
}
\ No newline at end of file
diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java
index 68cc6f85..7b31ae1e 100644
--- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java
+++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java
@@ -5,9 +5,9 @@ public UserNotAuthenticatedException(String reason){
super("User could not be authenticated. "+reason);
}
- public UserNotAuthenticatedException() {
- super("User could not be authenticated.");
- }
+// public UserNotAuthenticatedException() {
+// super("User could not be authenticated.");
+// }
public UserNotAuthenticatedException(long id){
super("User with the id "+id+" could not be authenticated.");
diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundAdvice.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundAdvice.java
index bf255f31..3df30506 100644
--- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundAdvice.java
+++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundAdvice.java
@@ -17,6 +17,6 @@ class UserNotFoundAdvice {
@ResponseStatus(HttpStatus.NOT_FOUND)
ResponseEntity userNotFoundHandler(UserNotFoundException ex) {
LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage());
- return new ResponseEntity<>(new ServerResponse("Denied", ex.getMessage()), HttpStatus.NOT_FOUND);
+ return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.NOT_FOUND);
}
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java
index 463b00d8..9c89d4d8 100644
--- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java
+++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java
@@ -2,6 +2,10 @@
public class UserNotFoundException extends RuntimeException {
+ public UserNotFoundException(){
+ super("User not found.");
+ }
+
public UserNotFoundException(long id) {
super("Could not find user " + id);
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestController.java b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestController.java
index 4b4b1b38..1dc9a1a1 100644
--- a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestController.java
+++ b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestController.java
@@ -49,7 +49,7 @@ public ResponseEntity getAccessTokenAndUserInfoByRefreshTokenAndUse
@PathVariable long userId,
@RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String refreshToken) {
- LOG.info("Requested refreshing for user {} with token {}.", userId, refreshToken);
+ LOG.info("Requested login for user {} with token {}.", userId, refreshToken);
return userRestService.getAccessTokenByRefreshTokenAndUserId(refreshToken, userId);
}
diff --git a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java
index 8771d8e0..d5e2048c 100644
--- a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java
+++ b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java
@@ -1,9 +1,12 @@
package de.filefighter.rest.domain.user.rest;
+import de.filefighter.rest.domain.token.business.AccessTokenBusinessService;
import de.filefighter.rest.domain.token.data.dto.AccessToken;
import de.filefighter.rest.domain.token.data.dto.RefreshToken;
+import de.filefighter.rest.domain.user.business.UserBusinessService;
import de.filefighter.rest.domain.user.data.dto.User;
import de.filefighter.rest.domain.user.data.dto.UserRegisterForm;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -11,19 +14,35 @@
@Service
public class UserRestService implements UserRestServiceInterface {
+ private final UserBusinessService userBusinessService;
+ private final AccessTokenBusinessService accessTokenBusinessService;
+
+ public UserRestService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService) {
+ this.userBusinessService = userBusinessService;
+ this.accessTokenBusinessService = accessTokenBusinessService;
+ }
+
@Override
- public ResponseEntity getUserByAccessTokenAndUserId(String accessToken, long userId) {
- return null;
+ public ResponseEntity getUserByAccessTokenAndUserId(String accessTokenValue, long userId) {
+ String cleanValue = accessTokenBusinessService.checkBearerHeader(accessTokenValue);
+ AccessToken accessToken = accessTokenBusinessService.findAccessTokenByValueAndUserId(cleanValue, userId);
+ User user = userBusinessService.getUserByAccessTokenAndUserId(accessToken, userId);
+ return new ResponseEntity<>(user, HttpStatus.OK);
}
@Override
public ResponseEntity getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword) {
- return null;
+ User user = userBusinessService.getUserByUsernameAndPassword(base64encodedUserAndPassword);
+ RefreshToken refreshToken = userBusinessService.getRefreshTokenForUser(user);
+ return new ResponseEntity<>(refreshToken, HttpStatus.OK);
}
@Override
public ResponseEntity getAccessTokenByRefreshTokenAndUserId(String refreshToken, long userId) {
- return null;
+ String cleanValue = accessTokenBusinessService.checkBearerHeader(refreshToken);
+ User user = userBusinessService.getUserByRefreshTokenAndUserId(cleanValue, userId);
+ AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(user);
+ return new ResponseEntity<>(accessToken, HttpStatus.OK);
}
@Override
diff --git a/src/main/java/de/filefighter/rest/domain/user/role/GroupRepository.java b/src/main/java/de/filefighter/rest/domain/user/role/GroupRepository.java
index 61d87549..557a2e10 100644
--- a/src/main/java/de/filefighter/rest/domain/user/role/GroupRepository.java
+++ b/src/main/java/de/filefighter/rest/domain/user/role/GroupRepository.java
@@ -9,7 +9,7 @@ public class GroupRepository {
//TODO: test this.
public Groups getRoleById(long id) {
for (Groups role : roles) {
- if (role.getRoleId() == id) {
+ if (role.getGroupId() == id) {
return role;
}
}
@@ -17,7 +17,11 @@ public Groups getRoleById(long id) {
}
public Groups[] getRolesByIds(long... ids){
- Groups[] roles = new Groups[ids.length]; //TODO: check this again.
+ Groups[] roles;
+ if(null == ids){
+ return new Groups[0];
+ }
+ roles = new Groups[ids.length];
for (int i = 0; i < ids.length; i++) {
roles[i] = this.getRoleById(ids[i]);
diff --git a/src/main/java/de/filefighter/rest/domain/user/role/Groups.java b/src/main/java/de/filefighter/rest/domain/user/role/Groups.java
index a6ca7f18..616a6dff 100644
--- a/src/main/java/de/filefighter/rest/domain/user/role/Groups.java
+++ b/src/main/java/de/filefighter/rest/domain/user/role/Groups.java
@@ -5,16 +5,16 @@ public enum Groups {
FAMILY(0, "Family"),
ADMIN(1, "Admin");
- private final long roleId;
+ private final long groupId;
private final String displayName;
Groups(long roleId, String displayName) {
- this.roleId = roleId;
+ this.groupId = roleId;
this.displayName = displayName;
}
- public long getRoleId() {
- return roleId;
+ public long getGroupId() {
+ return groupId;
}
public String getDisplayName() {
diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java
index 68b3d581..689e799b 100644
--- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java
+++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java
@@ -6,7 +6,6 @@
import de.filefighter.rest.RestApplicationIntegrationTest;
import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemEntity;
import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository;
-import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import de.filefighter.rest.domain.user.data.persistance.UserEntity;
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
@@ -16,11 +15,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
-import java.time.Instant;
import java.util.Arrays;
-import java.util.UUID;
-import static de.filefighter.rest.domain.token.business.AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -54,16 +50,6 @@ public void userExists(long userId) {
.build());
}
- @And("user {long} has access token {string}")
- public void userHasAccessToken(long userId, String accessTokenValue) {
- accessTokenRepository.save(AccessTokenEntity
- .builder()
- .userId(userId)
- .value(accessTokenValue)
- .validUntil(Instant.now().getEpochSecond() + ACCESS_TOKEN_DURATION_IN_SECONDS)
- .build());
- }
-
@And("user with id {long} exists and has username {string}, password {string} and refreshToken {string}")
public void userWithIdExistsAndHasUsernamePasswordAndRefreshToken(long userId, String username, String password, String refreshTokenValue) {
userRepository.save(UserEntity
@@ -83,15 +69,15 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId,
System.out.println(Arrays.toString(names));
- // create root dir.
+ // build root dir.
fileSystemRepository.save(FileSystemEntity
.builder()
.isFile(false)
.path(completeFilePath.toString())
- .create());
+ .build());
- // create all files and folders.
+ // build all files and folders.
for (int i = 0; i < names.length; i++) {
if (!names[i].isEmpty() && !names[i].isBlank()) {
boolean isLastOne = i == names.length - 1;
@@ -102,7 +88,7 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId,
.builder()
.isFile(false)
.path(completeFilePath.toString())
- .create());
+ .build());
System.out.println("folder: "+completeFilePath.toString());
}else{
System.out.println("last one: "+names[i]);
@@ -111,7 +97,7 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId,
.builder()
.isFile(true)
.id(fsItemId)
- .create());
+ .build());
} else if (fileOrFolder.equals("folder")) {
completeFilePath.append(names[i]).append("/");
fileSystemRepository.save(FileSystemEntity
@@ -119,7 +105,7 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId,
.isFile(false)
.id(fsItemId)
.path(completeFilePath.toString())
- .create());
+ .build());
} else {
throw new IllegalArgumentException("Found not valid string for FileOrFolder in Steps file.");
}
@@ -148,7 +134,7 @@ public void responseContainsKeyAndValue(String key, String value) throws JsonPro
@And("response contains the user with id {long}")
public void responseContainsTheUserWithId(long userId) throws JsonProcessingException {
JsonNode rootNode = objectMapper.readTree(latestResponse.getBody());
- long actualValue = rootNode.get("userId").asLong();
+ long actualValue = rootNode.get("id").asLong();
assertEquals(userId, actualValue);
}
diff --git a/src/test/java/de/filefighter/rest/cucumber/SystemHealthSteps.java b/src/test/java/de/filefighter/rest/cucumber/SystemHealthSteps.java
index 813926d6..57498ad2 100644
--- a/src/test/java/de/filefighter/rest/cucumber/SystemHealthSteps.java
+++ b/src/test/java/de/filefighter/rest/cucumber/SystemHealthSteps.java
@@ -1,12 +1,21 @@
package de.filefighter.rest.cucumber;
import de.filefighter.rest.RestApplicationIntegrationTest;
+import io.cucumber.java.en.And;
import io.cucumber.java.en.When;
import org.springframework.http.HttpMethod;
+import java.util.Timer;
+import java.util.concurrent.TimeUnit;
+
public class SystemHealthSteps extends RestApplicationIntegrationTest {
@When("the systemHealth endpoint is requested")
public void theSystemHealthEndpointIsRequested() {
executeRestApiCall(HttpMethod.GET, "health/");
}
+
+ @And("the user waits for {int} second\\(s)")
+ public void theUserWaitsForSecondS(int seconds) throws InterruptedException {
+ TimeUnit.SECONDS.sleep(seconds);
+ }
}
diff --git a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java
index fce5a740..872b63a3 100644
--- a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java
+++ b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java
@@ -1,27 +1,127 @@
package de.filefighter.rest.cucumber;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import de.filefighter.rest.RestApplicationIntegrationTest;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import io.cucumber.java.en.And;
-import io.cucumber.java.en.Then;
+import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
+import org.bson.internal.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpMethod;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.UUID;
+
+import static com.mongodb.internal.connection.tlschannel.util.Util.assertTrue;
+import static de.filefighter.rest.configuration.RestConfiguration.*;
+import static de.filefighter.rest.domain.token.business.AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class UserAuthorizationSteps extends RestApplicationIntegrationTest {
+ private final ObjectMapper objectMapper;
+ private final AccessTokenRepository accessTokenRepository;
+
+ @Autowired
+ public UserAuthorizationSteps(AccessTokenRepository accessTokenRepository) {
+ this.objectMapper = new ObjectMapper();
+ this.accessTokenRepository = accessTokenRepository;
+ }
+
+
+ @Given("accessToken with value {string} exists for user {long} and is valid until {long}")
+ public void accessTokenWithValueExistsForUserAndIsValidUntil(String tokenValue, long userId, long validUntil) {
+ accessTokenRepository.save(AccessTokenEntity.builder()
+ .userId(userId)
+ .value(tokenValue)
+ .validUntil(validUntil)
+ .build());
+ }
+
+ @Given("accessToken with value {string} exists for user {long}")
+ public void accessTokenWithValueExistsForUser(String tokenValue, long userId) {
+ accessTokenRepository.save(AccessTokenEntity.builder()
+ .userId(userId)
+ .value(tokenValue)
+ .validUntil(Instant.now().getEpochSecond() + ACCESS_TOKEN_DURATION_IN_SECONDS).build());
+ }
+
@When("user requests login with username {string} and password {string}")
public void userRequestsLoginWithUsernameAndPassword(String username, String password) {
+ String authString = username + ":" + password;
+ String base64encoded = Base64.encode(authString.getBytes());
+ base64encoded = AUTHORIZATION_BASIC_PREFIX + base64encoded;
+
+ HashMap authHeader = new HashMap<>();
+ authHeader.put("Authorization", base64encoded);
+
+ String url = BASE_API_URI + USER_BASE_URI + "login";
+
+ executeRestApiCall(HttpMethod.GET, url, authHeader);
}
@When("user requests accessToken with refreshToken {string} and userId {long}")
public void userRequestsAccessTokenWithRefreshTokenAndUserId(String refreshTokenValue, long userId) {
- }
+ String authHeaderString = AUTHORIZATION_BEARER_PREFIX + refreshTokenValue;
+ String url = BASE_API_URI + USER_BASE_URI + userId + "/login";
- @And("response contains valid accessToken")
- public void responseContainsValidAccessToken() {
+ HashMap authHeader = new HashMap<>();
+ authHeader.put("Authorization", authHeaderString);
+
+ executeRestApiCall(HttpMethod.GET, url, authHeader);
}
@When("user requests userInfo with accessToken {string} and userId {long}")
public void userRequestsUserInfoWithAccessTokenAndUserId(String accessTokenValue, long userId) {
+ String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue;
+ String url = BASE_API_URI + USER_BASE_URI + userId + "/info";
+
+ HashMap authHeader = new HashMap<>();
+ authHeader.put("Authorization", authHeaderString);
+
+ executeRestApiCall(HttpMethod.GET, url, authHeader);
+ }
+
+ @And("response contains valid accessToken for user {long}")
+ public void responseContainsValidAccessTokenForUser(long userId) throws JsonProcessingException {
+ JsonNode rootNode = objectMapper.readTree(latestResponse.getBody());
+ String tokenValue = rootNode.get("token").asText();
+ long actualUserId = rootNode.get("userId").asLong();
+ long validUntil = rootNode.get("validUntil").asLong();
+
+ int expectedTokenLength = UUID.randomUUID().toString().length();
+ int actualTokenLength = tokenValue.length();
+ boolean isStillViable = validUntil > Instant.now().getEpochSecond();
+
+ assertEquals(expectedTokenLength, actualTokenLength);
+ assertTrue(isStillViable);
+ assertEquals(userId, actualUserId);
+ }
+
+ @And("response contains refreshToken {string} and the user with id {long}")
+ public void responseContainsRefreshTokenAndTheUserWithId(String refreshToken, long userId) throws JsonProcessingException {
+ JsonNode rootNode = objectMapper.readTree(latestResponse.getBody());
+ String actualRefreshToken = rootNode.get("refreshToken").asText();
+ JsonNode userNode = rootNode.get("user");
+ long actualUserId = userNode.get("id").asLong();
+
+ assertEquals(userId, actualUserId);
+ assertEquals(refreshToken, actualRefreshToken);
+ }
+
+ @And("response contains valid accessToken for user {long} with a different value than {string}")
+ public void responseContainsValidAccessTokenForUserWithADifferentValueThan(long userId, String differentTokenValue) throws JsonProcessingException {
+ JsonNode rootNode = objectMapper.readTree(latestResponse.getBody());
+ String actualTokenValue = rootNode.get("token").asText();
+ long actualUserId = rootNode.get("userId").asLong();
+
+ assertEquals(userId, actualUserId);
+ assertNotEquals(differentTokenValue, actualTokenValue);
}
}
diff --git a/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java b/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java
new file mode 100644
index 00000000..0f192d85
--- /dev/null
+++ b/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java
@@ -0,0 +1,37 @@
+package de.filefighter.rest.domain.common;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SuppressWarnings(value = "ConstantConditions")
+class UtilsUnitTest {
+
+ @Test
+ void stringIsValid() {
+ String string = "string";
+ boolean actual = Utils.stringIsValid(string);
+ assertTrue(actual);
+ }
+
+ @Test
+ void stringIsNull() {
+ String string = null;
+ boolean actual = Utils.stringIsValid(string);
+ assertFalse(actual);
+ }
+
+ @Test
+ void stringIsEmpty() {
+ String string = "";
+ boolean actual = Utils.stringIsValid(string);
+ assertFalse(actual);
+ }
+
+ @Test
+ void stringIsBlank() {
+ String string = "";
+ boolean actual = Utils.stringIsValid(string);
+ assertFalse(actual);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java
index 954b9a27..28452505 100644
--- a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java
+++ b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java
@@ -28,7 +28,7 @@ void getContentsOfFolder() {
File dummyFile = new File();
ResponseEntity expectedModel = new ResponseEntity<>(FolderContents.builder()
.files(new File[]{dummyFile})
- .folders(new Folder[]{dummyFolder}).create(), OK);
+ .folders(new Folder[]{dummyFolder}).build(), OK);
String path= "/root/data.txt";
String token = "token";
@@ -72,7 +72,7 @@ void uploadFileOrFolder() {
File file = new File();
ResponseEntity expectedModel = new ResponseEntity<>(file, OK);
- FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.create().name("ugabuga").build();
+ FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.builder().name("ugabuga").build();
String token = "token";
when(fileSystemRestServiceMock.uploadFileSystemItemWithAccessToken(fileSystemItemUpdate, token)).thenReturn(expectedModel);
@@ -87,7 +87,7 @@ void updateExistingFileOrFolder() {
ResponseEntity expectedModel = new ResponseEntity<>(file, OK);
long id = 420L;
- FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.create().name("ugabuga").build();
+ FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.builder().name("ugabuga").build();
String token = "token";
when(fileSystemRestServiceMock.updatedFileSystemItemWithIdAndAccessToken(id, fileSystemItemUpdate, token)).thenReturn(expectedModel);
diff --git a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestControllerUnitTest.java
deleted file mode 100644
index 187a9086..00000000
--- a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestControllerUnitTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.filefighter.rest.domain.health.rest;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-
-import static org.mockito.Mockito.*;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-class SystemHealthRestControllerUnitTest {
-
- private final SystemHealthRestService systemHealthRestServiceMock = mock(SystemHealthRestService.class);
- private MockMvc mockMvc;
-
- @BeforeEach
- public void setUp() {
- SystemHealthRestController systemHealthRestController = new SystemHealthRestController(systemHealthRestServiceMock);
- mockMvc = MockMvcBuilders.standaloneSetup(systemHealthRestController).build();
- }
-
- @Test
- void getSystemHealthInfo() throws Exception {
- mockMvc.perform(get("/health"))
- .andExpect(status().isOk())
- .andReturn();
-
- verify(systemHealthRestServiceMock, times(1)).getSystemHealth();
- }
-}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestIntegrationTest.java b/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestIntegrationTest.java
deleted file mode 100644
index fd13c08f..00000000
--- a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestIntegrationTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package de.filefighter.rest.domain.health.rest;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository;
-import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
-import de.filefighter.rest.domain.user.data.persistance.UserEntity;
-import de.filefighter.rest.domain.user.data.persistance.UserRepository;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.web.server.LocalServerPort;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
-public class SystemHealthRestIntegrationTest {
-
- @LocalServerPort
- private int port;
-
- private final Logger LOG = LoggerFactory.getLogger(SystemHealthRestIntegrationTest.class);
- private final ObjectMapper objectMapper;
- private final TestRestTemplate restTemplate;
- private final UserRepository userRepository;
- private final FileSystemRepository fileSystemRepository;
- private final AccessTokenRepository accessTokenRepository;
-
- @Autowired
- public SystemHealthRestIntegrationTest(TestRestTemplate restTemplate, UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
- this.objectMapper = new ObjectMapper();
- this.restTemplate = restTemplate;
- this.userRepository = userRepository;
- this.fileSystemRepository = fileSystemRepository;
- this.accessTokenRepository = accessTokenRepository;
- }
-
- @BeforeEach
- public void cleanDbs() {
- LOG.info("Cleaning Databases.");
- userRepository.deleteAll();
- fileSystemRepository.deleteAll();
- accessTokenRepository.deleteAll();
- }
-
- @Test
- public void healthCheckShouldContainVariablesAndCorrectValues() throws JsonProcessingException {
- LOG.info("Preloading default admin user: " + userRepository.save(UserEntity
- .builder()
- .userId(0L)
- .username("admin")
- .password("admin")
- .refreshToken("refreshToken1234")
- .roleIds(new long[]{0, 1})
- .build()));
- String jsonString = this.restTemplate.getForObject("http://localhost:" + port + "/health", String.class);
-
- // Note when a key does not exist, a NullPointerException will be thrown.
- JsonNode root = objectMapper.readTree(jsonString);
- String uptime = root.get("uptimeInSeconds").asText();
- String userCount = root.get("userCount").asText();
-
- assertTrue(Integer.parseInt(uptime) > 0);
- assertEquals(1, Integer.parseInt(userCount));
- }
-}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestServiceUnitTest.java
index ca18b206..8b8cc210 100644
--- a/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestServiceUnitTest.java
+++ b/src/test/java/de/filefighter/rest/domain/health/rest/SystemHealthRestServiceUnitTest.java
@@ -23,7 +23,7 @@ public void setUp() {
@Test
void getSystemHealth() {
- SystemHealth dummyHealth = SystemHealth.builder().uptimeInSeconds(420).create();
+ SystemHealth dummyHealth = SystemHealth.builder().uptimeInSeconds(420).build();
ResponseEntity expectedModel = new ResponseEntity<>(dummyHealth, HttpStatus.OK);
when(systemHealthBusinessServiceMock.getCurrentSystemHealthInfo()).thenReturn(dummyHealth);
diff --git a/src/test/java/de/filefighter/rest/domain/permission/rest/PermissionRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/permission/rest/PermissionRestControllerUnitTest.java
index d35d0fea..54474ebf 100644
--- a/src/test/java/de/filefighter/rest/domain/permission/rest/PermissionRestControllerUnitTest.java
+++ b/src/test/java/de/filefighter/rest/domain/permission/rest/PermissionRestControllerUnitTest.java
@@ -30,7 +30,7 @@ void setUp() {
void getPermissionSetForFileOrFolder() {
String token = "token";
long id = 420;
- User dummyUser = User.builder().create();
+ User dummyUser = User.builder().build();
ResponseEntity expected = new ResponseEntity<>(new PermissionSet(null, null, new User[]{dummyUser}, null), OK);
when(permissionRestService.getPermissionSetByIdAndToken(id, token)).thenReturn(expected);
diff --git a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java
new file mode 100644
index 00000000..997b9b0b
--- /dev/null
+++ b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java
@@ -0,0 +1,151 @@
+package de.filefighter.rest.domain.token.business;
+
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.time.Instant;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class AccessTokenBusinessServiceUnitTest {
+
+ private final AccessTokenRepository accessTokenRepositoryMock = mock(AccessTokenRepository.class);
+ private final AccessTokenDtoService accessTokenDtoService = mock(AccessTokenDtoService.class);
+ private AccessTokenBusinessService accessTokenBusinessService;
+
+ @BeforeEach
+ void setUp() {
+ accessTokenBusinessService = new AccessTokenBusinessService(accessTokenRepositoryMock, accessTokenDtoService);
+ }
+
+ @Test
+ void getValidAccessTokenForUserWhenNoTokenExists() {
+ long dummyId = 1234;
+ User dummyUser = User.builder().id(dummyId).build();
+ AccessToken dummyAccessToken = AccessToken.builder().userId(dummyId).build();
+ AccessTokenEntity dummyAccessTokenEntity = AccessTokenEntity.builder().userId(dummyId).build();
+
+ when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(null);
+ when(accessTokenRepositoryMock.save(any())).thenReturn(dummyAccessTokenEntity);
+ when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken);
+
+ AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser);
+ assertEquals(dummyAccessToken, accessToken);
+ }
+
+ @Test
+ void getValidAccessTokenForUserWhenTokenExists() {
+ long dummyId = 1234;
+ User dummyUser = User.builder().id(dummyId).build();
+ AccessToken dummyAccessToken = AccessToken.builder().userId(dummyId).build();
+ AccessTokenEntity dummyAccessTokenEntity = AccessTokenEntity
+ .builder()
+ .userId(dummyId)
+ .validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS + 100)
+ .build();
+
+ when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(dummyAccessTokenEntity);
+ when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken);
+
+ AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser);
+ assertEquals(dummyAccessToken, accessToken);
+ }
+
+ @Test
+ void getValidAccessTokenForUserWhenTokenExistsButIsInvalid() {
+ long dummyId = 1234;
+ User dummyUser = User.builder().id(dummyId).build();
+ AccessToken dummyAccessToken = AccessToken.builder().userId(dummyId).build();
+ AccessTokenEntity dummyAccessTokenEntity = AccessTokenEntity
+ .builder()
+ .userId(dummyId)
+ .validUntil(Instant.now().getEpochSecond())
+ .build();
+
+ when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(dummyAccessTokenEntity);
+ when(accessTokenRepositoryMock.save(any())).thenReturn(dummyAccessTokenEntity);
+ when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken);
+
+ AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser);
+
+ assertEquals(dummyAccessToken, accessToken);
+ verify(accessTokenRepositoryMock, times(0)).save(dummyAccessTokenEntity); // the newly saved token is different.
+ }
+
+ @Test
+ void findAccessTokenByValueAndUserIdWithInvalidToken() {
+ String tokenValue = "";
+ long userId = 1234;
+
+ assertThrows(IllegalArgumentException.class, () ->
+ accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId)
+ );
+ }
+
+ @Test
+ void findAccessTokenByValueAndUserIdWithTokenNotFound() {
+ String tokenValue = "value";
+ long userId = 1234;
+
+ when(accessTokenRepositoryMock.findByUserIdAndValue(userId, tokenValue)).thenReturn(null);
+
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId)
+ );
+ }
+
+ @Test
+ void findAccessTokenByValueAndUserIdWithFoundToken() {
+ String tokenValue = "validToken";
+ long userId = 1234;
+ AccessToken dummyAccessToken = AccessToken.builder().build();
+ AccessTokenEntity dummyAccessTokenEntity = AccessTokenEntity.builder().build();
+
+ when(accessTokenRepositoryMock.findByUserIdAndValue(userId, tokenValue)).thenReturn(dummyAccessTokenEntity);
+ when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken);
+
+ AccessToken actual = accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId);
+
+ assertEquals(dummyAccessToken, actual);
+ }
+
+ @Test
+ void generateRandomTokenValue() {
+ String generatedToken = accessTokenBusinessService.generateRandomTokenValue();
+ assertEquals(36, generatedToken.length());
+ }
+
+ @Test
+ void checkBearerHeaderWithWrongHeader(){
+ String header0 = "wrongHeader";
+ String header1 = "";
+ String header2 = "Bearer: ";
+
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ accessTokenBusinessService.checkBearerHeader(header0)
+ );
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ accessTokenBusinessService.checkBearerHeader(header1)
+ );
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ accessTokenBusinessService.checkBearerHeader(header2)
+ );
+ }
+
+ @Test
+ void checkBearerHeaderWithCorrectHeader(){
+ String header = "Bearer: something";
+ String expected = "something";
+
+ String actual = accessTokenBusinessService.checkBearerHeader(header);
+
+ assertEquals(expected, actual);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java
new file mode 100644
index 00000000..705d0e76
--- /dev/null
+++ b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java
@@ -0,0 +1,65 @@
+package de.filefighter.rest.domain.token.business;
+
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
+import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
+import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class AccessTokenDtoServiceUnitTest {
+
+ private final AccessTokenRepository accessTokenRepository = mock(AccessTokenRepository.class);
+ private AccessTokenDtoService accessTokenDtoService;
+
+ @BeforeEach
+ void setUp() {
+ accessTokenDtoService = new AccessTokenDtoService(accessTokenRepository);
+ }
+
+ @Test
+ void createDto() {
+ AccessTokenEntity dummyEntity = AccessTokenEntity.builder()
+ .validUntil(420)
+ .userId(240)
+ .value("token")
+ .build();
+
+ AccessToken actual = accessTokenDtoService.createDto(dummyEntity);
+
+ assertEquals(dummyEntity.getUserId(), actual.getUserId());
+ assertEquals(dummyEntity.getValidUntil(), actual.getValidUntil());
+ assertEquals(dummyEntity.getValue(), actual.getToken());
+ }
+
+ @Test
+ void findEntityNotSuccessfully() {
+ long userId = 420;
+ String token = "token";
+ AccessToken dummyToken = AccessToken.builder().userId(userId).token(token).build();
+
+ when(accessTokenRepository.findByUserIdAndValue(userId, token)).thenReturn(null);
+
+ assertThrows(AccessTokenNotFoundException.class, () ->
+ accessTokenDtoService.findEntity(dummyToken)
+ );
+ }
+
+ @Test
+ void findEntitySuccessfully() {
+ long userId = 420;
+ String token = "token";
+ AccessToken dummyToken = AccessToken.builder().userId(userId).token(token).build();
+ AccessTokenEntity expected = AccessTokenEntity.builder().userId(userId).value(token).build();
+
+ when(accessTokenRepository.findByUserIdAndValue(userId, token)).thenReturn(expected);
+
+ AccessTokenEntity actual = accessTokenDtoService.findEntity(dummyToken);
+
+ assertEquals(expected, actual);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java
index 919ba089..857a99b3 100644
--- a/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java
+++ b/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java
@@ -1,31 +1,200 @@
package de.filefighter.rest.domain.user.business;
+import de.filefighter.rest.domain.token.data.dto.AccessToken;
+import de.filefighter.rest.domain.token.data.dto.RefreshToken;
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.data.persistance.UserEntity;
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
+import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
+import de.filefighter.rest.domain.user.exceptions.UserNotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX;
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class UserBusinessServiceUnitTest {
private final UserRepository userRepositoryMock = mock(UserRepository.class);
+ private final UserDtoService userDtoServiceMock = mock(UserDtoService.class);
private UserBusinessService userBusinessService;
@BeforeEach
void setUp() {
- userBusinessService = new UserBusinessService(userRepositoryMock);
+ userBusinessService = new UserBusinessService(userRepositoryMock, userDtoServiceMock);
}
@Test
void getUserCount() {
- long expectedCount = 420;
+ long count = 20;
- when(userRepositoryMock.count()).thenReturn(expectedCount);
+ when(userRepositoryMock.count()).thenReturn(count);
- long actualCount = userBusinessService.getUserCount();
+ long actual = userBusinessService.getUserCount();
- assertEquals(expectedCount, actualCount);
+ assertEquals(count, actual);
+ }
+
+ @Test
+ void getUserByUsernameAndPasswordThrowsErrors() {
+ String notValid = "";
+ String validButDoesntMatch = "something";
+ String matchesButIsNotSupportedEncoding = AUTHORIZATION_BASIC_PREFIX + "���";
+ String withoutFormalRequirements = AUTHORIZATION_BASIC_PREFIX + "dWdhYnVnYXBhc3N3b3Jk"; //ugabugapassword
+ String userNotFound = AUTHORIZATION_BASIC_PREFIX + "dXNlcjpwYXNzd29yZA=="; // user:password
+
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ userBusinessService.getUserByUsernameAndPassword(notValid)
+ );
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ userBusinessService.getUserByUsernameAndPassword(validButDoesntMatch)
+ );
+ assertThrows(RuntimeException.class, () ->
+ userBusinessService.getUserByUsernameAndPassword(matchesButIsNotSupportedEncoding)
+ );
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ userBusinessService.getUserByUsernameAndPassword(withoutFormalRequirements)
+ );
+
+ when(userRepositoryMock.findByUsernameAndPassword("user", "password")).thenReturn(null);
+ assertThrows(UserNotFoundException.class, () ->
+ userBusinessService.getUserByUsernameAndPassword(userNotFound)
+ );
+ }
+
+ @Test
+ void getUserByUsernameAndPasswordWorksCorrectly() {
+ String header = AUTHORIZATION_BASIC_PREFIX + "dXNlcjpwYXNzd29yZA=="; // user:password
+ User dummyUser = User.builder().build();
+ UserEntity dummyEntity = UserEntity.builder().build();
+
+ when(userRepositoryMock.findByUsernameAndPassword("user", "password")).thenReturn(dummyEntity);
+ when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser);
+
+ User actual = userBusinessService.getUserByUsernameAndPassword(header);
+ assertEquals(dummyUser, actual);
+ }
+
+ @Test
+ void getRefreshTokenForUserWithoutUser() {
+ String invalidString = "";
+ long userId = 420;
+ String username = "someString";
+
+ User dummyUser = User.builder().id(userId).username(username).build();
+
+ when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(null);
+
+ assertThrows(UserNotFoundException.class, () ->
+ userBusinessService.getRefreshTokenForUser(dummyUser)
+ );
+ }
+
+ @Test
+ void getRefreshTokenForUserWithInvalidString() {
+ String invalidString = "";
+ long userId = 420;
+ String username = "someString";
+
+ User dummyUser = User.builder().id(userId).username(username).build();
+ UserEntity dummyEntity = UserEntity.builder().refreshToken(invalidString).build();
+
+ when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(dummyEntity);
+
+ assertThrows(IllegalStateException.class, () ->
+ userBusinessService.getRefreshTokenForUser(dummyUser)
+ );
+ }
+
+ @Test
+ void getCorrectRefreshTokenForUser() {
+ long userId = 420;
+ String username = "someString";
+ String refreshToken = "someToken";
+ User dummyUser = User.builder().id(userId).username(username).build();
+ UserEntity dummyEntity = UserEntity.builder().refreshToken(refreshToken).build();
+ RefreshToken expected = RefreshToken.builder().refreshToken(refreshToken).user(dummyUser).build();
+
+ when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(dummyEntity);
+
+ RefreshToken actual = userBusinessService.getRefreshTokenForUser(dummyUser);
+ assertEquals(expected, actual);
+ }
+
+ // -------------------------------------------------------------------------------------------- //
+
+ @Test
+ void getUserByAccessTokenAndUserIdWithInvalidUserId() {
+ long userId = 420;
+ AccessToken dummyAccessToken = AccessToken.builder().userId(300).build();
+
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ userBusinessService.getUserByAccessTokenAndUserId(dummyAccessToken, userId)
+ );
+ }
+
+ @Test
+ void getUserByAccessTokenAndUserIdWithoutUser() {
+ long userId = 420;
+ AccessToken accessToken = AccessToken.builder().userId(userId).build();
+
+ when(userRepositoryMock.findByUserId(userId)).thenReturn(null);
+
+ assertThrows(UserNotFoundException.class, () ->
+ userBusinessService.getUserByAccessTokenAndUserId(accessToken, userId)
+ );
+ }
+
+ @Test
+ void getUserByAccessTokenAndUserIdCorrectly() {
+ long userId = 420;
+ AccessToken accessToken = AccessToken.builder().userId(userId).build();
+ User dummyUser = User.builder().id(userId).build();
+ UserEntity dummyEntity = UserEntity.builder().build();
+
+ when(userRepositoryMock.findByUserId(userId)).thenReturn(dummyEntity);
+ when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser);
+
+ User actual = userBusinessService.getUserByAccessTokenAndUserId(accessToken, userId);
+
+ assertEquals(dummyUser, actual);
+ }
+
+ // -------------------------------------------------------------------------------------------- //
+
+ @Test
+ void getUserByRefreshTokenAndUserIdWithInvalidToken() {
+ assertThrows(UserNotAuthenticatedException.class, () ->
+ userBusinessService.getUserByRefreshTokenAndUserId("", 0)
+ );
+ }
+
+ @Test
+ void getUserByRefreshTokenAndUserIdWithoutUser() {
+ String token = "token";
+ long userId = 420;
+
+ when(userRepositoryMock.findByRefreshTokenAndUserId(token, userId)).thenReturn(null);
+
+ assertThrows(UserNotFoundException.class, () ->
+ userBusinessService.getUserByRefreshTokenAndUserId(token, userId)
+ );
+ }
+
+ @Test
+ void getUserByRefreshTokenAndUserIdCorrectly() {
+ String token = "token";
+ long userId = 420;
+ User dummyUser = User.builder().id(userId).build();
+ UserEntity dummyEntity = UserEntity.builder().refreshToken(token).build();
+
+ when(userRepositoryMock.findByRefreshTokenAndUserId(token, userId)).thenReturn(dummyEntity);
+ when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser);
+
+ User actual = userBusinessService.getUserByRefreshTokenAndUserId(token, userId);
+
+ assertEquals(dummyUser, actual);
}
}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java
new file mode 100644
index 00000000..3c5b8e3c
--- /dev/null
+++ b/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java
@@ -0,0 +1,67 @@
+package de.filefighter.rest.domain.user.business;
+
+import de.filefighter.rest.domain.user.data.dto.User;
+import de.filefighter.rest.domain.user.data.persistance.UserEntity;
+import de.filefighter.rest.domain.user.data.persistance.UserRepository;
+import de.filefighter.rest.domain.user.exceptions.UserNotFoundException;
+import de.filefighter.rest.domain.user.role.GroupRepository;
+import de.filefighter.rest.domain.user.role.Groups;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class UserDtoServiceUnitTest {
+
+ private final GroupRepository groupRepositoryMock = mock(GroupRepository.class);
+ private final UserRepository userRepositoryMock = mock(UserRepository.class);
+ private UserDtoService userDtoService;
+
+ @BeforeEach
+ void setUp() {
+ userDtoService = new UserDtoService(groupRepositoryMock, userRepositoryMock);
+ }
+
+ @Test
+ void createDto() {
+ long userId = 0;
+ String username = "kevin";
+ long[] groups = new long[]{0};
+ UserEntity dummyEntity = UserEntity.builder().userId(userId).groupIds(groups).username(username).build();
+
+ when(groupRepositoryMock.getRolesByIds(groups)).thenReturn(new Groups[]{Groups.FAMILY});
+
+ User actualUser = userDtoService.createDto(dummyEntity);
+ assertEquals(userId, actualUser.getId());
+ assertEquals(username, actualUser.getUsername());
+ assertEquals(groups[0], actualUser.getGroups()[0].getGroupId());
+ }
+
+ @Test
+ void findEntityThrowsException() {
+ long userId = 0;
+ String username = "kevin";
+ User user = User.builder().username(username).id(userId).build();
+
+ when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(null);
+
+ assertThrows(UserNotFoundException.class, () ->
+ userDtoService.findEntity(user)
+ );
+ }
+
+ @Test
+ void findEntityWorksCorrectly() {
+ long userId = 0;
+ String username = "kevin";
+ User user = User.builder().username(username).id(userId).build();
+ UserEntity expected = UserEntity.builder().username(username).userId(userId).build();
+
+ when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(expected);
+ UserEntity actual = userDtoService.findEntity(user);
+
+ assertEquals(expected, actual);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/filefighter/rest/domain/user/rest/UserRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/rest/UserRestControllerUnitTest.java
index 6d146269..42a06bd2 100644
--- a/src/test/java/de/filefighter/rest/domain/user/rest/UserRestControllerUnitTest.java
+++ b/src/test/java/de/filefighter/rest/domain/user/rest/UserRestControllerUnitTest.java
@@ -26,7 +26,7 @@ void setUp() {
@Test
void registerNewUser() {
- User user = User.builder().id(420).roles(null).username("kevin").create();
+ User user = User.builder().id(420).groups(null).username("kevin").build();
ResponseEntity expectedUser = new ResponseEntity<>(user, OK);
when(userRestServiceMock.registerNewUserWithAccessToken(any(), any())).thenReturn(expectedUser);
@@ -38,7 +38,7 @@ void registerNewUser() {
@Test
void loginUserWithUsernameAndPassword() {
- User user = User.builder().id(420).roles(null).username("kevin").create();
+ User user = User.builder().id(420).groups(null).username("kevin").build();
RefreshToken refreshToken = RefreshToken.builder().refreshToken("token").user(user).build();
ResponseEntity expectedRefreshToken = new ResponseEntity<>(refreshToken, OK);
@@ -62,7 +62,7 @@ void getAccessTokenAndUserInfoByRefreshTokenAndUserId() {
@Test
void getUserInfoWithAccessToken() {
- User user = User.builder().id(420).roles(null).username("kevin").create();
+ User user = User.builder().id(420).groups(null).username("kevin").build();
ResponseEntity expectedUser = new ResponseEntity<>(user, OK);
when(userRestServiceMock.getUserByAccessTokenAndUserId("token", 420)).thenReturn(expectedUser);
@@ -73,9 +73,9 @@ void getUserInfoWithAccessToken() {
@Test
void updateUserWithAccessToken() {
- User user = User.builder().id(420).roles(null).username("kevin").create();
+ User user = User.builder().id(420).groups(null).username("kevin").build();
ResponseEntity expectedUser = new ResponseEntity<>(user, OK);
- UserRegisterForm userRegisterForm = UserRegisterForm.builder().create();
+ UserRegisterForm userRegisterForm = UserRegisterForm.builder().build();
when(userRestServiceMock.updateUserByAccessTokenAndUserId(userRegisterForm, "token", 420)).thenReturn(expectedUser);
ResponseEntity actualUser = userRestController.updateUserWithAccessToken(420,"token", userRegisterForm);
@@ -85,7 +85,7 @@ void updateUserWithAccessToken() {
@Test
void findUserByUsername(){
- User user = User.builder().id(420).roles(null).username("kevin").create();
+ User user = User.builder().id(420).groups(null).username("kevin").build();
ResponseEntity expectedUser = new ResponseEntity<>(user, OK);
String username="kevin";
diff --git a/src/test/resources/SystemHealth.feature b/src/test/resources/SystemHealth.feature
index 40433196..1a75e9b3 100644
--- a/src/test/resources/SystemHealth.feature
+++ b/src/test/resources/SystemHealth.feature
@@ -7,13 +7,17 @@ Background:
Scenario: SystemHealth is requested without users in db
When the systemHealth endpoint is requested
+ And the user waits for 2 second(s)
Then response contains key "userCount" and value "0"
And response contains key "uptimeInSeconds" and value of at least 1
+ And response status code is 200
Scenario: SystemHealth is requested with users in db
Given user 1234 exists
And user 3214 exists
+ And the user waits for 2 second(s)
When the systemHealth endpoint is requested
Then response contains key "userCount" and value "2"
And response contains key "uptimeInSeconds" and value of at least 1
+ And response status code is 200
diff --git a/src/test/resources/UserAuthorization.feature b/src/test/resources/UserAuthorization.feature
index 7bc88839..d53ec677 100644
--- a/src/test/resources/UserAuthorization.feature
+++ b/src/test/resources/UserAuthorization.feature
@@ -1,44 +1,59 @@
-#Feature: User Authorization
-# As a user
-# I want to be able to log in with username and password, as well as verify my identity
-# when using the endpoints.
-#
-#Background:
-# Given database is empty
-# And user with id 1234 exists and has username "user", password "secure_password" and refreshToken "token"
-#
-#Scenario: Successful login with username and password.
-# When user requests login with username "user" and password "secure_password"
-# Then response contains key "refreshToken" and value "token"
-# And response status code is 200
-# And response contains the user with id 1234
-#
-#Scenario: Failed login with username and password.
-# When user requests login with username "user" and password "wrong_password"
-# Then response contains key "message" and value "User not authenticated."
-# And response contains key "status" and value "denied"
-# And response status code is 401
-#
-#Scenario: Successful retrieval of accessToken with refreshToken.
-# When user requests accessToken with refreshToken "token" and userId 1234
-# Then response contains key "userId" and value "1234"
-# And response contains valid accessToken
-# And response status code is 200
-#
-#Scenario: Failed retrieval of accessToken with wrong refreshToken.
-# When user requests accessToken with refreshToken "not_the_token" and userId 1234
-# Then response contains key "message" and value "User not authenticated."
-# And response contains key "status" and value "denied"
-# And response status code is 401
-#
-#Scenario: Successful UserInfo request with valid accessToken.
-# Given user 1234 has access token "accessToken"
-# When user requests userInfo with accessToken "accessToken" and userId 1234
-# Then response contains the user with id 1234
-# And response status code is 200
-#
-#Scenario: Failed UserInfo request with invalid accessToken.
-# When user requests userInfo with accessToken "notTheAccessToken" and userId 1234
-# Then response contains key "message" and value "User not authenticated."
-# And response contains key "status" and value "denied"
-# And response status code is 401
\ No newline at end of file
+Feature: User Authorization
+ As a user
+ I want to be able to log in with username and password, as well as verify my identity
+ when using the endpoints.
+
+Background:
+ Given database is empty
+ And user with id 1234 exists and has username "user", password "secure_password" and refreshToken "token"
+
+Scenario: Successful login with username and password.
+ When user requests login with username "user" and password "secure_password"
+ Then response status code is 200
+ And response contains refreshToken "token" and the user with id 1234
+
+Scenario: Failed login with wrong username or password.
+ When user requests login with username "user" and password "wrong_password"
+ Then response contains key "message" and value "No User found with this username and password."
+ And response contains key "status" and value "denied"
+ And response status code is 404
+
+Scenario: Successful creation of new accessToken with refreshToken.
+ When user requests accessToken with refreshToken "token" and userId 1234
+ Then response contains key "userId" and value "1234"
+ And response contains valid accessToken for user 1234
+ And response status code is 200
+
+Scenario: Successful retrieval of existing accessToken with refreshToken.
+ Given accessToken with value "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282" exists for user 1234
+ When user requests accessToken with refreshToken "token" and userId 1234
+ Then response contains key "userId" and value "1234"
+ And response contains valid accessToken for user 1234
+ And response status code is 200
+
+ # Better scenario description?
+Scenario: Successful retrieval of overwritten accessToken with refreshToken
+ Given accessToken with value "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282" exists for user 1234 and is valid until 0
+ When user requests accessToken with refreshToken "token" and userId 1234
+ Then response contains key "userId" and value "1234"
+ And response contains valid accessToken for user 1234 with a different value than "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282"
+ And response status code is 200
+
+
+ Scenario: Failed retrieval of accessToken with wrong refreshToken.
+ When user requests accessToken with refreshToken "not_the_token" and userId 1234
+ Then response contains key "message" and value "Could not find user 1234"
+ And response contains key "status" and value "denied"
+ And response status code is 404
+
+Scenario: Successful UserInfo request with valid accessToken.
+ Given accessToken with value "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282" exists for user 1234
+ When user requests userInfo with accessToken "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282" and userId 1234
+ Then response contains the user with id 1234
+ And response status code is 200
+
+Scenario: Failed UserInfo request with invalid accessToken.
+ When user requests userInfo with accessToken "tokenInWrongFormat" and userId 1234
+ Then response contains key "message" and value "User with the id 1234 could not be authenticated."
+ And response contains key "status" and value "denied"
+ And response status code is 401
\ No newline at end of file