Skip to content
This repository was archived by the owner on Apr 5, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>de.filefighter</groupId>
<artifactId>rest</artifactId>
<version>0.0.4</version>
<version>0.0.5</version>
<name>RestApi</name>
<description>RestApi for FileFighter</description>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public AccessToken getValidAccessTokenForUser(User user) {
accessTokenEntity = AccessTokenEntity
.builder()
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
.value(this.generateRandomTokenValue())
.value(generateRandomTokenValue())
.userId(user.getId())
.build();
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
Expand All @@ -47,7 +47,7 @@ public AccessToken getValidAccessTokenForUser(User user) {
accessTokenEntity = AccessTokenEntity
.builder()
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
.value(this.generateRandomTokenValue())
.value(generateRandomTokenValue())
.userId(user.getId())
.build();
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
Expand Down Expand Up @@ -80,7 +80,7 @@ public AccessToken findAccessTokenByValue(String accessTokenValue) {
}


public AccessToken validateAccessTokenValue(String accessTokenValue) {
public AccessToken validateAccessTokenValueWithHeader(String accessTokenValue) {
String cleanValue = validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, accessTokenValue);
AccessTokenEntity accessTokenEntity = accessTokenRepository.findByValue(cleanValue);
if (null == accessTokenEntity)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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;
Expand All @@ -15,6 +16,9 @@
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 {

Expand All @@ -28,7 +32,9 @@ public UserAuthorizationService(UserRepository userRepository, UserDtoService us
this.userDtoService = userDtoService;
}

public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPassword) {
public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPasswordWithHeader) {
String base64encodedUserAndPassword = Utils.validateAuthorizationHeader(AUTHORIZATION_BASIC_PREFIX, base64encodedUserAndPasswordWithHeader);

String decodedUsernameAndPassword = "";
try {
byte[] decodedValue = Base64.getDecoder().decode(base64encodedUserAndPassword);
Expand All @@ -54,17 +60,20 @@ public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndP
}

public User authenticateUserWithRefreshToken(String refreshToken) {
UserEntity userEntity = userRepository.findByRefreshToken(refreshToken);
String cleanValue = Utils.validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, refreshToken);
UserEntity userEntity = userRepository.findByRefreshToken(cleanValue);
if (null == userEntity)
throw new UserNotAuthenticatedException("No user found for this Refresh Token.");

return userDtoService.createDto(userEntity);
}

public void authenticateUserWithAccessToken(AccessToken accessToken) {
public User authenticateUserWithAccessToken(AccessToken accessToken) {
UserEntity userEntity = userRepository.findByUserId(accessToken.getUserId());
if (null == userEntity)
throw new UserNotAuthenticatedException(accessToken.getUserId());

return userDtoService.createDto(userEntity);
}

public void authenticateUserWithAccessTokenAndGroup(AccessToken accessToken, Groups groups) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
import de.filefighter.rest.domain.user.exceptions.UserNotFoundException;
import de.filefighter.rest.domain.user.exceptions.UserNotRegisteredException;
import de.filefighter.rest.domain.user.exceptions.UserNotUpdatedException;
import de.filefighter.rest.domain.user.group.GroupRepository;
import de.filefighter.rest.domain.user.group.Groups;
import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.regex.Pattern;

import static de.filefighter.rest.domain.common.Utils.stringIsValid;
Expand All @@ -26,16 +33,19 @@ public class UserBusinessService {
private final UserRepository userRepository;
private final UserDtoService userDtoService;
private final GroupRepository groupRepository;
private final MongoTemplate mongoTemplate;


private static final Logger LOG = LoggerFactory.getLogger(UserBusinessService.class);

@Value("${filefighter.disable-password-check}")
public boolean passwordCheckDisabled;

public UserBusinessService(UserRepository userRepository, UserDtoService userDtoService, GroupRepository groupRepository) {
public UserBusinessService(UserRepository userRepository, UserDtoService userDtoService, GroupRepository groupRepository, MongoTemplate mongoTemplate) {
this.userRepository = userRepository;
this.userDtoService = userDtoService;
this.groupRepository = groupRepository;
this.mongoTemplate = mongoTemplate;
}

public long getUserCount() {
Expand Down Expand Up @@ -97,14 +107,15 @@ public void registerNewUser(UserRegisterForm newUser) {

// check pws.
String password = newUser.getPassword();
passwordIsValid(password);
if (!passwordIsValid(password))
throw new UserNotRegisteredException("Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.");

String confirmationPassword = newUser.getConfirmationPassword();

if (!password.contentEquals(confirmationPassword))
throw new UserNotRegisteredException("Passwords do not match.");

if(password.toLowerCase().contains(username.toLowerCase()))
if (password.toLowerCase().contains(username.toLowerCase()))
throw new UserNotRegisteredException("Username must not appear in password.");

//check groups
Expand All @@ -130,14 +141,93 @@ public void registerNewUser(UserRegisterForm newUser) {
.build());
}

public void passwordIsValid(String password) {
public boolean passwordIsValid(String password) {
if (!Utils.stringIsValid(password))
throw new UserNotRegisteredException("Password was empty.");
return false;

if(this.passwordCheckDisabled) return;
if (this.passwordCheckDisabled) return true;

Pattern pattern = Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\\S+$).{8,20}$");
if (!pattern.matcher(password).matches())
throw new UserNotRegisteredException("Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.");
Pattern pattern = Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\\S+).{8,20}$");
return pattern.matcher(password).matches();
}

public void updateUser(long userId, UserRegisterForm userToUpdate, User authenticatedUser) {
if (null == userToUpdate)
throw new UserNotUpdatedException("No updates specified.");

if(null == authenticatedUser.getGroups())
throw new UserNotUpdatedException("Authenticated User is not allowed");

boolean authenticatedUserIsAdmin = Arrays.stream(authenticatedUser.getGroups()).anyMatch(g -> g == Groups.ADMIN);
if (userId != authenticatedUser.getId() && !authenticatedUserIsAdmin)
throw new UserNotUpdatedException("Only Admins are allowed to update other users.");

UserEntity userEntityToUpdate = userRepository.findByUserId(userId);
Update newUpdate = new Update();
boolean changesWereMade = false;

// username
String username = userToUpdate.getUsername();
if (null != username) {
if (!stringIsValid(username))
throw new UserNotUpdatedException("Wanted to change username, but username was not valid.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but new username..


User user = null;
try {
user = this.findUserByUsername(username);
} catch (UserNotFoundException ignored) {
LOG.info("Username '{}' is free to use.", username);
}

if (null != user)
throw new UserNotUpdatedException("Username already taken.");

changesWereMade = true;
newUpdate.set("username", username);
}

// pw
if (null != userToUpdate.getPassword()) {
String password = userToUpdate.getPassword();
String confirmation = userToUpdate.getConfirmationPassword();

if (!stringIsValid(password) || !stringIsValid(confirmation))
throw new UserNotUpdatedException("Wanted to change password, but password was not valid.");

if (!passwordIsValid(password))
throw new UserNotUpdatedException("Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.");

if (!password.contentEquals(confirmation))
throw new UserNotUpdatedException("Passwords do not match.");

if (password.toLowerCase().contains(userEntityToUpdate.getLowercaseUsername()))
throw new UserNotUpdatedException("Username must not appear in password.");

changesWereMade = true;
newUpdate.set("password", password);
}

// groups
if (null != userToUpdate.getGroupIds()) {
try {
for (Groups group : groupRepository.getGroupsByIds(userToUpdate.getGroupIds())) {
if (group == Groups.ADMIN && !authenticatedUserIsAdmin)
throw new UserNotUpdatedException("Only admins can add users to group " + Groups.ADMIN.getDisplayName());
}
} catch (IllegalArgumentException exception) {
throw new UserNotUpdatedException("One or more groups do not exist.");
}

changesWereMade = true;
newUpdate.set("groupIds", userToUpdate.getGroupIds());
}

if(!changesWereMade)
throw new UserNotUpdatedException("No changes were made.");

Query query = new Query();
query.addCriteria(Criteria.where("userId").is(userId));
mongoTemplate.findAndModify(query, newUpdate, UserEntity.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package de.filefighter.rest.domain.user.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
class UserNotUpdatedAdvise {

@ResponseBody
@ExceptionHandler(UserNotUpdatedException.class)
@ResponseStatus(HttpStatus.CONFLICT)
ResponseEntity<ServerResponse> userNotUpdatedExceptionHandler(UserNotUpdatedException ex) {
LoggerFactory.getLogger(UserNotUpdatedException.class).warn(ex.getMessage());
return new ResponseEntity<>(new ServerResponse(HttpStatus.CONFLICT, ex.getMessage()), HttpStatus.CONFLICT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.filefighter.rest.domain.user.exceptions;

public class UserNotUpdatedException extends RuntimeException{
public UserNotUpdatedException() {
super("User could not get updated");
}

public UserNotUpdatedException(String reason) {
super("User could not get updated. "+reason);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,22 @@ public ResponseEntity<User> getUserInfo(
return userRestService.getUserByUserIdAuthenticateWithAccessToken(accessToken, userId);
}

@PutMapping(USER_BASE_URI + "edit")
public ResponseEntity<User> updateUser(
@PutMapping(USER_BASE_URI + "{userId}/edit")
public ResponseEntity<ServerResponse> updateUser(
@PathVariable long userId,
@RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken,
@RequestBody UserRegisterForm updatedUser) {

LOG.info("Updated User and Token {}, with form {}.", accessToken, updatedUser);
return userRestService.updateUserWithAccessToken(updatedUser, accessToken);
LOG.info("Updated User {} and Token {}, with form {}.", userId, accessToken, updatedUser);
return userRestService.updateUserByUserIdAuthenticateWithAccessToken(updatedUser, userId, accessToken);
}

@GetMapping(USER_BASE_URI + "find")
public ResponseEntity<User> findUserByUsername(
@RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken,
@RequestParam(name = "username", value = "username") String username
) {
LOG.info("Requested finding User with the username {} and Token {}", username, accessToken);
LOG.info("Requested finding User with the username {} and Token {}", username, accessToken);
return userRestService.findUserByUsernameAndAccessToken(username, accessToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.filefighter.rest.domain.user.rest;

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;
Expand All @@ -13,8 +12,6 @@
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;
import static de.filefighter.rest.domain.user.group.Groups.ADMIN;


Expand All @@ -33,44 +30,46 @@ public UserRestService(UserBusinessService userBusinessService, UserAuthorizatio

@Override
public ResponseEntity<User> getUserByUserIdAuthenticateWithAccessToken(String accessToken, long userId) {
AccessToken validAccessToken = accessTokenBusinessService.validateAccessTokenValue(accessToken);
AccessToken validAccessToken = accessTokenBusinessService.validateAccessTokenValueWithHeader(accessToken);
userAuthorizationService.authenticateUserWithAccessToken(validAccessToken);
User user = userBusinessService.getUserById(userId);
return new ResponseEntity<>(user, HttpStatus.OK);
}

@Override
public ResponseEntity<RefreshToken> getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword) {
String cleanValue = Utils.validateAuthorizationHeader(AUTHORIZATION_BASIC_PREFIX, base64encodedUserAndPassword);
User authenticatedUser = userAuthorizationService.authenticateUserWithUsernameAndPassword(cleanValue);
public ResponseEntity<RefreshToken> getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPasswordWithHeader) {
User authenticatedUser = userAuthorizationService.authenticateUserWithUsernameAndPassword(base64encodedUserAndPasswordWithHeader);
RefreshToken refreshToken = userBusinessService.getRefreshTokenForUser(authenticatedUser);
return new ResponseEntity<>(refreshToken, HttpStatus.OK);
}

@Override
public ResponseEntity<AccessToken> getAccessTokenByRefreshToken(String refreshToken) {
String cleanValue = Utils.validateAuthorizationHeader(AUTHORIZATION_BEARER_PREFIX, refreshToken);
User user = userAuthorizationService.authenticateUserWithRefreshToken(cleanValue);
public ResponseEntity<AccessToken> getAccessTokenByRefreshToken(String refreshTokenWithHeader) {
User user = userAuthorizationService.authenticateUserWithRefreshToken(refreshTokenWithHeader);
AccessToken accessToken = accessTokenBusinessService.getValidAccessTokenForUser(user);
return new ResponseEntity<>(accessToken, HttpStatus.OK);
}

@Override
public ResponseEntity<User> updateUserWithAccessToken(UserRegisterForm updatedUser, String accessToken) {
return null;
public ResponseEntity<ServerResponse> updateUserByUserIdAuthenticateWithAccessToken(UserRegisterForm updatedUser, long userId, String accessTokenValue) {
AccessToken accessToken = accessTokenBusinessService.validateAccessTokenValueWithHeader(accessTokenValue);
User authenticatedUser = userAuthorizationService.authenticateUserWithAccessToken(accessToken);
userBusinessService.updateUser(userId, updatedUser, authenticatedUser);
ServerResponse response = new ServerResponse(HttpStatus.CREATED, "User successfully updated.");
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@Override
public ResponseEntity<ServerResponse> registerNewUserWithAccessToken(UserRegisterForm newUser, String accessToken) {
AccessToken validAccessToken = accessTokenBusinessService.validateAccessTokenValue(accessToken);
AccessToken validAccessToken = accessTokenBusinessService.validateAccessTokenValueWithHeader(accessToken);
userAuthorizationService.authenticateUserWithAccessTokenAndGroup(validAccessToken, ADMIN);
userBusinessService.registerNewUser(newUser);
return new ResponseEntity<>(new ServerResponse(HttpStatus.CREATED, "User successfully created."), HttpStatus.CREATED);
}

@Override
public ResponseEntity<User> findUserByUsernameAndAccessToken(String username, String accessToken) {
AccessToken token = accessTokenBusinessService.validateAccessTokenValue(accessToken);
AccessToken token = accessTokenBusinessService.validateAccessTokenValueWithHeader(accessToken);
userAuthorizationService.authenticateUserWithAccessToken(token);
User foundUser = userBusinessService.findUserByUsername(username);
return new ResponseEntity<>(foundUser, HttpStatus.OK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface UserRestServiceInterface {
ResponseEntity<User> getUserByUserIdAuthenticateWithAccessToken(String accessToken, long userId);
ResponseEntity<RefreshToken> getRefreshTokenWithUsernameAndPassword(String base64encodedUserAndPassword);
ResponseEntity<AccessToken> getAccessTokenByRefreshToken(String refreshToken);
ResponseEntity<User> updateUserWithAccessToken(UserRegisterForm updatedUser, String accessToken);
ResponseEntity<ServerResponse> updateUserByUserIdAuthenticateWithAccessToken(UserRegisterForm updatedUser, long userId, String accessToken);
ResponseEntity<ServerResponse> registerNewUserWithAccessToken(UserRegisterForm newUser, String accessToken);
ResponseEntity<User> findUserByUsernameAndAccessToken(String username, String accessToken);
}
Loading