diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index 44529719..691a5613 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -72,6 +72,7 @@ CommandLineRunner initUserDataBaseProd(UserRepository repository) { .builder() .userId(0L) .username("admin") + .lowercaseUsername("admin") .password("admin") .refreshToken("refreshToken1234") .groupIds(new long[]{0, 1}) @@ -90,6 +91,7 @@ CommandLineRunner initUserDataBaseDev(UserRepository repository) { .builder() .userId(0) .username("user") + .lowercaseUsername("user") .password("1234") .refreshToken("rft1234") .groupIds(new long[]{0}) @@ -98,6 +100,7 @@ CommandLineRunner initUserDataBaseDev(UserRepository repository) { .builder() .userId(1) .username("user1") + .lowercaseUsername("user1") .password("12345") .refreshToken("rft") .groupIds(new long[]{-1}) 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 88135d5e..667cf5cc 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 @@ -6,6 +6,7 @@ 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 de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.springframework.stereotype.Service; import java.time.Instant; @@ -59,7 +60,7 @@ public AccessToken getValidAccessTokenForUser(User user) { public AccessToken findAccessTokenByValueAndUserId(String accessTokenValue, long userId) { if (!stringIsValid(accessTokenValue)) - throw new IllegalArgumentException("Value of AccessToken was not valid."); + throw new RequestDidntMeetFormalRequirementsException("Value of AccessToken was not valid."); AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(userId, accessTokenValue); if (null == accessTokenEntity) @@ -68,13 +69,24 @@ public AccessToken findAccessTokenByValueAndUserId(String accessTokenValue, long return accessTokenDtoService.createDto(accessTokenEntity); } + public AccessToken findAccessTokenByValue(String accessTokenValue) { + if (!stringIsValid(accessTokenValue)) + throw new RequestDidntMeetFormalRequirementsException("Value of AccessToken was not valid."); + + AccessTokenEntity accessTokenEntity = accessTokenRepository.findByValue(accessTokenValue); + if (null == accessTokenEntity) + throw new UserNotAuthenticatedException("AccessToken not found."); + + 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."); + throw new RequestDidntMeetFormalRequirementsException("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/exceptions/AccessTokenNotFoundAdvise.java b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java index c5e3c583..13e3c0eb 100644 --- a/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java +++ b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundAdvise.java @@ -17,7 +17,7 @@ public class AccessTokenNotFoundAdvise { @ResponseStatus(HttpStatus.BAD_REQUEST) ResponseEntity tokenNotFoundAdvise(AccessTokenNotFoundException ex) { - LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage()); + LoggerFactory.getLogger(AccessTokenNotFoundException.class).warn(ex.getMessage()); return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.BAD_REQUEST); } } 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 538f84c0..31ebbb98 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 @@ -7,6 +7,7 @@ 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 de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -39,11 +40,11 @@ public long getUserCount() { public User getUserByUsernameAndPassword(String base64encodedUserAndPasswordWithHeaderPrefix) { if (!stringIsValid(base64encodedUserAndPasswordWithHeaderPrefix)) - throw new UserNotAuthenticatedException("Header was empty."); + throw new RequestDidntMeetFormalRequirementsException("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."); + throw new RequestDidntMeetFormalRequirementsException("Header does not contain '" + AUTHORIZATION_BASIC_PREFIX + "', or format is invalid."); String[] split = base64encodedUserAndPasswordWithHeaderPrefix.split(AUTHORIZATION_BASIC_PREFIX); @@ -60,14 +61,14 @@ public User getUserByUsernameAndPassword(String base64encodedUserAndPasswordWith split = decodedUsernameUndPassword.strip().split(":"); if (split.length != 2) - throw new UserNotAuthenticatedException("Credentials didnt meet formal requirements."); + throw new RequestDidntMeetFormalRequirementsException("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."); + throw new UserNotAuthenticatedException("No User found with this username and password."); return userDtoService.createDto(userEntity); } @@ -75,7 +76,7 @@ public User getUserByUsernameAndPassword(String base64encodedUserAndPasswordWith public RefreshToken getRefreshTokenForUser(User user) { UserEntity userEntity = userRepository.findByUserIdAndUsername(user.getId(), user.getUsername()); if (null == userEntity) - throw new UserNotFoundException(); + throw new UserNotAuthenticatedException(user.getId()); String refreshTokenValue = userEntity.getRefreshToken(); @@ -91,11 +92,11 @@ public RefreshToken getRefreshTokenForUser(User user) { public User getUserByRefreshTokenAndUserId(String refreshToken, long userId) { if (!stringIsValid(refreshToken)) - throw new UserNotAuthenticatedException("RefreshToken was not valid."); + throw new RequestDidntMeetFormalRequirementsException("RefreshToken was not valid."); UserEntity userEntity = userRepository.findByRefreshTokenAndUserId(refreshToken, userId); if (null == userEntity) - throw new UserNotFoundException(userId); + throw new UserNotAuthenticatedException(userId); return userDtoService.createDto(userEntity); } @@ -110,4 +111,17 @@ public User getUserByAccessTokenAndUserId(AccessToken accessToken, long userId) return userDtoService.createDto(userEntity); } + + public User findUserByUsername(String username) { + if (!stringIsValid(username)) + throw new RequestDidntMeetFormalRequirementsException("Username was not valid."); + + String lowercaseUsername = username.toLowerCase().replace(" ",""); + + UserEntity entity = userRepository.findByLowercaseUsername(lowercaseUsername); + if (null == entity) + throw new UserNotFoundException("User with username '" + username + "' not found."); + + return userDtoService.createDto(entity); + } } 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 804b81ff..7d4dc21b 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 @@ -1,21 +1,24 @@ package de.filefighter.rest.domain.user.data.persistance; import lombok.Builder; -import lombok.Data; +import lombok.Getter; +import lombok.ToString; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoId; @Document(collection = "user") -@Data +@Getter +@ToString @Builder public class UserEntity { @MongoId - private String _id; - private long userId; - private String username; - private String password; - private String refreshToken; //TODO: add valid_until for refreshToken - private long[] groupIds; + private final String _id; + private final long userId; + private final String username; + private final String lowercaseUsername; // Redundancy for performance tradeoff. + private final String password; + private final String refreshToken; //TODO: add valid_until for refreshToken + private final 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 27d51680..5e885ec8 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 @@ -9,4 +9,5 @@ public interface UserRepository extends MongoRepository { UserEntity findByUsernameAndPassword(String username, String password); UserEntity findByRefreshTokenAndUserId(String refreshToken, long userId); UserEntity findByUserId(long userId); + UserEntity findByLowercaseUsername(String lowercaseUsername); } 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 bd9cfbde..a68abd04 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 @@ -16,7 +16,7 @@ public class UserAlreadyExistsAdvise { @ResponseStatus(HttpStatus.BAD_REQUEST) ResponseEntity userAlreadyExistsAdvise(UserAlreadyExistsException ex) { - LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage()); + LoggerFactory.getLogger(UserAlreadyExistsException.class).warn(ex.getMessage()); 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 3fb11dbb..9a46e540 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 @@ -16,7 +16,7 @@ public class UserNotAuthenticatedAdvise { @ExceptionHandler(UserNotAuthenticatedException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) ResponseEntity userNotAuthenticatedHandler(UserNotAuthenticatedException ex) { - LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage()); + LoggerFactory.getLogger(UserNotAuthenticatedException.class).warn(ex.getMessage()); 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 7b31ae1e..39bbc12e 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,10 +5,6 @@ public UserNotAuthenticatedException(String reason){ super("User could not be authenticated. "+reason); } -// 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 3df30506..9eaa9f5e 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 @@ -16,7 +16,7 @@ class UserNotFoundAdvice { @ExceptionHandler(UserNotFoundException.class) @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); + LoggerFactory.getLogger(UserNotFoundException.class).warn(ex.getMessage()); + return new ResponseEntity<>(new ServerResponse("not found", 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 9c89d4d8..598eda06 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 @@ -10,7 +10,7 @@ public UserNotFoundException(long id) { super("Could not find user " + id); } - public UserNotFoundException(String string) { - super(string); + public UserNotFoundException(String message) { + super(message); } } 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 d5e2048c..efb1cfa3 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 @@ -57,6 +57,9 @@ public ResponseEntity registerNewUserWithAccessToken(UserRegisterForm newU @Override public ResponseEntity findUserByUsernameAndAccessToken(String username, String accessToken) { - return null; + String cleanValue = accessTokenBusinessService.checkBearerHeader(accessToken); + AccessToken token = accessTokenBusinessService.findAccessTokenByValue(cleanValue); + User foundUser = userBusinessService.findUserByUsername(username); + return new ResponseEntity<>(foundUser, HttpStatus.OK); } } diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java b/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java new file mode 100644 index 00000000..44768d7f --- /dev/null +++ b/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java @@ -0,0 +1,22 @@ +package de.filefighter.rest.rest.exceptions; + +import de.filefighter.rest.rest.ServerResponse; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ControllerAdvice +public class RequestDidntMeetFormalRequirementsAdvise { + + @ResponseBody + @ExceptionHandler(RequestDidntMeetFormalRequirementsException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + ResponseEntity requestDidntMeetFormalRequirements(RequestDidntMeetFormalRequirementsException ex) { + LoggerFactory.getLogger(RequestDidntMeetFormalRequirementsException.class).warn(ex.getMessage()); + return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.BAD_REQUEST); + } +} diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java b/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java new file mode 100644 index 00000000..ae38e01c --- /dev/null +++ b/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java @@ -0,0 +1,12 @@ +package de.filefighter.rest.rest.exceptions; + +public class RequestDidntMeetFormalRequirementsException extends RuntimeException{ + + public RequestDidntMeetFormalRequirementsException() { + super("Request didnt meet formal requirements."); + } + + public RequestDidntMeetFormalRequirementsException(String message) { + super("Request didnt meet formal requirements. "+message); + } +} diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 689e799b..db4f297b 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -12,6 +12,8 @@ import io.cucumber.java.en.And; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; @@ -22,6 +24,7 @@ public class CommonCucumberSteps extends RestApplicationIntegrationTest { + private static final Logger LOG = LoggerFactory.getLogger(CommonCucumberSteps.class); private final UserRepository userRepository; private final AccessTokenRepository accessTokenRepository; private final FileSystemRepository fileSystemRepository; @@ -44,21 +47,33 @@ public void databaseIsEmpty() { @And("user {long} exists") public void userExists(long userId) { - userRepository.save(UserEntity + LOG.info("Creating User: " + userRepository.save(UserEntity .builder() .userId(userId) - .build()); + .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 + LOG.info("Creating User: " + userRepository.save(UserEntity .builder() .userId(userId) .username(username) + .lowercaseUsername(username.toLowerCase()) .password(password) .refreshToken(refreshTokenValue) - .build()); + .build())); + } + + @And("user with id {long} exists and has username {string}, password {string}") + public void userWithIdExistsAndHasUsernamePassword(long userId, String username, String password) { + LOG.info("Creating User: " + userRepository.save(UserEntity + .builder() + .userId(userId) + .username(username) + .lowercaseUsername(username.toLowerCase()) + .password(password) + .build())); } // This step almost needs a unit test. @@ -81,7 +96,7 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId, for (int i = 0; i < names.length; i++) { if (!names[i].isEmpty() && !names[i].isBlank()) { boolean isLastOne = i == names.length - 1; - if(!isLastOne){ + if (!isLastOne) { //is obviously a folder. completeFilePath.append(names[i]).append("/"); fileSystemRepository.save(FileSystemEntity @@ -89,9 +104,9 @@ public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId, .isFile(false) .path(completeFilePath.toString()) .build()); - System.out.println("folder: "+completeFilePath.toString()); - }else{ - System.out.println("last one: "+names[i]); + System.out.println("folder: " + completeFilePath.toString()); + } else { + System.out.println("last one: " + names[i]); if (fileOrFolder.equals("file")) { fileSystemRepository.save(FileSystemEntity .builder() diff --git a/src/test/java/de/filefighter/rest/cucumber/FindUserSteps.java b/src/test/java/de/filefighter/rest/cucumber/FindUserSteps.java new file mode 100644 index 00000000..650fad98 --- /dev/null +++ b/src/test/java/de/filefighter/rest/cucumber/FindUserSteps.java @@ -0,0 +1,22 @@ +package de.filefighter.rest.cucumber; + +import de.filefighter.rest.RestApplicationIntegrationTest; +import io.cucumber.java.en.When; +import org.springframework.http.HttpMethod; + +import java.util.HashMap; + +import static de.filefighter.rest.configuration.RestConfiguration.*; + +public class FindUserSteps extends RestApplicationIntegrationTest { + @When("user with accessToken {string} searches user with search-value {string}") + public void userWithAccessTokenSearchesUserWithSearchValue(String accessToken, String search_value) { + String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessToken; + String url = BASE_API_URI + USER_BASE_URI + "/find?username="+search_value; + + HashMap authHeader = new HashMap<>(); + authHeader.put("Authorization", authHeaderString); + + executeRestApiCall(HttpMethod.GET, url, authHeader); + } +} 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 index 997b9b0b..4961fcef 100644 --- a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java @@ -5,6 +5,7 @@ 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 de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -17,12 +18,12 @@ class AccessTokenBusinessServiceUnitTest { private final AccessTokenRepository accessTokenRepositoryMock = mock(AccessTokenRepository.class); - private final AccessTokenDtoService accessTokenDtoService = mock(AccessTokenDtoService.class); + private final AccessTokenDtoService accessTokenDtoServiceMock = mock(AccessTokenDtoService.class); private AccessTokenBusinessService accessTokenBusinessService; @BeforeEach void setUp() { - accessTokenBusinessService = new AccessTokenBusinessService(accessTokenRepositoryMock, accessTokenDtoService); + accessTokenBusinessService = new AccessTokenBusinessService(accessTokenRepositoryMock, accessTokenDtoServiceMock); } @Test @@ -34,7 +35,7 @@ void getValidAccessTokenForUserWhenNoTokenExists() { when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(null); when(accessTokenRepositoryMock.save(any())).thenReturn(dummyAccessTokenEntity); - when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); + when(accessTokenDtoServiceMock.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser); assertEquals(dummyAccessToken, accessToken); @@ -52,7 +53,7 @@ void getValidAccessTokenForUserWhenTokenExists() { .build(); when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(dummyAccessTokenEntity); - when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); + when(accessTokenDtoServiceMock.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser); assertEquals(dummyAccessToken, accessToken); @@ -71,7 +72,7 @@ void getValidAccessTokenForUserWhenTokenExistsButIsInvalid() { when(accessTokenRepositoryMock.findByUserId(dummyId)).thenReturn(dummyAccessTokenEntity); when(accessTokenRepositoryMock.save(any())).thenReturn(dummyAccessTokenEntity); - when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); + when(accessTokenDtoServiceMock.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(dummyUser); @@ -84,7 +85,7 @@ void findAccessTokenByValueAndUserIdWithInvalidToken() { String tokenValue = ""; long userId = 1234; - assertThrows(IllegalArgumentException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId) ); } @@ -109,13 +110,44 @@ void findAccessTokenByValueAndUserIdWithFoundToken() { AccessTokenEntity dummyAccessTokenEntity = AccessTokenEntity.builder().build(); when(accessTokenRepositoryMock.findByUserIdAndValue(userId, tokenValue)).thenReturn(dummyAccessTokenEntity); - when(accessTokenDtoService.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); + when(accessTokenDtoServiceMock.createDto(dummyAccessTokenEntity)).thenReturn(dummyAccessToken); AccessToken actual = accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId); assertEquals(dummyAccessToken, actual); } + @Test + void findAccessTokenByValueThrowsException(){ + String invalidFormat = ""; + String validFormat = "ugabuga"; + + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + accessTokenBusinessService.findAccessTokenByValue(invalidFormat) + ); + + when(accessTokenRepositoryMock.findByValue(validFormat)).thenReturn(null); + + assertThrows(UserNotAuthenticatedException.class, () -> + accessTokenBusinessService.findAccessTokenByValue(validFormat) + ); + } + + @Test + void findAccessTokenByValueSuccessfully(){ + String validFormat = "ugabuga"; + + AccessTokenEntity accessTokenEntity = AccessTokenEntity.builder().build(); + AccessToken expected = AccessToken.builder().build(); + + when(accessTokenRepositoryMock.findByValue(validFormat)).thenReturn(accessTokenEntity); + when(accessTokenDtoServiceMock.createDto(accessTokenEntity)).thenReturn(expected); + + AccessToken actual = accessTokenBusinessService.findAccessTokenByValue(validFormat); + + assertEquals(expected, actual); + } + @Test void generateRandomTokenValue() { String generatedToken = accessTokenBusinessService.generateRandomTokenValue(); @@ -128,13 +160,13 @@ void checkBearerHeaderWithWrongHeader(){ String header1 = ""; String header2 = "Bearer: "; - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> accessTokenBusinessService.checkBearerHeader(header0) ); - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> accessTokenBusinessService.checkBearerHeader(header1) ); - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> accessTokenBusinessService.checkBearerHeader(header2) ); } 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 857a99b3..f23e53b1 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 @@ -7,6 +7,7 @@ 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 de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -45,21 +46,21 @@ void getUserByUsernameAndPasswordThrowsErrors() { String withoutFormalRequirements = AUTHORIZATION_BASIC_PREFIX + "dWdhYnVnYXBhc3N3b3Jk"; //ugabugapassword String userNotFound = AUTHORIZATION_BASIC_PREFIX + "dXNlcjpwYXNzd29yZA=="; // user:password - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> userBusinessService.getUserByUsernameAndPassword(notValid) ); - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> userBusinessService.getUserByUsernameAndPassword(validButDoesntMatch) ); assertThrows(RuntimeException.class, () -> userBusinessService.getUserByUsernameAndPassword(matchesButIsNotSupportedEncoding) ); - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> userBusinessService.getUserByUsernameAndPassword(withoutFormalRequirements) ); when(userRepositoryMock.findByUsernameAndPassword("user", "password")).thenReturn(null); - assertThrows(UserNotFoundException.class, () -> + assertThrows(UserNotAuthenticatedException.class, () -> userBusinessService.getUserByUsernameAndPassword(userNotFound) ); } @@ -79,7 +80,6 @@ void getUserByUsernameAndPasswordWorksCorrectly() { @Test void getRefreshTokenForUserWithoutUser() { - String invalidString = ""; long userId = 420; String username = "someString"; @@ -87,7 +87,7 @@ void getRefreshTokenForUserWithoutUser() { when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(null); - assertThrows(UserNotFoundException.class, () -> + assertThrows(UserNotAuthenticatedException.class, () -> userBusinessService.getRefreshTokenForUser(dummyUser) ); } @@ -166,8 +166,9 @@ void getUserByAccessTokenAndUserIdCorrectly() { @Test void getUserByRefreshTokenAndUserIdWithInvalidToken() { - assertThrows(UserNotAuthenticatedException.class, () -> - userBusinessService.getUserByRefreshTokenAndUserId("", 0) + String invalidToken = ""; + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + userBusinessService.getUserByRefreshTokenAndUserId(invalidToken, 0) ); } @@ -178,7 +179,7 @@ void getUserByRefreshTokenAndUserIdWithoutUser() { when(userRepositoryMock.findByRefreshTokenAndUserId(token, userId)).thenReturn(null); - assertThrows(UserNotFoundException.class, () -> + assertThrows(UserNotAuthenticatedException.class, () -> userBusinessService.getUserByRefreshTokenAndUserId(token, userId) ); } @@ -197,4 +198,34 @@ void getUserByRefreshTokenAndUserIdCorrectly() { assertEquals(dummyUser, actual); } + + @Test + void findUserByUsernameThrowsExceptions(){ + String invalidFormat = ""; + String validFormat = "ugabuga"; + + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + userBusinessService.findUserByUsername(invalidFormat) + ); + + when(userRepositoryMock.findByLowercaseUsername(validFormat)).thenReturn(null); + + assertThrows(UserNotFoundException.class, () -> + userBusinessService.findUserByUsername(validFormat) + ); + } + + @Test + void findUserByUsernameWorksCorrectly(){ + String username = "some str ing w i th white spaces"; + UserEntity userEntity = UserEntity.builder().build(); + User user = User.builder().build(); + + when(userRepositoryMock.findByLowercaseUsername("somestringwithwhitespaces")).thenReturn(userEntity); + when(userDtoServiceMock.createDto(userEntity)).thenReturn(user); + + User actual = userBusinessService.findUserByUsername(username); + + assertEquals(user, actual); + } } \ No newline at end of file diff --git a/src/test/resources/FindUser.feature b/src/test/resources/FindUser.feature index f2527556..13546c77 100644 --- a/src/test/resources/FindUser.feature +++ b/src/test/resources/FindUser.feature @@ -1,38 +1,38 @@ -#Feature: -# As a user -# I want to find another user -# -# Background: -# Given database is empty -# And user with id 1234 exists and has username "kangaroo", password "pig-system" -# And accessToken with value "accessToken1" exists for user 1234 -# And user with id 1235 exists and has username "penguin", password "i-love-capitalism" -# And accessToken with value "accessToken2" exists for user 1235 -# -# Scenario: Successful find another user -# When user with id "1234" and accessToken "accessToken1" searches user with search-value "penguin" -# Then response status code is 200 -# And response contains the user with id 1235 -# -# Scenario: Successful find another user with username in wrong case -# When user with id "1234" and accessToken "accessToken1" searches user with search-value "PeNgUiN" -# Then response status code is 200 -# And response contains the user with id 1235 -# -# Scenario: Successful find another user with username including some spaces -# When user with id "1234" and accessToken "accessToken1" searches user with search-value " pen guin " -# Then response status code is 200 -# And response contains the user with id 1235 -# -# Scenario: Failed to find another user because username has spelling errors -# When user with id "1234" and accessToken "accessToken1" searches user with search-value "benguin" -# Then response status code is 404 -# And response contains key "message" and value "User with username 'benguin' does not exist." -# And response contains key "status" and value "not found" -# -# #kinda same but still -# Scenario: Failed to find another user because username does not exist -# When user with id "1234" and accessToken "accessToken1" searches user with search-value "bielefeld" -# Then response status code is 404 -# And response contains key "message" and value "User with username 'bielefeld' does not exist." -# And response contains key "status" and value "not found" \ No newline at end of file +Feature: Find User with Username + As a user + I want to find another user + + Background: + Given database is empty + And user with id 1234 exists and has username "kangaroo", password "pig-system" + And accessToken with value "accessToken1" exists for user 1234 + And user with id 1235 exists and has username "penguin", password "i-love-capitalism" + And accessToken with value "accessToken2" exists for user 1235 + + Scenario: Successful find another user + When user with accessToken "accessToken1" searches user with search-value "penguin" + Then response status code is 200 + And response contains the user with id 1235 + + Scenario: Successful find another user with username in wrong case + When user with accessToken "accessToken1" searches user with search-value "PeNgUiN" + Then response status code is 200 + And response contains the user with id 1235 + + Scenario: Successful find another user with username including some spaces + When user with accessToken "accessToken1" searches user with search-value " pen guin " + Then response status code is 200 + And response contains the user with id 1235 + + Scenario: Failed to find another user because username has spelling errors + When user with accessToken "accessToken1" searches user with search-value "benguin" + Then response status code is 404 + And response contains key "message" and value "User with username 'benguin' not found." + And response contains key "status" and value "not found" + + #kinda same but still + Scenario: Failed to find another user because username does not exist + When user with accessToken "accessToken1" searches user with search-value "bielefeld" + Then response status code is 404 + And response contains key "message" and value "User with username 'bielefeld' not found." + And response contains key "status" and value "not found" \ No newline at end of file diff --git a/src/test/resources/UserAuthorization.feature b/src/test/resources/UserAuthorization.feature index 1d1dbb93..16b57e98 100644 --- a/src/test/resources/UserAuthorization.feature +++ b/src/test/resources/UserAuthorization.feature @@ -14,9 +14,9 @@ Scenario: Successful login with username and password. 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." + Then response contains key "message" and value "User could not be authenticated. No User found with this username and password." And response contains key "status" and value "denied" - And response status code is 404 + And response status code is 401 Scenario: Successful creation of new accessToken with refreshToken. When user requests accessToken with refreshToken "token" and userId 1234 @@ -41,9 +41,9 @@ Scenario: Successful retrieval of overwritten accessToken with refreshToken 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" + 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 404 + And response status code is 401 Scenario: Successful UserInfo request with valid accessToken. Given accessToken with value "6bb9cb4f-7b51-4c0a-8013-ed7a34e56282" exists for user 1234