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
16 changes: 16 additions & 0 deletions .run/Run Cucumber Tests.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Cucumber Tests" type="JUnit" factoryName="JUnit">
<useClassPathOnly />
<option name="PACKAGE_NAME" value="de.filefighter.rest.cucumber" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
package de.filefighter.rest.configuration;

import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository;
import de.filefighter.rest.domain.token.business.AccessTokenBusinessService;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import de.filefighter.rest.domain.user.data.persistance.UserEntity;
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import java.time.Instant;

@Configuration
public class PrepareDataBase {

@Value("${server.port}")
int serverPort;

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

@Bean
@Profile({"dev", "prod"})
CommandLineRunner veryImportantFileFighterStartScript() {
return args -> {
System.out.println();
System.out.println("-------------------------------< REST API >-------------------------------");
System.out.println();
System.out.println(" _____ _ _ _____ _ _ _ ");
System.out.println(" | ___| (_) | | ___ | ___| (_) __ _ | |__ | |_ ___ _ __ ");
System.out.println(" | |_ | | | | / _ \\ | |_ | | / _ | | '_ \\ | __| / _ \\ | '__|");
System.out.println(" | _| | | | | | __/ | _| | | | (_| | | | | | | |_ | __/ | | ");
System.out.println(" |_| |_| |_| \\___| |_| |_| \\__, | |_| |_| \\__| \\___| |_| ");
System.out.println(" |___/ ");
System.out.println(" Version 0.2 Last updated at 03.11.20 ");
System.out.println(" Developed by Gimleux, Valentin, Open-Schnick. ");
System.out.println(" Development Blog: https://filefighter.github.io ");
System.out.println(" The code can be found at: https://www.github.com/filefighter ");
System.out.println(" Running on http://localhost:" + serverPort);
System.out.println();
System.out.println("-------------------------------< REST API >-------------------------------");
System.out.println();
};
}

@Bean
CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {

Expand All @@ -32,7 +64,7 @@ CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemReposit

@Bean
@Profile("prod")
CommandLineRunner initUserDataBase(UserRepository repository) {
CommandLineRunner initUserDataBaseProd(UserRepository repository) {

//Note: when the admin user changes his/her password, a new refreshToken will be created.
return args -> {
Expand All @@ -42,9 +74,57 @@ CommandLineRunner initUserDataBase(UserRepository repository) {
.username("admin")
.password("admin")
.refreshToken("refreshToken1234")
.roleIds(new long[]{0, 1})
.groupIds(new long[]{0, 1})
.build()));
LOG.info("Loading Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
LOG.info("Inserting Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
};
}

@Bean
@Profile("dev")
CommandLineRunner initUserDataBaseDev(UserRepository repository) {

return args -> {
LOG.info("Preloading default users: " +
repository.save(UserEntity
.builder()
.userId(0)
.username("user")
.password("1234")
.refreshToken("rft1234")
.groupIds(new long[]{0})
.build()) +
repository.save(UserEntity
.builder()
.userId(1)
.username("user1")
.password("12345")
.refreshToken("rft")
.groupIds(new long[]{-1})
.build()));
LOG.info("Inserting Users" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
};
}

@Bean
@Profile("dev")
CommandLineRunner initAccessTokenDataBaseDev(AccessTokenRepository repository) {

return args -> {
LOG.info("Preloading default tokens: " +
repository.save(AccessTokenEntity
.builder()
.userId(0)
.value("token")
.validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
.build()) +
repository.save(AccessTokenEntity
.builder()
.userId(1)
.value("token1234")
.validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
.build()));
LOG.info("Inserting token" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.filefighter.rest.domain.common;

public interface DtoServiceInterface<D,E> {
D createDto(E entity);
E findEntity(D dto);
}
8 changes: 8 additions & 0 deletions src/main/java/de/filefighter/rest/domain/common/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.filefighter.rest.domain.common;

public class Utils {

public static boolean stringIsValid(String s){
return !(null == s || s.isEmpty() || s.isBlank());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import lombok.Data;

@Data
@Builder(builderMethodName = "create")
@Builder
public class FileSystemItemUpdate {
private String name;
private FileSystemType type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.Getter;

@Getter
@Builder(buildMethodName = "create")
@Builder
public class FolderContents {
private final Folder[] folders;
private final File[] files;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

@Data
@Document(collection = "file")
@Builder(buildMethodName = "create")
@Builder
public class FileSystemEntity {
@MongoId private String _id;
private long id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public SystemHealth getCurrentSystemHealthInfo(){
return SystemHealth.builder()
.uptimeInSeconds(currentEpoch - serverStartedAt)
.userCount(userBusinessService.getUserCount())
.create();
.build();
}

public long getCurrentEpochSeconds(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

@Getter
@Builder(buildMethodName = "create")
@Builder
public class SystemHealth {
private final long uptimeInSeconds;
private final long userCount;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,80 @@
package de.filefighter.rest.domain.token.business;

import de.filefighter.rest.domain.token.data.dto.AccessToken;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
import de.filefighter.rest.domain.user.data.dto.User;
import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.UUID;

import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX;
import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX;
import static de.filefighter.rest.domain.common.Utils.stringIsValid;

@Service
public class AccessTokenBusinessService {

private final AccessTokenRepository accessTokenRepository;
private final AccessTokenDtoService accessTokenDtoService;

public static final long ACCESS_TOKEN_DURATION_IN_SECONDS = 3600L;
public static final long ACCESS_TOKEN_SAFETY_MARGIN = 5L;

public AccessTokenBusinessService(AccessTokenRepository accessTokenRepository, AccessTokenDtoService accessTokenDtoService) {
this.accessTokenRepository = accessTokenRepository;
this.accessTokenDtoService = accessTokenDtoService;
}

public AccessToken getValidAccessTokenForUser(User user) {
AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserId(user.getId());
long currentTimeSeconds = Instant.now().getEpochSecond();

if (null == accessTokenEntity) {
accessTokenEntity = AccessTokenEntity
.builder()
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
.value(this.generateRandomTokenValue())
.userId(user.getId())
.build();
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
} else {
if (currentTimeSeconds + ACCESS_TOKEN_SAFETY_MARGIN > accessTokenEntity.getValidUntil()) {
accessTokenRepository.delete(accessTokenEntity);
accessTokenEntity = AccessTokenEntity
.builder()
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
.value(this.generateRandomTokenValue())
.userId(user.getId())
.build();
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
}
}

return accessTokenDtoService.createDto(accessTokenEntity);
}

public AccessToken findAccessTokenByValueAndUserId(String accessTokenValue, long userId) {
if (!stringIsValid(accessTokenValue))
throw new IllegalArgumentException("Value of AccessToken was not valid.");

AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(userId, accessTokenValue);
if (null == accessTokenEntity)
throw new UserNotAuthenticatedException(userId);

return accessTokenDtoService.createDto(accessTokenEntity);
}

public String generateRandomTokenValue() {
return UUID.randomUUID().toString();
}

public String checkBearerHeader(String accessTokenValue) {
if (!accessTokenValue.matches("^" + AUTHORIZATION_BEARER_PREFIX + "[^\\s](.*)$"))
throw new UserNotAuthenticatedException("Header does not contain '" + AUTHORIZATION_BEARER_PREFIX + "', or format is invalid.");
return accessTokenValue.split(AUTHORIZATION_BEARER_PREFIX)[1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.filefighter.rest.domain.token.business;

import de.filefighter.rest.domain.common.DtoServiceInterface;
import de.filefighter.rest.domain.token.data.dto.AccessToken;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class AccessTokenDtoService implements DtoServiceInterface<AccessToken, AccessTokenEntity> {

private final AccessTokenRepository accessTokenRepository;

public AccessTokenDtoService(AccessTokenRepository accessTokenRepository) {
this.accessTokenRepository = accessTokenRepository;
}

@Override
public AccessToken createDto(AccessTokenEntity entity) {
return AccessToken
.builder()
.token(entity.getValue())
.userId(entity.getUserId())
.validUntil(entity.getValidUntil())
.build();
}

@Override
public AccessTokenEntity findEntity(AccessToken dto) {
AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(dto.getUserId(), dto.getToken());
if (null == accessTokenEntity)
throw new AccessTokenNotFoundException("AccessTokenEntity does not exist for AccessToken: "+ dto);

return accessTokenEntity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ public class AccessTokenEntity {
private String value;
private long userId;
private long validUntil;

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
public interface AccessTokenRepository extends MongoRepository<AccessTokenEntity, String> {
AccessTokenEntity findByUserId(long userId);
AccessTokenEntity findByValue(String value);
void deleteByUserId(long userId);
AccessTokenEntity findByUserIdAndValue(long userId, String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class TokenNotFoundAdvise {
public class AccessTokenNotFoundAdvise {
@ResponseBody
@ExceptionHandler(TokenNotFoundException.class)
@ExceptionHandler(AccessTokenNotFoundException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)

ResponseEntity<ServerResponse> tokenNotFoundAdvise(TokenNotFoundException ex) {
ResponseEntity<ServerResponse> tokenNotFoundAdvise(AccessTokenNotFoundException ex) {
LoggerFactory.getLogger(UserAlreadyExistsAdvise.class).warn(ex.getMessage());
return new ResponseEntity<>(new ServerResponse("Denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(new ServerResponse("denied", ex.getMessage()), HttpStatus.BAD_REQUEST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.filefighter.rest.domain.token.exceptions;

public class AccessTokenNotFoundException extends RuntimeException {

public AccessTokenNotFoundException(String reason) {
super(reason);
}
}

This file was deleted.

Loading