Skip to content
This repository was archived by the owner on Apr 5, 2024. It is now read-only.

Commit 59a6ab3

Browse files
authored
FF-89 Implemented user auth. logic. (#9)
* Added Steps, and fixed feature * Added default users for dev, fixed wrong param names "roles" * FF-89 implemented logic, fixed cucumber tests. * Implemented requested changes by @qvalentin (#9) * Fixed test. * Added UnitTests (1/2) - Some Cleanup * Added UnitTests (2/2) - Cleanup, fixes
2 parents b18ebff + a83a913 commit 59a6ab3

File tree

47 files changed

+1121
-240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1121
-240
lines changed

.run/Run Cucumber Tests.run.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Run Cucumber Tests" type="JUnit" factoryName="JUnit">
3+
<useClassPathOnly />
4+
<option name="PACKAGE_NAME" value="de.filefighter.rest.cucumber" />
5+
<option name="MAIN_CLASS_NAME" value="" />
6+
<option name="METHOD_NAME" value="" />
7+
<option name="TEST_OBJECT" value="package" />
8+
<option name="PARAMETERS" value="" />
9+
<option name="TEST_SEARCH_SCOPE">
10+
<value defaultName="wholeProject" />
11+
</option>
12+
<method v="2">
13+
<option name="Make" enabled="true" />
14+
</method>
15+
</configuration>
16+
</component>

src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,53 @@
11
package de.filefighter.rest.configuration;
22

33
import de.filefighter.rest.domain.filesystem.data.persistance.FileSystemRepository;
4+
import de.filefighter.rest.domain.token.business.AccessTokenBusinessService;
5+
import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
46
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
57
import de.filefighter.rest.domain.user.data.persistance.UserEntity;
68
import de.filefighter.rest.domain.user.data.persistance.UserRepository;
79
import org.slf4j.Logger;
810
import org.slf4j.LoggerFactory;
11+
import org.springframework.beans.factory.annotation.Value;
912
import org.springframework.boot.CommandLineRunner;
1013
import org.springframework.context.annotation.Bean;
1114
import org.springframework.context.annotation.Configuration;
1215
import org.springframework.context.annotation.Profile;
1316

17+
import java.time.Instant;
18+
1419
@Configuration
1520
public class PrepareDataBase {
1621

22+
@Value("${server.port}")
23+
int serverPort;
24+
1725
private static final Logger LOG = LoggerFactory.getLogger(PrepareDataBase.class);
1826

27+
@Bean
28+
@Profile({"dev", "prod"})
29+
CommandLineRunner veryImportantFileFighterStartScript() {
30+
return args -> {
31+
System.out.println();
32+
System.out.println("-------------------------------< REST API >-------------------------------");
33+
System.out.println();
34+
System.out.println(" _____ _ _ _____ _ _ _ ");
35+
System.out.println(" | ___| (_) | | ___ | ___| (_) __ _ | |__ | |_ ___ _ __ ");
36+
System.out.println(" | |_ | | | | / _ \\ | |_ | | / _ | | '_ \\ | __| / _ \\ | '__|");
37+
System.out.println(" | _| | | | | | __/ | _| | | | (_| | | | | | | |_ | __/ | | ");
38+
System.out.println(" |_| |_| |_| \\___| |_| |_| \\__, | |_| |_| \\__| \\___| |_| ");
39+
System.out.println(" |___/ ");
40+
System.out.println(" Version 0.2 Last updated at 03.11.20 ");
41+
System.out.println(" Developed by Gimleux, Valentin, Open-Schnick. ");
42+
System.out.println(" Development Blog: https://filefighter.github.io ");
43+
System.out.println(" The code can be found at: https://www.github.com/filefighter ");
44+
System.out.println(" Running on http://localhost:" + serverPort);
45+
System.out.println();
46+
System.out.println("-------------------------------< REST API >-------------------------------");
47+
System.out.println();
48+
};
49+
}
50+
1951
@Bean
2052
CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
2153

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

3365
@Bean
3466
@Profile("prod")
35-
CommandLineRunner initUserDataBase(UserRepository repository) {
67+
CommandLineRunner initUserDataBaseProd(UserRepository repository) {
3668

3769
//Note: when the admin user changes his/her password, a new refreshToken will be created.
3870
return args -> {
@@ -42,9 +74,57 @@ CommandLineRunner initUserDataBase(UserRepository repository) {
4274
.username("admin")
4375
.password("admin")
4476
.refreshToken("refreshToken1234")
45-
.roleIds(new long[]{0, 1})
77+
.groupIds(new long[]{0, 1})
4678
.build()));
47-
LOG.info("Loading Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
79+
LOG.info("Inserting Users" + (repository.findAll().size() == 1 ? " was successful." : " failed."));
80+
};
81+
}
82+
83+
@Bean
84+
@Profile("dev")
85+
CommandLineRunner initUserDataBaseDev(UserRepository repository) {
86+
87+
return args -> {
88+
LOG.info("Preloading default users: " +
89+
repository.save(UserEntity
90+
.builder()
91+
.userId(0)
92+
.username("user")
93+
.password("1234")
94+
.refreshToken("rft1234")
95+
.groupIds(new long[]{0})
96+
.build()) +
97+
repository.save(UserEntity
98+
.builder()
99+
.userId(1)
100+
.username("user1")
101+
.password("12345")
102+
.refreshToken("rft")
103+
.groupIds(new long[]{-1})
104+
.build()));
105+
LOG.info("Inserting Users" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
106+
};
107+
}
108+
109+
@Bean
110+
@Profile("dev")
111+
CommandLineRunner initAccessTokenDataBaseDev(AccessTokenRepository repository) {
112+
113+
return args -> {
114+
LOG.info("Preloading default tokens: " +
115+
repository.save(AccessTokenEntity
116+
.builder()
117+
.userId(0)
118+
.value("token")
119+
.validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
120+
.build()) +
121+
repository.save(AccessTokenEntity
122+
.builder()
123+
.userId(1)
124+
.value("token1234")
125+
.validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS)
126+
.build()));
127+
LOG.info("Inserting token" + (repository.findAll().size() == 2 ? " was successful." : " failed."));
48128
};
49129
}
50130
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package de.filefighter.rest.domain.common;
2+
3+
public interface DtoServiceInterface<D,E> {
4+
D createDto(E entity);
5+
E findEntity(D dto);
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package de.filefighter.rest.domain.common;
2+
3+
public class Utils {
4+
5+
public static boolean stringIsValid(String s){
6+
return !(null == s || s.isEmpty() || s.isBlank());
7+
}
8+
}

src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import lombok.Data;
66

77
@Data
8-
@Builder(builderMethodName = "create")
8+
@Builder
99
public class FileSystemItemUpdate {
1010
private String name;
1111
private FileSystemType type;

src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import lombok.Getter;
55

66
@Getter
7-
@Builder(buildMethodName = "create")
7+
@Builder
88
public class FolderContents {
99
private final Folder[] folders;
1010
private final File[] files;

src/main/java/de/filefighter/rest/domain/filesystem/data/persistance/FileSystemEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
@Data
99
@Document(collection = "file")
10-
@Builder(buildMethodName = "create")
10+
@Builder
1111
public class FileSystemEntity {
1212
@MongoId private String _id;
1313
private long id;

src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public SystemHealth getCurrentSystemHealthInfo(){
2222
return SystemHealth.builder()
2323
.uptimeInSeconds(currentEpoch - serverStartedAt)
2424
.userCount(userBusinessService.getUserCount())
25-
.create();
25+
.build();
2626
}
2727

2828
public long getCurrentEpochSeconds(){

src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
@Getter
11-
@Builder(buildMethodName = "create")
11+
@Builder
1212
public class SystemHealth {
1313
private final long uptimeInSeconds;
1414
private final long userCount;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,80 @@
11
package de.filefighter.rest.domain.token.business;
22

3+
import de.filefighter.rest.domain.token.data.dto.AccessToken;
4+
import de.filefighter.rest.domain.token.data.persistance.AccessTokenEntity;
5+
import de.filefighter.rest.domain.token.data.persistance.AccessTokenRepository;
6+
import de.filefighter.rest.domain.token.exceptions.AccessTokenNotFoundException;
7+
import de.filefighter.rest.domain.user.data.dto.User;
8+
import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException;
39
import org.springframework.stereotype.Service;
410

11+
import java.time.Instant;
12+
import java.util.UUID;
13+
14+
import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BASIC_PREFIX;
15+
import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX;
16+
import static de.filefighter.rest.domain.common.Utils.stringIsValid;
17+
518
@Service
619
public class AccessTokenBusinessService {
20+
21+
private final AccessTokenRepository accessTokenRepository;
22+
private final AccessTokenDtoService accessTokenDtoService;
23+
724
public static final long ACCESS_TOKEN_DURATION_IN_SECONDS = 3600L;
25+
public static final long ACCESS_TOKEN_SAFETY_MARGIN = 5L;
26+
27+
public AccessTokenBusinessService(AccessTokenRepository accessTokenRepository, AccessTokenDtoService accessTokenDtoService) {
28+
this.accessTokenRepository = accessTokenRepository;
29+
this.accessTokenDtoService = accessTokenDtoService;
30+
}
31+
32+
public AccessToken getValidAccessTokenForUser(User user) {
33+
AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserId(user.getId());
34+
long currentTimeSeconds = Instant.now().getEpochSecond();
35+
36+
if (null == accessTokenEntity) {
37+
accessTokenEntity = AccessTokenEntity
38+
.builder()
39+
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
40+
.value(this.generateRandomTokenValue())
41+
.userId(user.getId())
42+
.build();
43+
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
44+
} else {
45+
if (currentTimeSeconds + ACCESS_TOKEN_SAFETY_MARGIN > accessTokenEntity.getValidUntil()) {
46+
accessTokenRepository.delete(accessTokenEntity);
47+
accessTokenEntity = AccessTokenEntity
48+
.builder()
49+
.validUntil(currentTimeSeconds + ACCESS_TOKEN_DURATION_IN_SECONDS)
50+
.value(this.generateRandomTokenValue())
51+
.userId(user.getId())
52+
.build();
53+
accessTokenEntity = accessTokenRepository.save(accessTokenEntity);
54+
}
55+
}
56+
57+
return accessTokenDtoService.createDto(accessTokenEntity);
58+
}
59+
60+
public AccessToken findAccessTokenByValueAndUserId(String accessTokenValue, long userId) {
61+
if (!stringIsValid(accessTokenValue))
62+
throw new IllegalArgumentException("Value of AccessToken was not valid.");
63+
64+
AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(userId, accessTokenValue);
65+
if (null == accessTokenEntity)
66+
throw new UserNotAuthenticatedException(userId);
67+
68+
return accessTokenDtoService.createDto(accessTokenEntity);
69+
}
70+
71+
public String generateRandomTokenValue() {
72+
return UUID.randomUUID().toString();
73+
}
74+
75+
public String checkBearerHeader(String accessTokenValue) {
76+
if (!accessTokenValue.matches("^" + AUTHORIZATION_BEARER_PREFIX + "[^\\s](.*)$"))
77+
throw new UserNotAuthenticatedException("Header does not contain '" + AUTHORIZATION_BEARER_PREFIX + "', or format is invalid.");
78+
return accessTokenValue.split(AUTHORIZATION_BEARER_PREFIX)[1];
79+
}
880
}

0 commit comments

Comments
 (0)