From 7d76726af8719d76ca462b3d28edfdeb6d1f23ae Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sat, 14 Nov 2020 12:24:04 +0100 Subject: [PATCH 1/3] FF-109 Rework BusinessServices Logic --- .../filefighter/rest/domain/common/Utils.java | 12 ++ .../business/AccessTokenBusinessService.java | 12 +- .../business/UserAuthorizationService.java | 75 ++++++++++++ .../user/business/UserBusinessService.java | 62 +--------- .../user/data/persistance/UserRepository.java | 2 +- .../domain/user/rest/UserRestController.java | 24 ++-- .../domain/user/rest/UserRestService.java | 33 +++-- .../user/rest/UserRestServiceInterface.java | 6 +- src/main/resources/CLASS_DIAGRAM_rest.uml | 106 ++++++++-------- src/main/resources/DB_SCHEMA_filefighter.uml | 2 +- .../rest/domain/common/UtilsUnitTest.java | 32 +++++ .../AccessTokenBusinessServiceUnitTest.java | 40 ++++-- .../UserAuthorizationServiceUnitTest.java | 104 ++++++++++++++++ .../business/UserBusinessServiceUnitTest.java | 114 ++---------------- .../user/rest/UserRestControllerUnitTest.java | 14 +-- 15 files changed, 374 insertions(+), 264 deletions(-) create mode 100644 src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java create mode 100644 src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java diff --git a/src/main/java/de/filefighter/rest/domain/common/Utils.java b/src/main/java/de/filefighter/rest/domain/common/Utils.java index 4e81e622..991e1d6e 100644 --- a/src/main/java/de/filefighter/rest/domain/common/Utils.java +++ b/src/main/java/de/filefighter/rest/domain/common/Utils.java @@ -1,8 +1,20 @@ package de.filefighter.rest.domain.common; +import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; + public class Utils { public static boolean stringIsValid(String s){ return !(null == s || s.isEmpty() || s.isBlank()); } + + public static String validateAuthorizationHeader(String header, String testString){ + if(!stringIsValid(testString)) + throw new RequestDidntMeetFormalRequirementsException("Header does not contain a valid String."); + + if (!testString.matches("^" + header + "[^\\s](.*)$")) + throw new RequestDidntMeetFormalRequirementsException("Header does not contain '" + header + "', or format is invalid."); + String[] split = testString.split(header); + return split[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 d5fe5e74..a23847c8 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 @@ -15,6 +15,7 @@ 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; +import static de.filefighter.rest.domain.common.Utils.validateAuthorizationHeader; @Service public class AccessTokenBusinessService { @@ -81,10 +82,13 @@ public AccessToken findAccessTokenByValue(String accessTokenValue) { } - public String checkBearerHeader(String accessTokenValue) { - if (!accessTokenValue.matches("^" + AUTHORIZATION_BEARER_PREFIX + "[^\\s](.*)$")) - throw new RequestDidntMeetFormalRequirementsException("Header does not contain '" + AUTHORIZATION_BEARER_PREFIX + "', or format is invalid."); - return accessTokenValue.split(AUTHORIZATION_BEARER_PREFIX)[1]; + public AccessToken validateAccessTokenValue(String accessTokenValue) { + String cleanValue = validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, accessTokenValue); + AccessTokenEntity accessTokenEntity = accessTokenRepository.findByValue(cleanValue); + if (null == accessTokenEntity) + throw new UserNotAuthenticatedException("AccessToken not found."); + + return accessTokenDtoService.createDto(accessTokenEntity); } public String generateRandomTokenValue() { diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java new file mode 100644 index 00000000..82094497 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java @@ -0,0 +1,75 @@ +package de.filefighter.rest.domain.user.business; + +import de.filefighter.rest.domain.common.Utils; +import de.filefighter.rest.domain.token.data.dto.AccessToken; +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.rest.exceptions.RequestDidntMeetFormalRequirementsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX; +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX; + +@Service +public class UserAuthorizationService { + + private final UserRepository userRepository; + private final UserDtoService userDtoService; + + private static final Logger LOG = LoggerFactory.getLogger(UserAuthorizationService.class); + + public UserAuthorizationService(UserRepository userRepository, UserDtoService userDtoService) { + this.userRepository = userRepository; + this.userDtoService = userDtoService; + } + + public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPasswordWithHeaderPrefix) { + base64encodedUserAndPasswordWithHeaderPrefix = Utils.validateAuthorizationHeader(AUTHORIZATION_BASIC_PREFIX, base64encodedUserAndPasswordWithHeaderPrefix); + 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); + } + + String[] split = decodedUsernameUndPassword.strip().split(":"); + + if (split.length != 2) + 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 UserNotAuthenticatedException("No User found with this username and password."); + + return userDtoService.createDto(userEntity); + } + + public User authenticateUserWithRefreshToken(String refreshToken) { + refreshToken = Utils.validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, refreshToken); + + UserEntity userEntity = userRepository.findByRefreshToken(refreshToken); + if (null == userEntity) + throw new UserNotAuthenticatedException("Refresh Token was not valid"); + + return userDtoService.createDto(userEntity); + } + + public void authenticateUserWithAccessToken(AccessToken accessToken) { + UserEntity userEntity = userRepository.findByUserId(accessToken.getUserId()); + if (null == userEntity) + throw new UserNotAuthenticatedException(accessToken.getUserId()); + } +} 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 31ebbb98..6b05abd2 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 @@ -27,8 +27,6 @@ public class UserBusinessService { private final UserRepository userRepository; private final UserDtoService userDtoService; - private static final Logger LOG = LoggerFactory.getLogger(UserBusinessService.class); - public UserBusinessService(UserRepository userRepository, UserDtoService userDtoService) { this.userRepository = userRepository; this.userDtoService = userDtoService; @@ -38,45 +36,19 @@ public long getUserCount() { return userRepository.count(); } - public User getUserByUsernameAndPassword(String base64encodedUserAndPasswordWithHeaderPrefix) { - if (!stringIsValid(base64encodedUserAndPasswordWithHeaderPrefix)) - throw new RequestDidntMeetFormalRequirementsException("Header was empty."); - - //TODO: maybe filter unsupported characters? - if (!base64encodedUserAndPasswordWithHeaderPrefix.matches("^" + AUTHORIZATION_BASIC_PREFIX + "[^\\s](.*)$")) - throw new RequestDidntMeetFormalRequirementsException("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); + public User getUserById(long userId) { + UserEntity userEntity = userRepository.findByUserId(userId); + if (null == userEntity) { + throw new UserNotFoundException(userId); } - split = decodedUsernameUndPassword.strip().split(":"); - - if (split.length != 2) - 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 UserNotAuthenticatedException("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 UserNotAuthenticatedException(user.getId()); + throw new UserNotFoundException(user.getId()); String refreshTokenValue = userEntity.getRefreshToken(); @@ -90,33 +62,11 @@ public RefreshToken getRefreshTokenForUser(User user) { .build(); } - public User getUserByRefreshTokenAndUserId(String refreshToken, long userId) { - if (!stringIsValid(refreshToken)) - throw new RequestDidntMeetFormalRequirementsException("RefreshToken was not valid."); - - UserEntity userEntity = userRepository.findByRefreshTokenAndUserId(refreshToken, userId); - if (null == userEntity) - throw new UserNotAuthenticatedException(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); - } - public User findUserByUsername(String username) { if (!stringIsValid(username)) throw new RequestDidntMeetFormalRequirementsException("Username was not valid."); - String lowercaseUsername = username.toLowerCase().replace(" ",""); + String lowercaseUsername = username.toLowerCase().replace(" ", ""); UserEntity entity = userRepository.findByLowercaseUsername(lowercaseUsername); if (null == entity) 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 5e885ec8..b4fefc13 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 @@ -7,7 +7,7 @@ public interface UserRepository extends MongoRepository { UserEntity findByUserIdAndUsername(long userId, String username); UserEntity findByUsernameAndPassword(String username, String password); - UserEntity findByRefreshTokenAndUserId(String refreshToken, long userId); + UserEntity findByRefreshToken(String refreshToken); UserEntity findByUserId(long userId); UserEntity findByLowercaseUsername(String lowercaseUsername); } 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 1dc9a1a1..71189bea 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 @@ -37,40 +37,38 @@ public ResponseEntity registerNewUser( } @GetMapping(USER_BASE_URI + "login") - public ResponseEntity loginUserWithUsernameAndPassword( + public ResponseEntity loginWithUsernameAndPassword( @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BASIC_PREFIX + "S2V2aW46MTIzNA==") String base64encodedUserAndPassword) { LOG.info("Requested Login."); return userRestService.getRefreshTokenWithUsernameAndPassword(base64encodedUserAndPassword); } - @GetMapping(USER_BASE_URI + "{userId}/login") - public ResponseEntity getAccessTokenAndUserInfoByRefreshTokenAndUserId( - @PathVariable long userId, + @GetMapping(USER_BASE_URI + "auth") + public ResponseEntity getAccessToken( @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String refreshToken) { - LOG.info("Requested login for user {} with token {}.", userId, refreshToken); - return userRestService.getAccessTokenByRefreshTokenAndUserId(refreshToken, userId); + LOG.info("Requested login for token {}.", refreshToken); + return userRestService.getAccessTokenByRefreshToken(refreshToken); } @GetMapping(USER_BASE_URI + "{userId}/info") - public ResponseEntity getUserInfoWithAccessToken( + public ResponseEntity getUserInfo( @PathVariable long userId, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken) { LOG.info("Requested User {} with token {}.", userId, accessToken); - return userRestService.getUserByAccessTokenAndUserId(accessToken, userId); + return userRestService.getUserByUserIdAuthenticateWithAccessToken(accessToken, userId); } - @PutMapping(USER_BASE_URI + "{userId}/edit") - public ResponseEntity updateUserWithAccessToken( - @PathVariable long userId, + @PutMapping(USER_BASE_URI + "edit") + public ResponseEntity updateUser( @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken, @RequestBody UserRegisterForm updatedUser) { - LOG.info("Updated User with the id {} and Token {}, with form {}.", userId, accessToken, updatedUser); - return userRestService.updateUserByAccessTokenAndUserId(updatedUser, accessToken, userId); + LOG.info("Updated User and Token {}, with form {}.", accessToken, updatedUser); + return userRestService.updateUserWithAccessToken(updatedUser, accessToken); } @GetMapping(USER_BASE_URI + "find") 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 efb1cfa3..044bf3ae 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,8 +1,11 @@ package de.filefighter.rest.domain.user.rest; +import de.filefighter.rest.configuration.RestConfiguration; +import de.filefighter.rest.domain.common.Utils; 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.UserAuthorizationService; 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; @@ -10,43 +13,47 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX; + @Service public class UserRestService implements UserRestServiceInterface { private final UserBusinessService userBusinessService; + private final UserAuthorizationService userAuthorizationService; private final AccessTokenBusinessService accessTokenBusinessService; - public UserRestService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService) { + public UserRestService(UserBusinessService userBusinessService, UserAuthorizationService userAuthorizationService, AccessTokenBusinessService accessTokenBusinessService) { this.userBusinessService = userBusinessService; + this.userAuthorizationService = userAuthorizationService; this.accessTokenBusinessService = accessTokenBusinessService; } @Override - public ResponseEntity getUserByAccessTokenAndUserId(String accessTokenValue, long userId) { - String cleanValue = accessTokenBusinessService.checkBearerHeader(accessTokenValue); - AccessToken accessToken = accessTokenBusinessService.findAccessTokenByValueAndUserId(cleanValue, userId); - User user = userBusinessService.getUserByAccessTokenAndUserId(accessToken, userId); + public ResponseEntity getUserByUserIdAuthenticateWithAccessToken(String accessToken, long userId) { + AccessToken validAccessToken = accessTokenBusinessService.validateAccessTokenValue(accessToken); + userAuthorizationService.authenticateUserWithAccessToken(validAccessToken); + User user = userBusinessService.getUserById(userId); return new ResponseEntity<>(user, HttpStatus.OK); } @Override public ResponseEntity getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword) { - User user = userBusinessService.getUserByUsernameAndPassword(base64encodedUserAndPassword); - RefreshToken refreshToken = userBusinessService.getRefreshTokenForUser(user); + User authenticatedUser = userAuthorizationService.authenticateUserWithUsernameAndPassword(base64encodedUserAndPassword); + RefreshToken refreshToken = userBusinessService.getRefreshTokenForUser(authenticatedUser); return new ResponseEntity<>(refreshToken, HttpStatus.OK); } @Override - public ResponseEntity getAccessTokenByRefreshTokenAndUserId(String refreshToken, long userId) { - String cleanValue = accessTokenBusinessService.checkBearerHeader(refreshToken); - User user = userBusinessService.getUserByRefreshTokenAndUserId(cleanValue, userId); + public ResponseEntity getAccessTokenByRefreshToken(String refreshToken) { + String cleanValue = Utils.validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, refreshToken); + User user = userAuthorizationService.authenticateUserWithRefreshToken(cleanValue); AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(user); return new ResponseEntity<>(accessToken, HttpStatus.OK); } @Override - public ResponseEntity updateUserByAccessTokenAndUserId(UserRegisterForm updatedUser, String accessToken, long userId) { + public ResponseEntity updateUserWithAccessToken(UserRegisterForm updatedUser, String accessToken) { return null; } @@ -57,8 +64,8 @@ public ResponseEntity registerNewUserWithAccessToken(UserRegisterForm newU @Override public ResponseEntity findUserByUsernameAndAccessToken(String username, String accessToken) { - String cleanValue = accessTokenBusinessService.checkBearerHeader(accessToken); - AccessToken token = accessTokenBusinessService.findAccessTokenByValue(cleanValue); + AccessToken token = accessTokenBusinessService.validateAccessTokenValue(accessToken); + userAuthorizationService.authenticateUserWithAccessToken(token); User foundUser = userBusinessService.findUserByUsername(username); return new ResponseEntity<>(foundUser, HttpStatus.OK); } diff --git a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestServiceInterface.java b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestServiceInterface.java index 892c0b85..87084da2 100644 --- a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestServiceInterface.java +++ b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestServiceInterface.java @@ -7,10 +7,10 @@ import org.springframework.http.ResponseEntity; public interface UserRestServiceInterface { - ResponseEntity getUserByAccessTokenAndUserId(String accessToken, long userId); + ResponseEntity getUserByUserIdAuthenticateWithAccessToken(String accessToken, long userId); ResponseEntity getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword); - ResponseEntity getAccessTokenByRefreshTokenAndUserId(String refreshToken, long userId); - ResponseEntity updateUserByAccessTokenAndUserId(UserRegisterForm updatedUser, String accessToken, long userId); + ResponseEntity getAccessTokenByRefreshToken(String refreshToken); + ResponseEntity updateUserWithAccessToken(UserRegisterForm updatedUser, String accessToken); ResponseEntity registerNewUserWithAccessToken(UserRegisterForm newUser, String accessToken); ResponseEntity findUserByUsernameAndAccessToken(String username, String accessToken); } diff --git a/src/main/resources/CLASS_DIAGRAM_rest.uml b/src/main/resources/CLASS_DIAGRAM_rest.uml index 200ac13d..586be7a9 100644 --- a/src/main/resources/CLASS_DIAGRAM_rest.uml +++ b/src/main/resources/CLASS_DIAGRAM_rest.uml @@ -7,110 +7,110 @@ de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity.AccessTokenEntityBuilder de.filefighter.rest.domain.permission.rest.PermissionRestController de.filefighter.rest.domain.user.rest.UserRestServiceInterface - de.filefighter.rest.domain.health.rest.SystemHealthRestService de.filefighter.rest.domain.filesystem.rest.FileSystemRestController + de.filefighter.rest.domain.health.rest.SystemHealthRestService de.filefighter.rest.domain.health.rest.SystemHealthRestInterface - de.filefighter.rest.domain.filesystem.rest.FileSystemRestServiceInterface de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedAdvise - de.filefighter.rest.cucumber.SystemHealthSteps + de.filefighter.rest.domain.filesystem.rest.FileSystemRestServiceInterface + de.filefighter.rest.cucumber.SystemHealthSteps de.filefighter.rest.domain.filesystem.rest.FileSystemRestControllerUnitTest de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository de.filefighter.rest.domain.filesystem.data.dto.FolderContents de.filefighter.rest.domain.token.business.AccessTokenBusinessService de.filefighter.rest.domain.permission.data.dto.request.PermissionRecipient - de.filefighter.rest.domain.token.data.dto.RefreshToken.RefreshTokenBuilder de.filefighter.rest.domain.user.data.persistance.UserRepository + de.filefighter.rest.domain.token.data.dto.RefreshToken.RefreshTokenBuilder de.filefighter.rest.domain.filesystem.rest.FileSystemRestService de.filefighter.rest.domain.user.rest.UserRestControllerUnitTest - de.filefighter.rest.domain.user.business.UserDtoService de.filefighter.rest.cucumber.CucumberIntegrationTest + de.filefighter.rest.domain.user.business.UserDtoService de.filefighter.rest.domain.user.data.persistance.UserEntity - de.filefighter.rest.cucumber.ViewFolderContentsSteps + de.filefighter.rest.cucumber.ViewFolderContentsSteps de.filefighter.rest.HeaderSettingRequestCallback de.filefighter.rest.ResponseResults de.filefighter.rest.domain.permission.data.dto.request.PermissionType + de.filefighter.rest.domain.user.data.dto.UserRegisterForm de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate.FileSystemItemUpdateBuilder de.filefighter.rest.domain.permission.data.dto.request.PermissionRequest - de.filefighter.rest.domain.user.data.dto.UserRegisterForm - de.filefighter.rest.domain.token.business.AccessTokenDtoService - de.filefighter.rest.domain.filesystem.data.dto.Folder + de.filefighter.rest.domain.filesystem.data.dto.Folder de.filefighter.rest.domain.user.group.GroupRepositoryUnitTest + de.filefighter.rest.domain.token.business.AccessTokenDtoService de.filefighter.rest.domain.health.business.SystemHealthBusinessServiceUnitTest + de.filefighter.rest.RestApplicationIntegrationTest de.filefighter.rest.domain.filesystem.type.FileSystemType - de.filefighter.rest.RestApplicationIntegrationTest de.filefighter.rest.domain.permission.data.dto.request.PermissionRecipientType de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity de.filefighter.rest.domain.token.data.dto.AccessToken.AccessTokenBuilder de.filefighter.rest.domain.user.group.GroupRepository de.filefighter.rest.rest.RestErrorControllerUnitTest de.filefighter.rest.domain.filesystem.data.dto.FolderContents.FolderContentsBuilder - de.filefighter.rest.domain.permission.rest.PermissionRestServiceInterface de.filefighter.rest.domain.permission.rest.PermissionRestService - de.filefighter.rest.domain.user.business.UserBusinessService + de.filefighter.rest.domain.permission.rest.PermissionRestServiceInterface de.filefighter.rest.domain.user.exceptions.UserNotFoundAdvice + de.filefighter.rest.domain.user.business.UserBusinessService de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository + de.filefighter.rest.domain.user.business.UserBusinessServiceUnitTest de.filefighter.rest.domain.health.data.SystemHealth.SystemHealthBuilder de.filefighter.rest.domain.user.exceptions.UserAlreadyExistsAdvise - de.filefighter.rest.domain.user.business.UserBusinessServiceUnitTest de.filefighter.rest.domain.user.data.dto.UserRegisterForm.UserRegisterFormBuilder de.filefighter.rest.domain.health.rest.SystemHealthRestController de.filefighter.rest.domain.permission.data.dto.PermissionSet - de.filefighter.rest.domain.filesystem.data.dto.File + de.filefighter.rest.domain.filesystem.data.dto.File de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException de.filefighter.rest.domain.common.Utils de.filefighter.rest.domain.user.business.UserDtoServiceUnitTest de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService - de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem + de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository de.filefighter.rest.domain.user.data.dto.User - de.filefighter.rest.domain.filesystem.data.persistance.FileSystemEntity de.filefighter.rest.domain.user.rest.UserRestController + de.filefighter.rest.domain.filesystem.data.persistance.FileSystemEntity de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundAdvise - de.filefighter.rest.domain.permission.rest.PermissionRestControllerUnitTest de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException - de.filefighter.rest.RestApplication + de.filefighter.rest.domain.permission.rest.PermissionRestControllerUnitTest de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepositoryUnitTest de.filefighter.rest.domain.user.group.Groups + de.filefighter.rest.RestApplication de.filefighter.rest.domain.health.rest.SystemHealthRestServiceUnitTest - de.filefighter.rest.domain.token.data.dto.AccessToken de.filefighter.rest.domain.user.rest.UserRestService de.filefighter.rest.domain.filesystem.data.persistance.FileSystemEntity.FileSystemEntityBuilder + de.filefighter.rest.domain.token.data.dto.AccessToken de.filefighter.rest.configuration.PrepareDataBase - de.filefighter.rest.cucumber.UserAuthorizationSteps + de.filefighter.rest.cucumber.UserAuthorizationSteps de.filefighter.rest.domain.user.exceptions.UserAlreadyExistsException de.filefighter.rest.domain.user.data.dto.User.UserBuilder - de.filefighter.rest.cucumber.CrudPermissionSteps + de.filefighter.rest.cucumber.CrudPermissionSteps de.filefighter.rest.configuration.RestConfiguration de.filefighter.rest.domain.health.data.SystemHealth - de.filefighter.rest.domain.common.DtoServiceInterface + de.filefighter.rest.domain.common.DtoServiceInterface de.filefighter.rest.rest.RestErrorController de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate de.filefighter.rest.domain.token.business.AccessTokenDtoServiceUnitTest de.filefighter.rest.domain.common.UtilsUnitTest - de.filefighter.rest.domain.token.data.dto.RefreshToken de.filefighter.rest.domain.user.exceptions.UserNotFoundException - de.filefighter.rest.cucumber.CommonCucumberSteps - de.filefighter.rest.domain.permission.business.PermissionBusinessService + de.filefighter.rest.domain.token.data.dto.RefreshToken + de.filefighter.rest.cucumber.CommonCucumberSteps de.filefighter.rest.rest.ServerResponse + de.filefighter.rest.domain.permission.business.PermissionBusinessService de.filefighter.rest.domain.user.data.persistance.UserEntity.UserEntityBuilder de.filefighter.rest.domain.health.business.SystemHealthBusinessService de.filefighter.rest.domain.token.business.AccessTokenBusinessServiceUnitTest - + - + - - - + + + @@ -118,9 +118,9 @@ - - - + + + @@ -128,46 +128,46 @@ - - - + + + - - - + + + - - - + + + - - - + - + + + - - - + + + - - - + + + - + de.filefighter.rest.configuration.SwaggerConfiguration diff --git a/src/main/resources/DB_SCHEMA_filefighter.uml b/src/main/resources/DB_SCHEMA_filefighter.uml index f2f984a2..e9a9795f 100644 --- a/src/main/resources/DB_SCHEMA_filefighter.uml +++ b/src/main/resources/DB_SCHEMA_filefighter.uml @@ -4,8 +4,8 @@ 9354147b-ef48-46d1-ba1e-bb184772808e.SCHEMA:filefighter 9354147b-ef48-46d1-ba1e-bb184772808e.TABLE:filefighter.user - 9354147b-ef48-46d1-ba1e-bb184772808e.TABLE:filefighter.filesystem 9354147b-ef48-46d1-ba1e-bb184772808e.TABLE:filefighter.token + 9354147b-ef48-46d1-ba1e-bb184772808e.TABLE:filefighter.filesystem diff --git a/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java b/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java index 0f192d85..16821e31 100644 --- a/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/common/UtilsUnitTest.java @@ -1,7 +1,9 @@ package de.filefighter.rest.domain.common; +import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.Test; +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX; import static org.junit.jupiter.api.Assertions.*; @SuppressWarnings(value = "ConstantConditions") @@ -34,4 +36,34 @@ void stringIsBlank() { boolean actual = Utils.stringIsValid(string); assertFalse(actual); } + + @Test + void validateHeaderThrows() { + String dummyHeaderPrefix = "UGABUGA: "; + + String notValid = ""; + String validButDoesntMatch = "something"; + String noContent = dummyHeaderPrefix + ""; + + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + Utils.validateAuthorizationHeader(dummyHeaderPrefix, notValid) + ); + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + Utils.validateAuthorizationHeader(dummyHeaderPrefix, validButDoesntMatch) + ); + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + Utils.validateAuthorizationHeader(dummyHeaderPrefix, noContent) + ); + } + + @Test + void validateHeaderWorks() { + String dummyHeaderPrefix = "UGABUGA: "; + String expected = "baum"; + String valid = dummyHeaderPrefix.concat(expected); + + String actual = Utils.validateAuthorizationHeader(dummyHeaderPrefix, valid); + + assertEquals(expected, actual); + } } \ No newline at end of file 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 4961fcef..9f0438fa 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 @@ -118,7 +118,7 @@ void findAccessTokenByValueAndUserIdWithFoundToken() { } @Test - void findAccessTokenByValueThrowsException(){ + void findAccessTokenByValueThrowsException() { String invalidFormat = ""; String validFormat = "ugabuga"; @@ -134,7 +134,7 @@ void findAccessTokenByValueThrowsException(){ } @Test - void findAccessTokenByValueSuccessfully(){ + void findAccessTokenByValueSuccessfully() { String validFormat = "ugabuga"; AccessTokenEntity accessTokenEntity = AccessTokenEntity.builder().build(); @@ -155,29 +155,51 @@ void generateRandomTokenValue() { } @Test - void checkBearerHeaderWithWrongHeader(){ + void validateAccessTokenValueWithWrongHeader() { String header0 = "wrongHeader"; String header1 = ""; String header2 = "Bearer: "; assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - accessTokenBusinessService.checkBearerHeader(header0) + accessTokenBusinessService.validateAccessTokenValue(header0) ); assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - accessTokenBusinessService.checkBearerHeader(header1) + accessTokenBusinessService.validateAccessTokenValue(header1) ); assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - accessTokenBusinessService.checkBearerHeader(header2) + accessTokenBusinessService.validateAccessTokenValue(header2) ); } @Test - void checkBearerHeaderWithCorrectHeader(){ + void validateAccessTokenValueButTokenDoesNotExist() { String header = "Bearer: something"; - String expected = "something"; - String actual = accessTokenBusinessService.checkBearerHeader(header); + when(accessTokenRepositoryMock.findByValue("something")).thenReturn(null); + assertThrows(UserNotAuthenticatedException.class, () -> + accessTokenBusinessService.validateAccessTokenValue(header) + ); + } + + @Test + void validateAccessTokenValue() { + String header = "Bearer: something"; + AccessToken expected = AccessToken.builder().build(); + AccessTokenEntity accessTokenEntity = AccessTokenEntity.builder().build(); + + when(accessTokenRepositoryMock.findByValue("something")).thenReturn(accessTokenEntity); + when(accessTokenDtoServiceMock.createDto(accessTokenEntity)).thenReturn(expected); + + AccessToken actual = accessTokenBusinessService.validateAccessTokenValue(header); assertEquals(expected, actual); } + + @Test + void getAccessTokenCount(){ + long count = 420; + when(accessTokenRepositoryMock.count()).thenReturn(count); + + assertEquals(420, accessTokenBusinessService.getAccessTokenCount()); + } } \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java new file mode 100644 index 00000000..13d2b59c --- /dev/null +++ b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java @@ -0,0 +1,104 @@ +package de.filefighter.rest.domain.user.business; + +import de.filefighter.rest.domain.token.data.dto.AccessToken; +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.rest.exceptions.RequestDidntMeetFormalRequirementsException; +import org.junit.jupiter.api.Test; + +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX; +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class UserAuthorizationServiceUnitTest { + + private final UserRepository userRepositoryMock = mock(UserRepository.class); + private final UserDtoService userDtoServiceMock = mock(UserDtoService.class); + private final UserAuthorizationService userAuthorizationService = new UserAuthorizationService( + userRepositoryMock, + userDtoServiceMock); + + @Test + void authenticateUserWithUsernameAndPasswordThrows() { + String matchesButIsNotSupportedEncoding = AUTHORIZATION_BASIC_PREFIX + "���"; + String matchesButDoesNotMeetRequirements = AUTHORIZATION_BASIC_PREFIX + "dWdhYnVnYQ=="; + String matchesButUserWasNotFound = AUTHORIZATION_BASIC_PREFIX + "dXNlcjp1c2Vy"; + + assertThrows(RuntimeException.class, () -> + userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButIsNotSupportedEncoding) + ); + assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButDoesNotMeetRequirements) + ); + + when(userRepositoryMock.findByUsernameAndPassword("user", "user")).thenReturn(null); + + assertThrows(UserNotAuthenticatedException.class, () -> + userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButUserWasNotFound)); + } + + @Test + void authenticateUserWithUsernameAndPasswordWorksCorrectly() { + 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 = userAuthorizationService.authenticateUserWithUsernameAndPassword(header); + assertEquals(dummyUser, actual); + } + + @Test + void authenticateUserWithRefreshTokenThrowsExceptions() { + String refreshToken = "Something"; + String authString = AUTHORIZATION_BEARER_PREFIX + refreshToken; + + when(userRepositoryMock.findByRefreshToken(refreshToken)).thenReturn(null); + + assertThrows(UserNotAuthenticatedException.class, () -> + userAuthorizationService.authenticateUserWithRefreshToken(authString)); + } + + @Test + void authenticateUserWithRefreshTokenWorksCorrectly() { + String refreshToken = "Something"; + String authString = AUTHORIZATION_BEARER_PREFIX + refreshToken; + UserEntity dummyEntity = UserEntity.builder().build(); + User dummyUser = User.builder().build(); + + when(userRepositoryMock.findByRefreshToken(refreshToken)).thenReturn(dummyEntity); + when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser); + + User actualUser = userAuthorizationService.authenticateUserWithRefreshToken(authString); + assertEquals(dummyUser, actualUser); + } + + + @Test + void authenticateUserWithAccessTokenThrows() { + long userId = 420; + AccessToken accessToken = AccessToken.builder().userId(userId).build(); + + when(userRepositoryMock.findByUserId(userId)).thenReturn(null); + + assertThrows(UserNotAuthenticatedException.class, () -> + userAuthorizationService.authenticateUserWithAccessToken(accessToken)); + } + + @Test + void authenticateUserWithAccessTokenWorksCorrectly() { + long userId = 420; + AccessToken accessToken = AccessToken.builder().userId(userId).build(); + UserEntity userEntity = UserEntity.builder().build(); + + when(userRepositoryMock.findByUserId(userId)).thenReturn(userEntity); + + userAuthorizationService.authenticateUserWithAccessToken(accessToken); + } +} \ 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 f23e53b1..f368bd4b 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 @@ -38,46 +38,6 @@ void getUserCount() { 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(RequestDidntMeetFormalRequirementsException.class, () -> - userBusinessService.getUserByUsernameAndPassword(notValid) - ); - assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - userBusinessService.getUserByUsernameAndPassword(validButDoesntMatch) - ); - assertThrows(RuntimeException.class, () -> - userBusinessService.getUserByUsernameAndPassword(matchesButIsNotSupportedEncoding) - ); - assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - userBusinessService.getUserByUsernameAndPassword(withoutFormalRequirements) - ); - - when(userRepositoryMock.findByUsernameAndPassword("user", "password")).thenReturn(null); - assertThrows(UserNotAuthenticatedException.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() { long userId = 420; @@ -87,7 +47,7 @@ void getRefreshTokenForUserWithoutUser() { when(userRepositoryMock.findByUserIdAndUsername(userId, username)).thenReturn(null); - assertThrows(UserNotAuthenticatedException.class, () -> + assertThrows(UserNotFoundException.class, () -> userBusinessService.getRefreshTokenForUser(dummyUser) ); } @@ -123,79 +83,25 @@ void getCorrectRefreshTokenForUser() { 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); + void getUserByIdThrowsExceptions(){ + long id = 420; + when(userRepositoryMock.findByUserId(id)).thenReturn(null); assertThrows(UserNotFoundException.class, () -> - userBusinessService.getUserByAccessTokenAndUserId(accessToken, userId) - ); + userBusinessService.getUserById(id)); } @Test - void getUserByAccessTokenAndUserIdCorrectly() { - long userId = 420; - AccessToken accessToken = AccessToken.builder().userId(userId).build(); - User dummyUser = User.builder().id(userId).build(); + void getUserByIdWorks(){ + long id = 420; UserEntity dummyEntity = UserEntity.builder().build(); + User dummyUser = User.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() { - String invalidToken = ""; - assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - userBusinessService.getUserByRefreshTokenAndUserId(invalidToken, 0) - ); - } - - @Test - void getUserByRefreshTokenAndUserIdWithoutUser() { - String token = "token"; - long userId = 420; - - when(userRepositoryMock.findByRefreshTokenAndUserId(token, userId)).thenReturn(null); - - assertThrows(UserNotAuthenticatedException.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(userRepositoryMock.findByUserId(id)).thenReturn(dummyEntity); when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser); - User actual = userBusinessService.getUserByRefreshTokenAndUserId(token, userId); - + User actual = userBusinessService.getUserById(id); assertEquals(dummyUser, actual); } 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 42a06bd2..8c170f65 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 @@ -44,7 +44,7 @@ void loginUserWithUsernameAndPassword() { when(userRestServiceMock.getRefreshTokenWithUsernameAndPassword(any())).thenReturn(expectedRefreshToken); - ResponseEntity actualRefreshToken = userRestController.loginUserWithUsernameAndPassword(""); + ResponseEntity actualRefreshToken = userRestController.loginWithUsernameAndPassword(""); assertEquals(expectedRefreshToken, actualRefreshToken); } @@ -54,9 +54,9 @@ void getAccessTokenAndUserInfoByRefreshTokenAndUserId() { AccessToken accessToken = AccessToken.builder().build(); ResponseEntity accessTokenEntityModel = new ResponseEntity<>(accessToken, OK); - when(userRestServiceMock.getAccessTokenByRefreshTokenAndUserId("token", 420)).thenReturn(accessTokenEntityModel); + when(userRestServiceMock.getAccessTokenByRefreshToken("token")).thenReturn(accessTokenEntityModel); - ResponseEntity actualAccessTokenEntity = userRestController.getAccessTokenAndUserInfoByRefreshTokenAndUserId(420, "token"); + ResponseEntity actualAccessTokenEntity = userRestController.getAccessToken("token"); assertEquals(accessTokenEntityModel, actualAccessTokenEntity); } @@ -65,8 +65,8 @@ void getUserInfoWithAccessToken() { User user = User.builder().id(420).groups(null).username("kevin").build(); ResponseEntity expectedUser = new ResponseEntity<>(user, OK); - when(userRestServiceMock.getUserByAccessTokenAndUserId("token", 420)).thenReturn(expectedUser); - ResponseEntity actualUser = userRestController.getUserInfoWithAccessToken(420,"token"); + when(userRestServiceMock.getUserByUserIdAuthenticateWithAccessToken("token", 420)).thenReturn(expectedUser); + ResponseEntity actualUser = userRestController.getUserInfo(420,"token"); assertEquals(expectedUser, actualUser); } @@ -77,8 +77,8 @@ void updateUserWithAccessToken() { ResponseEntity expectedUser = new ResponseEntity<>(user, OK); UserRegisterForm userRegisterForm = UserRegisterForm.builder().build(); - when(userRestServiceMock.updateUserByAccessTokenAndUserId(userRegisterForm, "token", 420)).thenReturn(expectedUser); - ResponseEntity actualUser = userRestController.updateUserWithAccessToken(420,"token", userRegisterForm); + when(userRestServiceMock.updateUserWithAccessToken(userRegisterForm, "token")).thenReturn(expectedUser); + ResponseEntity actualUser = userRestController.updateUser("token", userRegisterForm); assertEquals(expectedUser, actualUser); } From b70997fff56fd5a2be3c1ac940c84222941a3c51 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sat, 14 Nov 2020 12:38:28 +0100 Subject: [PATCH 2/3] FF-110 Fixed Tests and Bugs. --- .../rest/configuration/RestConfiguration.java | 2 +- .../user/business/UserAuthorizationService.java | 11 ++++------- .../rest/domain/user/rest/UserRestService.java | 4 +++- .../rest/cucumber/UserAuthorizationSteps.java | 6 +++--- src/test/resources/UserAuthorization.feature | 12 ++++++------ 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java index 45265812..a458b7f4 100644 --- a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java +++ b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java @@ -10,7 +10,7 @@ public class RestConfiguration { //Custom static constants - public static final String BASE_API_URI = "/api/v1/"; + public static final String BASE_API_URI = "/api/v1"; public static final String AUTHORIZATION_BASIC_PREFIX = "Basic: "; public static final String AUTHORIZATION_BEARER_PREFIX = "Bearer: "; public static final String FS_BASE_URI = "/filesystem/"; diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java index 82094497..9ebd5a9e 100644 --- a/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java +++ b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java @@ -31,14 +31,13 @@ public UserAuthorizationService(UserRepository userRepository, UserDtoService us this.userDtoService = userDtoService; } - public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPasswordWithHeaderPrefix) { - base64encodedUserAndPasswordWithHeaderPrefix = Utils.validateAuthorizationHeader(AUTHORIZATION_BASIC_PREFIX, base64encodedUserAndPasswordWithHeaderPrefix); + public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPassword) { String decodedUsernameUndPassword; try { - byte[] decodedValue = Base64.getDecoder().decode(base64encodedUserAndPasswordWithHeaderPrefix); + byte[] decodedValue = Base64.getDecoder().decode(base64encodedUserAndPassword); decodedUsernameUndPassword = new String(decodedValue, StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException | IllegalArgumentException ex) { - LOG.warn("Found UnsupportedEncodingException in {}", base64encodedUserAndPasswordWithHeaderPrefix); + LOG.warn("Found UnsupportedEncodingException in {}", base64encodedUserAndPassword); throw new RuntimeException(ex); } @@ -58,11 +57,9 @@ public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndP } public User authenticateUserWithRefreshToken(String refreshToken) { - refreshToken = Utils.validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, refreshToken); - UserEntity userEntity = userRepository.findByRefreshToken(refreshToken); if (null == userEntity) - throw new UserNotAuthenticatedException("Refresh Token was not valid"); + throw new UserNotAuthenticatedException("No user found for this Refresh Token."); return userDtoService.createDto(userEntity); } 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 044bf3ae..2143ffd5 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 @@ -13,6 +13,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX; import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX; @@ -39,7 +40,8 @@ public ResponseEntity getUserByUserIdAuthenticateWithAccessToken(String ac @Override public ResponseEntity getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword) { - User authenticatedUser = userAuthorizationService.authenticateUserWithUsernameAndPassword(base64encodedUserAndPassword); + String cleanValue = Utils.validateAuthorizationHeader(AUTHORIZATION_BASIC_PREFIX, base64encodedUserAndPassword); + User authenticatedUser = userAuthorizationService.authenticateUserWithUsernameAndPassword(cleanValue); RefreshToken refreshToken = userBusinessService.getRefreshTokenForUser(authenticatedUser); return new ResponseEntity<>(refreshToken, HttpStatus.OK); } diff --git a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java index 872b63a3..4fd18f3b 100644 --- a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java @@ -66,10 +66,10 @@ public void userRequestsLoginWithUsernameAndPassword(String username, String pas executeRestApiCall(HttpMethod.GET, url, authHeader); } - @When("user requests accessToken with refreshToken {string} and userId {long}") - public void userRequestsAccessTokenWithRefreshTokenAndUserId(String refreshTokenValue, long userId) { + @When("user requests accessToken with refreshToken {string}") + public void userRequestsAccessTokenWithRefreshTokenAndUserId(String refreshTokenValue) { String authHeaderString = AUTHORIZATION_BEARER_PREFIX + refreshTokenValue; - String url = BASE_API_URI + USER_BASE_URI + userId + "/login"; + String url = BASE_API_URI + USER_BASE_URI + "auth"; HashMap authHeader = new HashMap<>(); authHeader.put("Authorization", authHeaderString); diff --git a/src/test/resources/UserAuthorization.feature b/src/test/resources/UserAuthorization.feature index 16b57e98..91737c28 100644 --- a/src/test/resources/UserAuthorization.feature +++ b/src/test/resources/UserAuthorization.feature @@ -19,14 +19,14 @@ Scenario: Failed login with wrong username or password. And response status code is 401 Scenario: Successful creation of new accessToken with refreshToken. - When user requests accessToken with refreshToken "token" and userId 1234 + When user requests accessToken with refreshToken "token" 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 + When user requests accessToken with refreshToken "token" Then response contains key "userId" and value "1234" And response contains valid accessToken for user 1234 And response status code is 200 @@ -34,14 +34,14 @@ Scenario: Successful retrieval of existing accessToken with refreshToken. # 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 + When user requests accessToken with refreshToken "token" 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 "User with the id 1234 could not be authenticated." + When user requests accessToken with refreshToken "not_the_token" + Then response contains key "message" and value "User could not be authenticated. No user found for this Refresh Token." And response contains key "status" and value "denied" And response status code is 401 @@ -53,6 +53,6 @@ Scenario: Successful UserInfo request with valid accessToken. 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." + Then response contains key "message" and value "User could not be authenticated. AccessToken not found." And response contains key "status" and value "denied" And response status code is 401 \ No newline at end of file From 27d6b0eb75fceddd8f8b7fe2d7fac14ab37115bc Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sat, 14 Nov 2020 12:53:54 +0100 Subject: [PATCH 3/3] Fixed Tests. --- .run/JUnit Tests.run.xml | 6 +++++- .../business/UserAuthorizationServiceUnitTest.java | 11 +++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.run/JUnit Tests.run.xml b/.run/JUnit Tests.run.xml index cd78603d..b9d46b5c 100644 --- a/.run/JUnit Tests.run.xml +++ b/.run/JUnit Tests.run.xml @@ -1,12 +1,16 @@ - + diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java index 13d2b59c..79be9fb8 100644 --- a/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java @@ -24,9 +24,9 @@ class UserAuthorizationServiceUnitTest { @Test void authenticateUserWithUsernameAndPasswordThrows() { - String matchesButIsNotSupportedEncoding = AUTHORIZATION_BASIC_PREFIX + "���"; - String matchesButDoesNotMeetRequirements = AUTHORIZATION_BASIC_PREFIX + "dWdhYnVnYQ=="; - String matchesButUserWasNotFound = AUTHORIZATION_BASIC_PREFIX + "dXNlcjp1c2Vy"; + String matchesButIsNotSupportedEncoding = "���"; + String matchesButDoesNotMeetRequirements = "dWdhYnVnYQ=="; + String matchesButUserWasNotFound = "dXNlcjp1c2Vy"; assertThrows(RuntimeException.class, () -> userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButIsNotSupportedEncoding) @@ -43,7 +43,7 @@ void authenticateUserWithUsernameAndPasswordThrows() { @Test void authenticateUserWithUsernameAndPasswordWorksCorrectly() { - String header = AUTHORIZATION_BASIC_PREFIX + "dXNlcjpwYXNzd29yZA=="; // user:password + String header = "dXNlcjpwYXNzd29yZA=="; // user:password User dummyUser = User.builder().build(); UserEntity dummyEntity = UserEntity.builder().build(); @@ -68,14 +68,13 @@ void authenticateUserWithRefreshTokenThrowsExceptions() { @Test void authenticateUserWithRefreshTokenWorksCorrectly() { String refreshToken = "Something"; - String authString = AUTHORIZATION_BEARER_PREFIX + refreshToken; UserEntity dummyEntity = UserEntity.builder().build(); User dummyUser = User.builder().build(); when(userRepositoryMock.findByRefreshToken(refreshToken)).thenReturn(dummyEntity); when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser); - User actualUser = userAuthorizationService.authenticateUserWithRefreshToken(authString); + User actualUser = userAuthorizationService.authenticateUserWithRefreshToken(refreshToken); assertEquals(dummyUser, actualUser); }