Steffen Nitschke
4 years ago
32 changed files with 1444 additions and 4 deletions
-
16Multi-Chess.xml
-
12build.gradle
-
9fh.fd.ci.server/build.gradle
-
45fh.fd.ci.server/src/main/java/de/fd/fh/ServerApp.java
-
46fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Access.java
-
28fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessContextEventListener.java
-
58fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessRepository.java
-
152fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java
-
62fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java
-
6fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Role.java
-
13fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java
-
12fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java
-
104fh.fd.ci.server/src/main/java/de/fd/fh/server/access/web/AccessController.java
-
26fh.fd.ci.server/src/main/java/de/fd/fh/server/user/User.java
-
43fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserContextEventListener.java
-
25fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserId.java
-
52fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserRepository.java
-
48fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserService.java
-
18fh.fd.ci.server/src/main/java/de/fd/fh/server/user/events/ChangePasswordEvent.java
-
13fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/ChangeUserRequest.java
-
89fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserController.java
-
13fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserRequest.java
-
36fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessContextEventListenerTest.java
-
42fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessRepositoryTest.java
-
245fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java
-
31fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessTokenTest.java
-
51fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserContextEventListenerTest.java
-
40fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserRepositoryTest.java
-
84fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserServiceTest.java
-
6fh.fd.ci.shared/src/main/java/de/fd/fh/shared/Utils.java
-
11fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/LoginRequest.java
-
12fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/RegistrateRequest.java
@ -0,0 +1,16 @@ |
|||||
|
<code_scheme name="Multi-Chess" version="173"> |
||||
|
<option name="FORMATTER_TAGS_ENABLED" value="true" /> |
||||
|
<codeStyleSettings language="JAVA"> |
||||
|
<option name="BRACE_STYLE" value="2" /> |
||||
|
<option name="CLASS_BRACE_STYLE" value="2" /> |
||||
|
<option name="METHOD_BRACE_STYLE" value="2" /> |
||||
|
<option name="LAMBDA_BRACE_STYLE" value="2" /> |
||||
|
<option name="ELSE_ON_NEW_LINE" value="true" /> |
||||
|
<option name="CATCH_ON_NEW_LINE" value="true" /> |
||||
|
<option name="FINALLY_ON_NEW_LINE" value="true" /> |
||||
|
<option name="IF_BRACE_FORCE" value="3" /> |
||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" /> |
||||
|
<option name="WHILE_BRACE_FORCE" value="3" /> |
||||
|
<option name="FOR_BRACE_FORCE" value="3" /> |
||||
|
</codeStyleSettings> |
||||
|
</code_scheme> |
@ -1,12 +1,57 @@ |
|||||
package de.fd.fh; |
package de.fd.fh; |
||||
|
|
||||
|
import de.fd.fh.server.access.AccessContextEventListener; |
||||
|
import de.fd.fh.server.access.AccessRepository; |
||||
|
import de.fd.fh.server.access.AccessService; |
||||
|
import de.fd.fh.server.access.web.AccessController; |
||||
|
import de.fd.fh.server.user.UserContextEventListener; |
||||
|
import de.fd.fh.server.user.web.UserController; |
||||
|
import de.fd.fh.server.user.UserRepository; |
||||
|
import de.fd.fh.server.user.UserService; |
||||
|
|
||||
|
|
||||
|
import java.util.HashSet; |
||||
|
import java.util.Observable; |
||||
|
import java.util.Observer; |
||||
|
import java.util.Set; |
||||
|
|
||||
import static spark.Spark.*; |
import static spark.Spark.*; |
||||
|
|
||||
public class ServerApp |
public class ServerApp |
||||
{ |
{ |
||||
|
private static AccessRepository accessRepository; |
||||
|
private static UserRepository userRepository; |
||||
|
|
||||
|
private static final Set<Observer> listeners = new HashSet<>(); |
||||
|
|
||||
public static void main(String[] args) |
public static void main(String[] args) |
||||
{ |
{ |
||||
|
initRepositories(); |
||||
|
|
||||
|
initListeners(); |
||||
|
|
||||
|
new AccessController((AccessService) addListeners(new AccessService(accessRepository))); |
||||
|
new UserController((UserService) addListeners(new UserService(userRepository))); |
||||
|
|
||||
get("/hello", (req, res) -> "Hello World"); |
get("/hello", (req, res) -> "Hello World"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
private static Object addListeners(Observable service) |
||||
|
{ |
||||
|
listeners.forEach(service::addObserver); |
||||
|
|
||||
|
return service; |
||||
|
} |
||||
|
|
||||
|
private static void initListeners() |
||||
|
{ |
||||
|
listeners.add(new AccessContextEventListener(accessRepository)); |
||||
|
listeners.add(new UserContextEventListener(userRepository)); |
||||
|
} |
||||
|
|
||||
|
private static void initRepositories() { |
||||
|
accessRepository = new AccessRepository(); |
||||
|
userRepository = new UserRepository(); |
||||
} |
} |
||||
} |
} |
@ -0,0 +1,46 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import dev.morphia.annotations.Embedded; |
||||
|
import dev.morphia.annotations.Entity; |
||||
|
import dev.morphia.annotations.Id; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
@Entity("login") |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
@Getter |
||||
|
public class Access |
||||
|
{ |
||||
|
@Id |
||||
|
private String _id; |
||||
|
|
||||
|
private String name; |
||||
|
|
||||
|
private String password; |
||||
|
|
||||
|
@Embedded |
||||
|
private UserId userId; |
||||
|
|
||||
|
@Embedded |
||||
|
private AccessToken token; |
||||
|
|
||||
|
private Role role; |
||||
|
|
||||
|
void removeToken() |
||||
|
{ |
||||
|
this.token = null; |
||||
|
} |
||||
|
|
||||
|
void setToken(final AccessToken token) |
||||
|
{ |
||||
|
this.token = token; |
||||
|
} |
||||
|
|
||||
|
void updatePassword(final String newPassword) |
||||
|
{ |
||||
|
this.password = newPassword; |
||||
|
} |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.events.ChangePasswordEvent; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
import java.util.Observable; |
||||
|
import java.util.Observer; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
public class AccessContextEventListener implements Observer |
||||
|
{ |
||||
|
private final AccessRepository accessRepository; |
||||
|
|
||||
|
@Override |
||||
|
public void update(Observable observable, Object o) |
||||
|
{ |
||||
|
if(o instanceof ChangePasswordEvent) |
||||
|
{ |
||||
|
final ChangePasswordEvent event = (ChangePasswordEvent) o; |
||||
|
|
||||
|
final Access access = accessRepository.findByUserId(event.getUserId()); |
||||
|
|
||||
|
access.updatePassword(event.getNewPassword()); |
||||
|
|
||||
|
accessRepository.save(access); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import com.mongodb.MongoClient; |
||||
|
import com.mongodb.WriteResult; |
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import dev.morphia.Datastore; |
||||
|
import dev.morphia.Key; |
||||
|
import dev.morphia.Morphia; |
||||
|
|
||||
|
public class AccessRepository |
||||
|
{ |
||||
|
private final Datastore datastore; |
||||
|
|
||||
|
public AccessRepository() |
||||
|
{ |
||||
|
System.out.println("AccessRepo"); |
||||
|
final Morphia morphia = new Morphia(); |
||||
|
|
||||
|
morphia.mapPackage("de.fd.fh.server.access"); |
||||
|
|
||||
|
this.datastore = morphia.createDatastore(new MongoClient(), "smartwarfare"); |
||||
|
datastore.ensureIndexes(); |
||||
|
} |
||||
|
|
||||
|
AccessRepository(Datastore datastore) |
||||
|
{ |
||||
|
this.datastore = datastore; |
||||
|
} |
||||
|
|
||||
|
public Key<Access> save(final Access access) |
||||
|
{ |
||||
|
return datastore.save(access); |
||||
|
} |
||||
|
|
||||
|
Access findByUserName(final String name) |
||||
|
{ |
||||
|
return datastore.createQuery(Access.class) |
||||
|
.field("name").equal(name).first(); |
||||
|
} |
||||
|
|
||||
|
Access findByToken(final String token) |
||||
|
{ |
||||
|
return datastore.createQuery(Access.class) |
||||
|
.field("token.token").equal(token).first(); |
||||
|
} |
||||
|
|
||||
|
Access findByUserId(final UserId userId) |
||||
|
{ |
||||
|
return datastore.createQuery(Access.class) |
||||
|
.field("userId.identifier").equal(userId.getIdentifier()).first(); |
||||
|
} |
||||
|
|
||||
|
WriteResult deleteLoginByUserId(final UserId userId) |
||||
|
{ |
||||
|
return datastore.delete(datastore.createQuery(Access.class) |
||||
|
.field("userId.identifier").equal(userId.getIdentifier()).first()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.access.events.AccountCreatedEvent; |
||||
|
import de.fd.fh.server.access.events.AccountDeletedEvent; |
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import de.fd.fh.shared.network.messages.LoginRequest; |
||||
|
import de.fd.fh.shared.network.messages.RegistrateRequest; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.bson.types.ObjectId; |
||||
|
|
||||
|
import java.util.Base64; |
||||
|
import java.util.Observable; |
||||
|
|
||||
|
import static spark.Spark.halt; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
public class AccessService extends Observable |
||||
|
{ |
||||
|
private final AccessRepository accessRepository; |
||||
|
|
||||
|
public AccessToken before(final String path, final String token) { |
||||
|
System.out.println("Pfad: " + path); |
||||
|
if (!(path.equals("/accounts/login") |
||||
|
|| path.equals("/accounts/registrate") |
||||
|
)) |
||||
|
{ |
||||
|
final AccessToken accessToken = authenticate(token); |
||||
|
|
||||
|
if (accessToken == null) |
||||
|
{ |
||||
|
halt(401); |
||||
|
} |
||||
|
return accessToken; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private AccessToken authenticate(final String bearerToken) |
||||
|
{ |
||||
|
return accessRepository.findByToken(bearerToken.substring("Bearer ".length())).getToken(); |
||||
|
} |
||||
|
|
||||
|
public boolean createPlayer(RegistrateRequest message) |
||||
|
{ |
||||
|
System.out.println("createPlayer: " + message); |
||||
|
|
||||
|
if (userNameDoesNotExist(message.getUserName())) |
||||
|
{ |
||||
|
System.out.println("Name does exist."); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
final Access access = new Access( |
||||
|
new ObjectId().toHexString(), |
||||
|
message.getUserName(), |
||||
|
message.getPassword(), |
||||
|
UserId.random(), |
||||
|
null, |
||||
|
Role.USER |
||||
|
); |
||||
|
|
||||
|
accessRepository.save(access); |
||||
|
|
||||
|
setChanged(); |
||||
|
notifyObservers(new AccountCreatedEvent(access.getName(), |
||||
|
access.getUserId())); |
||||
|
|
||||
|
System.out.println("DBLogin: " + access); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private boolean userNameDoesNotExist(final String name) |
||||
|
{ |
||||
|
final Access user = accessRepository.findByUserName(name); |
||||
|
return user != null; |
||||
|
} |
||||
|
|
||||
|
public boolean logout(final String header) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
System.out.println("logout " + header); |
||||
|
|
||||
|
final Access access = accessRepository.findByToken(header.substring("Bearer ".length())); |
||||
|
|
||||
|
access.removeToken(); |
||||
|
|
||||
|
accessRepository.save(access); |
||||
|
|
||||
|
return true; |
||||
|
} catch (Exception e) |
||||
|
{ |
||||
|
e.printStackTrace(); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public LoginRequest authorization(final String header) |
||||
|
{ |
||||
|
System.out.println("authorization"); |
||||
|
final String auth = header.substring("Basic ".length()); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
byte[] message = Base64.getDecoder().decode(auth); |
||||
|
|
||||
|
String messageStr = new String(message); |
||||
|
String[] user_password = messageStr.split(":"); |
||||
|
|
||||
|
final Access access = accessRepository.findByUserName(user_password[0]); |
||||
|
|
||||
|
System.out.println(access.getName()); |
||||
|
if (user_password[1].equals(access.getPassword())) |
||||
|
{ |
||||
|
access.setToken(AccessToken.of(access)); |
||||
|
accessRepository.save(access); |
||||
|
|
||||
|
final LoginRequest loginRequest = new LoginRequest(); |
||||
|
loginRequest.setUserId(access.getUserId().getIdentifier()); |
||||
|
loginRequest.setToken(access.getToken().getToken()); |
||||
|
loginRequest.setName(access.getName()); |
||||
|
|
||||
|
return loginRequest; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} catch (Exception e) |
||||
|
{ |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public boolean deleteAccount(final UserId userId, final AccessToken token) |
||||
|
{ |
||||
|
if (!token.getUserId().getIdentifier() |
||||
|
.equals(userId.getIdentifier())) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
if (accessRepository.deleteLoginByUserId(userId).wasAcknowledged()) |
||||
|
{ |
||||
|
setChanged(); |
||||
|
notifyObservers(new AccountDeletedEvent(userId)); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import dev.morphia.annotations.Embedded; |
||||
|
import dev.morphia.annotations.PrePersist; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
@Embedded |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
@Getter |
||||
|
public class AccessToken |
||||
|
{ |
||||
|
private String token; |
||||
|
|
||||
|
private LocalDateTime createdDate; |
||||
|
|
||||
|
private Role role; |
||||
|
|
||||
|
@Embedded |
||||
|
private UserId userId; |
||||
|
|
||||
|
static AccessToken of(final Access access) |
||||
|
{ |
||||
|
return new AccessToken( |
||||
|
generateToken(), |
||||
|
LocalDateTime.now(), |
||||
|
access.getRole(), |
||||
|
access.getUserId() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@PrePersist |
||||
|
void prePersist() |
||||
|
{ |
||||
|
this.createdDate = LocalDateTime.now(); |
||||
|
} |
||||
|
|
||||
|
private static String generateToken() |
||||
|
{ |
||||
|
final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
||||
|
final String lower = upper.toLowerCase(); |
||||
|
final String numbers = "0123456789"; |
||||
|
final String alphabet = upper + lower + numbers; |
||||
|
|
||||
|
System.out.println("generate Security Token."); |
||||
|
|
||||
|
Random random = new Random(); |
||||
|
StringBuilder generatedString = new StringBuilder(); |
||||
|
for (int i = 0; i < 64; i++) { |
||||
|
generatedString.append(alphabet.charAt(random.nextInt(alphabet.length()))); |
||||
|
} |
||||
|
|
||||
|
System.out.println("Token: " + generatedString); |
||||
|
return generatedString.toString(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
public enum Role |
||||
|
{ |
||||
|
ADMIN, USER |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package de.fd.fh.server.access.events; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import lombok.Getter; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
@Getter |
||||
|
public class AccountCreatedEvent |
||||
|
{ |
||||
|
private final String name; |
||||
|
private final UserId userId; |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
package de.fd.fh.server.access.events; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import lombok.Getter; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
@Getter |
||||
|
public class AccountDeletedEvent |
||||
|
{ |
||||
|
private final UserId userId; |
||||
|
} |
@ -0,0 +1,104 @@ |
|||||
|
package de.fd.fh.server.access.web; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import de.fd.fh.server.access.AccessService; |
||||
|
import de.fd.fh.server.access.AccessToken; |
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import de.fd.fh.shared.Utils; |
||||
|
import de.fd.fh.shared.network.messages.LoginRequest; |
||||
|
import de.fd.fh.shared.network.messages.RegistrateRequest; |
||||
|
|
||||
|
import static spark.Spark.*; |
||||
|
|
||||
|
public class AccessController |
||||
|
{ |
||||
|
private final ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
public AccessController(final AccessService service) |
||||
|
{ |
||||
|
before("/*", |
||||
|
(req, res) -> |
||||
|
{ |
||||
|
final String path = req.pathInfo(); |
||||
|
final String token = req.headers(Utils.AUTHENTICATION_HEADER); |
||||
|
|
||||
|
final AccessToken accessToken = service.before(path, token); |
||||
|
|
||||
|
req.session().attribute("userId", |
||||
|
accessToken); |
||||
|
}); |
||||
|
|
||||
|
post("/accounts/registrate", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final RegistrateRequest message = |
||||
|
objectMapper.readValue(request.body(), RegistrateRequest.class); |
||||
|
|
||||
|
if (service.createPlayer(message)) |
||||
|
{ |
||||
|
response.status(201); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(400); |
||||
|
} |
||||
|
return response; |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
post("/accounts/login", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final String header = request.headers(Utils.AUTHENTICATION_HEADER); |
||||
|
|
||||
|
final LoginRequest login = service.authorization(header); |
||||
|
|
||||
|
if (login == null) |
||||
|
{ |
||||
|
response.status(401); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(200); |
||||
|
response.type("application/json"); |
||||
|
response.body(objectMapper.writeValueAsString(login)); |
||||
|
} |
||||
|
return response; |
||||
|
}); |
||||
|
|
||||
|
post("/accounts/logout", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final String token = request.headers(Utils.AUTHENTICATION_HEADER); |
||||
|
|
||||
|
if (service.logout(token)) |
||||
|
{ |
||||
|
response.status(200); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(400); |
||||
|
} |
||||
|
|
||||
|
return response; |
||||
|
}); |
||||
|
|
||||
|
delete("/accounts/:player_id", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final UserId userId = UserId.of(request.params(":player_id")); |
||||
|
final AccessToken token = request.session().attribute("userId"); |
||||
|
|
||||
|
if (service.deleteAccount(userId, token)) |
||||
|
{ |
||||
|
response.status(200); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(400); |
||||
|
} |
||||
|
|
||||
|
return response; |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import lombok.*; |
||||
|
|
||||
|
@AllArgsConstructor |
||||
|
@Getter |
||||
|
public class User { |
||||
|
|
||||
|
private final UserId id; |
||||
|
|
||||
|
private String name; |
||||
|
|
||||
|
public static User of(String name) |
||||
|
{ |
||||
|
return new User(null, name); |
||||
|
} |
||||
|
|
||||
|
public void rename(String name) |
||||
|
{ |
||||
|
if (name == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
this.name = name; |
||||
|
} |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import de.fd.fh.server.access.events.AccountCreatedEvent; |
||||
|
import de.fd.fh.server.access.events.AccountDeletedEvent; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
import java.util.Observable; |
||||
|
import java.util.Observer; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
public class UserContextEventListener implements Observer |
||||
|
{ |
||||
|
private final UserRepository userRepository; |
||||
|
|
||||
|
@Override |
||||
|
public void update( |
||||
|
final Observable observable, |
||||
|
final Object event) |
||||
|
{ |
||||
|
System.out.println("UserContextEventListener " + event); |
||||
|
if (event instanceof AccountCreatedEvent) { |
||||
|
handleAccountCreatedEvent((AccountCreatedEvent) event); |
||||
|
} |
||||
|
if (event instanceof AccountDeletedEvent) { |
||||
|
handleAccountDeletedEvent((AccountDeletedEvent) event); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void handleAccountDeletedEvent(final AccountDeletedEvent event) |
||||
|
{ |
||||
|
userRepository.deleteUserById(event.getUserId()); |
||||
|
} |
||||
|
|
||||
|
private void handleAccountCreatedEvent(final AccountCreatedEvent event) |
||||
|
{ |
||||
|
System.out.println("handleAccountCreatedEvent " + event); |
||||
|
final User user = new User(event.getUserId(), event.getName()); |
||||
|
System.out.println("User: " + user); |
||||
|
|
||||
|
userRepository.save(user); |
||||
|
System.out.println("UserId: " + user.getId()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import dev.morphia.annotations.Embedded; |
||||
|
import lombok.*; |
||||
|
import org.bson.types.ObjectId; |
||||
|
|
||||
|
@Getter |
||||
|
@Embedded |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE) |
||||
|
@EqualsAndHashCode(of = {"identifier"}) |
||||
|
public class UserId |
||||
|
{ |
||||
|
private String identifier; |
||||
|
|
||||
|
public static UserId of(final String identifier) |
||||
|
{ |
||||
|
return new UserId(identifier); |
||||
|
} |
||||
|
|
||||
|
public static UserId random() |
||||
|
{ |
||||
|
return new UserId(new ObjectId().toHexString()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import com.mongodb.MongoClient; |
||||
|
import com.mongodb.WriteResult; |
||||
|
import dev.morphia.Datastore; |
||||
|
import dev.morphia.Key; |
||||
|
import dev.morphia.Morphia; |
||||
|
|
||||
|
public class UserRepository { |
||||
|
|
||||
|
private final Datastore datastore; |
||||
|
|
||||
|
public UserRepository() |
||||
|
{ |
||||
|
System.out.println("UserRepo"); |
||||
|
final Morphia morphia = new Morphia(); |
||||
|
|
||||
|
morphia.mapPackage("de.fd.fh.server.user"); |
||||
|
|
||||
|
this.datastore = morphia.createDatastore(new MongoClient(), "smartwarfare"); |
||||
|
datastore.ensureIndexes(); |
||||
|
} |
||||
|
|
||||
|
UserRepository(Datastore datastore) |
||||
|
{ |
||||
|
this.datastore = datastore; |
||||
|
} |
||||
|
|
||||
|
public Key<User> save(final User user) |
||||
|
{ |
||||
|
return datastore.save(user); |
||||
|
} |
||||
|
|
||||
|
public User findUserById(final UserId userId) |
||||
|
{ |
||||
|
return datastore.createQuery(User.class) |
||||
|
.field("_id.identifier").equal(userId.getIdentifier()) |
||||
|
.first(); |
||||
|
} |
||||
|
|
||||
|
public User findUserByName(final String name) |
||||
|
{ |
||||
|
return datastore.createQuery(User.class) |
||||
|
.field("name").equal(name) |
||||
|
.first(); |
||||
|
} |
||||
|
|
||||
|
WriteResult deleteUserById(final UserId userId) |
||||
|
{ |
||||
|
return datastore.delete(findUserById(userId)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import de.fd.fh.server.user.events.ChangePasswordEvent; |
||||
|
import de.fd.fh.server.user.web.ChangeUserRequest; |
||||
|
import de.fd.fh.server.user.web.UserRequest; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
import java.util.Observable; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
public class UserService extends Observable |
||||
|
{ |
||||
|
private final UserRepository userRepository; |
||||
|
|
||||
|
public User changePlayer(final UserId userId, final ChangeUserRequest message) |
||||
|
{ |
||||
|
System.out.println("changePlayer: " + message); |
||||
|
|
||||
|
User user = userRepository.findUserById(userId); |
||||
|
|
||||
|
if (message.getPassword() != null) |
||||
|
{ |
||||
|
setChanged(); |
||||
|
notifyObservers(new ChangePasswordEvent(userId, message.getPassword())); |
||||
|
} |
||||
|
|
||||
|
userRepository.save(user); |
||||
|
|
||||
|
return userRepository.findUserById(userId); |
||||
|
} |
||||
|
|
||||
|
public User getPlayer(final UserId id) |
||||
|
{ |
||||
|
return userRepository.findUserById(id); |
||||
|
} |
||||
|
|
||||
|
public UserRequest getSmallPlayer(final UserId userId) |
||||
|
{ |
||||
|
final User user = userRepository.findUserById(userId); |
||||
|
|
||||
|
if(user == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return new UserRequest(user.getId().getIdentifier(), user.getName()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package de.fd.fh.server.user.events; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
@Getter |
||||
|
public class ChangePasswordEvent |
||||
|
{ |
||||
|
private final String newPassword; |
||||
|
|
||||
|
private final UserId userId; |
||||
|
|
||||
|
public ChangePasswordEvent(final UserId userId, final String password) |
||||
|
{ |
||||
|
this.newPassword = password; |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package de.fd.fh.server.user.web; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
@Getter |
||||
|
public class ChangeUserRequest |
||||
|
{ |
||||
|
private final String name; |
||||
|
|
||||
|
private final String password; |
||||
|
} |
@ -0,0 +1,89 @@ |
|||||
|
package de.fd.fh.server.user.web; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import de.fd.fh.server.access.AccessToken; |
||||
|
import de.fd.fh.server.user.User; |
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import de.fd.fh.server.user.UserService; |
||||
|
|
||||
|
import static spark.Spark.get; |
||||
|
import static spark.Spark.post; |
||||
|
|
||||
|
public class UserController |
||||
|
{ |
||||
|
private ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
public UserController(final UserService service) |
||||
|
{ |
||||
|
post("/users", |
||||
|
((request, response) -> |
||||
|
{ |
||||
|
final UserId userId = |
||||
|
((AccessToken) request.session() |
||||
|
.attribute("userId")) |
||||
|
.getUserId(); |
||||
|
|
||||
|
final ChangeUserRequest message = objectMapper.readValue(request.body(), |
||||
|
ChangeUserRequest.class); |
||||
|
|
||||
|
final User user = service.changePlayer( |
||||
|
userId, |
||||
|
message); |
||||
|
|
||||
|
if (user == null) |
||||
|
{ |
||||
|
response.status(400); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(200); |
||||
|
response.type("application/json"); |
||||
|
|
||||
|
return objectMapper.writeValueAsString(user); |
||||
|
} |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
)); |
||||
|
|
||||
|
get("/users", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final UserId userId = |
||||
|
((AccessToken) request.session() |
||||
|
.attribute("userId")) |
||||
|
.getUserId(); |
||||
|
|
||||
|
final User user = service.getPlayer(userId); |
||||
|
|
||||
|
if (user == null) |
||||
|
{ |
||||
|
response.status(400); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
response.status(200); |
||||
|
response.type("application/json"); |
||||
|
|
||||
|
return objectMapper.writeValueAsString(user); |
||||
|
} |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
get("/users/:user_id", |
||||
|
(request, response) -> |
||||
|
{ |
||||
|
final UserId userId = UserId.of(request.params(":user_id")); |
||||
|
final UserRequest user = service.getSmallPlayer(userId); |
||||
|
|
||||
|
if (user == null) |
||||
|
{ |
||||
|
response.status(404); |
||||
|
} |
||||
|
response.body(objectMapper.writeValueAsString(user)); |
||||
|
return response; |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package de.fd.fh.server.user.web; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
@RequiredArgsConstructor |
||||
|
@Getter |
||||
|
public class UserRequest |
||||
|
{ |
||||
|
private final String id; |
||||
|
|
||||
|
private final String name; |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import de.fd.fh.server.user.UserRepository; |
||||
|
import de.fd.fh.server.user.UserService; |
||||
|
import de.fd.fh.server.user.events.ChangePasswordEvent; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.ArgumentCaptor; |
||||
|
|
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.BDDMockito.then; |
||||
|
import static org.mockito.Mockito.*; |
||||
|
|
||||
|
class AccessContextEventListenerTest |
||||
|
{ |
||||
|
@Test |
||||
|
void given_changePasswordEvent_when_passwordChanged_should_changePassword() |
||||
|
{ |
||||
|
final ChangePasswordEvent event = new ChangePasswordEvent(UserId.of("12345"), "newPwd"); |
||||
|
|
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByUserId(any(UserId.class))) |
||||
|
.thenReturn(new Access()); |
||||
|
|
||||
|
final ArgumentCaptor<Access> captor = ArgumentCaptor.forClass(Access.class); |
||||
|
|
||||
|
new AccessContextEventListener(repository).update(null, event); |
||||
|
verify(repository).save(captor.capture()); |
||||
|
|
||||
|
assertEquals("newPwd", captor.getValue().getPassword(), "Have to be the new password"); |
||||
|
then(repository).should().findByUserId(any(UserId.class)); |
||||
|
then(repository).should().save(any(Access.class)); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import dev.morphia.Datastore; |
||||
|
import dev.morphia.Key; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.Mock; |
||||
|
|
||||
|
import static org.hamcrest.MatcherAssert.assertThat; |
||||
|
import static org.hamcrest.Matchers.notNullValue; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.BDDMockito.then; |
||||
|
import static org.mockito.Mockito.mock; |
||||
|
import static org.mockito.Mockito.when; |
||||
|
|
||||
|
class AccessRepositoryTest |
||||
|
{ |
||||
|
@Mock |
||||
|
private Datastore datastore; |
||||
|
|
||||
|
@BeforeEach |
||||
|
public void before() |
||||
|
{ |
||||
|
datastore = mock(Datastore.class); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_newUser_when_saveUser_should_storeUserInDatabase() |
||||
|
{ |
||||
|
when(datastore.save(any(Access.class))) |
||||
|
.thenReturn(new Key<>(Access.class, "collection", "id")); |
||||
|
|
||||
|
final Access access = new Access("testId", "testName", "testPwd", UserId.of("userId"), |
||||
|
null, Role.USER); |
||||
|
|
||||
|
final Key<Access> result = new AccessRepository(datastore).save(access); |
||||
|
|
||||
|
assertThat("Key is null", result, notNullValue()); |
||||
|
then(datastore).should().save(any(Access.class)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,245 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import com.mongodb.WriteResult; |
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import de.fd.fh.shared.network.messages.LoginRequest; |
||||
|
import de.fd.fh.shared.network.messages.RegistrateRequest; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.ArgumentCaptor; |
||||
|
import spark.HaltException; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.Base64; |
||||
|
import java.util.Observable; |
||||
|
import java.util.Observer; |
||||
|
|
||||
|
import static org.hamcrest.MatcherAssert.assertThat; |
||||
|
import static org.hamcrest.Matchers.notNullValue; |
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.BDDMockito.then; |
||||
|
import static org.mockito.Mockito.*; |
||||
|
|
||||
|
class AccessServiceTest implements Observer |
||||
|
{ |
||||
|
private Object event; |
||||
|
|
||||
|
@BeforeEach |
||||
|
void before() |
||||
|
{ |
||||
|
this.event = null; |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_authenticatedUser_when_serverAuthenticateUser_should_authenticateUser() |
||||
|
{ |
||||
|
final Access access = new Access( |
||||
|
"testId", |
||||
|
"testName", |
||||
|
"testPwd", |
||||
|
UserId.of("12345"), |
||||
|
new AccessToken( |
||||
|
"testToken", |
||||
|
LocalDateTime.now(), |
||||
|
Role.USER, |
||||
|
UserId.of("12345") |
||||
|
), |
||||
|
Role.USER); |
||||
|
|
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByToken(any())) |
||||
|
.thenReturn(access); |
||||
|
final String path = "/test/path"; |
||||
|
final String token = "testToken"; |
||||
|
|
||||
|
final AccessToken result = new AccessService(repository).before(path, token); |
||||
|
|
||||
|
assertThat("User is not authenticated", result, notNullValue()); |
||||
|
then(repository).should().findByToken(any()); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_notAuthenticatedUser_when_serverAuthenticateUser_should_denyUser() |
||||
|
{ |
||||
|
final Access access = new Access( |
||||
|
"testId", |
||||
|
"testName", |
||||
|
"testPwd", |
||||
|
UserId.of("12345"), |
||||
|
null, |
||||
|
Role.USER); |
||||
|
|
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByToken(any())) |
||||
|
.thenReturn(access); |
||||
|
final String path = "/test/path"; |
||||
|
final String token = "testToken"; |
||||
|
|
||||
|
assertThrows(HaltException.class, () ->new AccessService(repository).before(path, token)); |
||||
|
|
||||
|
then(repository).should().findByToken(any()); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_newUser_when_createUser_should_storeNewUser() |
||||
|
{ |
||||
|
final RegistrateRequest request = |
||||
|
RegistrateRequest.of("testUser", "testPwd"); |
||||
|
|
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByUserName(any())) |
||||
|
.thenReturn(null); |
||||
|
ArgumentCaptor<Access> accessCaptor = ArgumentCaptor.forClass(Access.class); |
||||
|
|
||||
|
final AccessService service = new AccessService(repository); |
||||
|
service.addObserver(this); |
||||
|
|
||||
|
final boolean result = service.createPlayer(request); |
||||
|
|
||||
|
assertTrue(result); |
||||
|
assertThat("No event thrown", this.event, notNullValue()); |
||||
|
|
||||
|
verify(repository).save(accessCaptor.capture()); |
||||
|
final Access createdAccess = accessCaptor.getValue(); |
||||
|
|
||||
|
assertNotNull(createdAccess, "No Access created"); |
||||
|
assertNotNull(createdAccess.get_id(), "No Id created"); |
||||
|
assertNotNull(createdAccess.getUserId(), "No UserId created"); |
||||
|
assertEquals("testUser", createdAccess.getName(), "Wrong Username"); |
||||
|
assertEquals("testPwd", createdAccess.getPassword(), "Wrong Password"); |
||||
|
assertEquals(Role.USER.name(), createdAccess.getRole().name(), "Should be USER"); |
||||
|
assertNull(createdAccess.getToken(), "User should not be logged in"); |
||||
|
|
||||
|
then(repository).should().findByUserName(any()); |
||||
|
then(repository).should().save(any(Access.class)); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_loggedInUser_when_logout_should_logoutUser() |
||||
|
{ |
||||
|
final Access access = new Access( |
||||
|
"testId", |
||||
|
"testName", |
||||
|
"testPwd", |
||||
|
UserId.of("12345"), |
||||
|
null, |
||||
|
Role.USER |
||||
|
); |
||||
|
final AccessToken token = AccessToken.of(access); |
||||
|
access.setToken(token); |
||||
|
|
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByToken(any())) |
||||
|
.thenReturn(access); |
||||
|
ArgumentCaptor<Access> accessCaptor = ArgumentCaptor.forClass(Access.class); |
||||
|
|
||||
|
final AccessService service = new AccessService(repository); |
||||
|
|
||||
|
final boolean result = service.logout("testToken"); |
||||
|
|
||||
|
assertTrue(result); |
||||
|
|
||||
|
verify(repository).save(accessCaptor.capture()); |
||||
|
final Access createdAccess = accessCaptor.getValue(); |
||||
|
|
||||
|
assertNotNull(createdAccess, "No Access created"); |
||||
|
assertNotNull(createdAccess.get_id(), "No Id created"); |
||||
|
assertNotNull(createdAccess.getUserId(), "No UserId created"); |
||||
|
assertEquals("testName", createdAccess.getName(), "Wrong Username"); |
||||
|
assertEquals("testPwd", createdAccess.getPassword(), "Wrong Password"); |
||||
|
assertEquals(Role.USER.name(), createdAccess.getRole().name(), "Should be USER"); |
||||
|
assertNull(createdAccess.getToken(), "User should logged out"); |
||||
|
|
||||
|
then(repository).should().findByToken(any()); |
||||
|
then(repository).should().save(any(Access.class)); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_loginUser_should_returnLoginRequest() |
||||
|
{ |
||||
|
final byte[] message = Base64.getEncoder().encode("testName:testPassword".getBytes()); |
||||
|
final String header = "Basic " + new String(message); |
||||
|
final Access access = new Access( |
||||
|
"testId", |
||||
|
"testName", |
||||
|
"testPassword", |
||||
|
UserId.of("12345"), |
||||
|
null, |
||||
|
Role.USER |
||||
|
); |
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.findByUserName(any())) |
||||
|
.thenReturn(access); |
||||
|
|
||||
|
final LoginRequest result = new AccessService(repository).authorization(header); |
||||
|
|
||||
|
assertNotNull(result); |
||||
|
assertEquals(result.getName(), "testName", "Wrong UserName"); |
||||
|
assertEquals(result.getUserId(), "12345", "Wrong Password"); |
||||
|
assertNotNull(result.getToken(), "Not logged in"); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUserWithWrongPassword_when_loginUser_should_returnAccessDeny() |
||||
|
{ |
||||
|
final byte[] message = Base64.getEncoder().encode("testName:testPassword".getBytes()); |
||||
|
final String header = "Basic " + new String(message); |
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
|
||||
|
final LoginRequest result = new AccessService(repository).authorization(header); |
||||
|
|
||||
|
assertNull(result, "Return LoginRequest but wrong permissions"); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_deleteUser_should_deleteUser() |
||||
|
{ |
||||
|
final UserId userId = UserId.of("12345"); |
||||
|
final AccessToken token = new AccessToken(null, null, null, UserId.of("12345")); |
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.deleteLoginByUserId(any(UserId.class))) |
||||
|
.thenReturn(new WriteResult(1, false, null)); |
||||
|
|
||||
|
final AccessService service = new AccessService(repository); |
||||
|
service.addObserver(this); |
||||
|
|
||||
|
final boolean result = service.deleteAccount(userId, token); |
||||
|
|
||||
|
assertTrue(result); |
||||
|
assertNotNull(event); |
||||
|
|
||||
|
then(repository).should().deleteLoginByUserId(any(UserId.class)); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_deleteUserWithWrongPermission_should_doNothing() |
||||
|
{ |
||||
|
final UserId userId = UserId.of("12345"); |
||||
|
final AccessToken token = new AccessToken(null, null, null, UserId.of("98765")); |
||||
|
final AccessRepository repository = mock(AccessRepository.class); |
||||
|
when(repository.deleteLoginByUserId(any(UserId.class))) |
||||
|
.thenReturn(new WriteResult(1, false, null)); |
||||
|
|
||||
|
final AccessService service = new AccessService(repository); |
||||
|
service.addObserver(this); |
||||
|
|
||||
|
final boolean result = service.deleteAccount(userId, token); |
||||
|
|
||||
|
assertFalse(result); |
||||
|
assertNull(event); |
||||
|
|
||||
|
then(repository).shouldHaveNoInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void update(Observable o, Object arg) |
||||
|
{ |
||||
|
this.event = arg; |
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package de.fd.fh.server.access; |
||||
|
|
||||
|
import de.fd.fh.server.user.UserId; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
|
||||
|
import static org.hamcrest.MatcherAssert.assertThat; |
||||
|
import static org.hamcrest.Matchers.equalTo; |
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
|
||||
|
class AccessTokenTest |
||||
|
{ |
||||
|
@Test |
||||
|
void given_accessData_when_createAccessToken_should_createGeneratedToken() |
||||
|
{ |
||||
|
final Access access = new Access( |
||||
|
"testId", |
||||
|
"testName", |
||||
|
"testPwd", |
||||
|
UserId.of("12345"), |
||||
|
null, |
||||
|
Role.USER); |
||||
|
|
||||
|
final AccessToken result = AccessToken.of(access); |
||||
|
|
||||
|
assertNotNull(result.getCreatedDate()); |
||||
|
assertNotNull(result.getToken()); |
||||
|
assertThat(result.getToken().length(), equalTo(64)); |
||||
|
assertEquals(result.getRole(), Role.USER); |
||||
|
assertEquals(result.getUserId(), UserId.of("12345")); |
||||
|
} |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import de.fd.fh.server.access.events.AccountCreatedEvent; |
||||
|
import de.fd.fh.server.access.events.AccountDeletedEvent; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.ArgumentCaptor; |
||||
|
|
||||
|
import static org.junit.jupiter.api.Assertions.assertEquals; |
||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.BDDMockito.then; |
||||
|
import static org.mockito.Mockito.mock; |
||||
|
import static org.mockito.Mockito.verify; |
||||
|
|
||||
|
class UserContextEventListenerTest |
||||
|
{ |
||||
|
@Test |
||||
|
void given_accountCreatedEvent_when_accountWasCreated_should_createUser() |
||||
|
{ |
||||
|
final AccountCreatedEvent event = new AccountCreatedEvent("testName", UserId.of("12345")); |
||||
|
final UserRepository repository = mock(UserRepository.class); |
||||
|
|
||||
|
final ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class); |
||||
|
|
||||
|
new UserContextEventListener(repository).update(null, event); |
||||
|
verify(repository).save(captor.capture()); |
||||
|
|
||||
|
assertNotNull(captor.getValue()); |
||||
|
assertEquals("testName", captor.getValue().getName(), "Should have the correct name"); |
||||
|
assertEquals("12345", captor.getValue().getId().getIdentifier(), "Should have the correct userId"); |
||||
|
then(repository).should().save(any()); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_accountDeletedEvent_when_accountWasDeleted_should_deleteUser() |
||||
|
{ |
||||
|
final AccountDeletedEvent event = new AccountDeletedEvent(UserId.of("12345")); |
||||
|
final UserRepository repository = mock(UserRepository.class); |
||||
|
|
||||
|
final ArgumentCaptor<UserId> captor = ArgumentCaptor.forClass(UserId.class); |
||||
|
|
||||
|
new UserContextEventListener(repository).update(null, event); |
||||
|
verify(repository).deleteUserById(captor.capture()); |
||||
|
|
||||
|
assertNotNull(captor.getValue()); |
||||
|
assertEquals("12345", captor.getValue().getIdentifier(), "No correct userId"); |
||||
|
then(repository).should().deleteUserById(any(UserId.class)); |
||||
|
then(repository).shouldHaveNoMoreInteractions(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import dev.morphia.Datastore; |
||||
|
import dev.morphia.Key; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.Mock; |
||||
|
|
||||
|
import static org.hamcrest.MatcherAssert.assertThat; |
||||
|
import static org.hamcrest.Matchers.notNullValue; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.BDDMockito.then; |
||||
|
import static org.mockito.Mockito.mock; |
||||
|
import static org.mockito.Mockito.when; |
||||
|
|
||||
|
class UserRepositoryTest |
||||
|
{ |
||||
|
@Mock |
||||
|
private Datastore datastore; |
||||
|
|
||||
|
@BeforeEach |
||||
|
public void before() |
||||
|
{ |
||||
|
datastore = mock(Datastore.class); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_newUser_when_saveUser_should_storeUserInDatabase() |
||||
|
{ |
||||
|
when(datastore.save(any(User.class))) |
||||
|
.thenReturn(new Key<>(User.class, "collection", "id")); |
||||
|
|
||||
|
final User access = new User(UserId.of("userId"), "testName"); |
||||
|
|
||||
|
final Key<User> result = new UserRepository(datastore).save(access); |
||||
|
|
||||
|
assertThat("Key is null", result, notNullValue()); |
||||
|
then(datastore).should().save(any(User.class)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,84 @@ |
|||||
|
package de.fd.fh.server.user; |
||||
|
|
||||
|
import de.fd.fh.server.user.web.ChangeUserRequest; |
||||
|
import de.fd.fh.server.user.web.UserRequest; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.ArgumentCaptor; |
||||
|
|
||||
|
import java.util.Observable; |
||||
|
import java.util.Observer; |
||||
|
|
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.Mockito.*; |
||||
|
|
||||
|
class UserServiceTest implements Observer |
||||
|
{ |
||||
|
private Object event; |
||||
|
|
||||
|
@BeforeEach |
||||
|
void before() |
||||
|
{ |
||||
|
event = null; |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_changePassword_should_changePassword() |
||||
|
{ |
||||
|
final User user = |
||||
|
User.of("testName"); |
||||
|
final ChangeUserRequest request = |
||||
|
new ChangeUserRequest("testName", "newPassword"); |
||||
|
final UserRepository repository = mock(UserRepository.class); |
||||
|
when(repository.findUserById(any(UserId.class))) |
||||
|
.thenReturn(user); |
||||
|
|
||||
|
final UserService service = new UserService(repository); |
||||
|
service.addObserver(this); |
||||
|
final ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class); |
||||
|
|
||||
|
service.changePlayer(UserId.of("12345"), request); |
||||
|
verify(repository).save(captor.capture()); |
||||
|
|
||||
|
assertNotNull(captor.getValue(), "Should be saved"); |
||||
|
assertNotNull(event); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_getPlayer_should_returnPlayer() |
||||
|
{ |
||||
|
final User user = |
||||
|
User.of("testName"); |
||||
|
final UserRepository repository = mock(UserRepository.class); |
||||
|
when(repository.findUserById(any(UserId.class))) |
||||
|
.thenReturn(user); |
||||
|
|
||||
|
final User result = new UserService(repository).getPlayer(UserId.of("12345")); |
||||
|
|
||||
|
assertNotNull(result); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void given_storedUser_when_getSmallPlayer_should_returnSmallPlayer() |
||||
|
{ |
||||
|
final User user = |
||||
|
new User(UserId.of("12345"), "testName"); |
||||
|
final UserRepository repository = mock(UserRepository.class); |
||||
|
when(repository.findUserById(any(UserId.class))) |
||||
|
.thenReturn(user); |
||||
|
|
||||
|
final UserRequest result = new UserService(repository).getSmallPlayer(UserId.of("12345")); |
||||
|
|
||||
|
assertNotNull(result); |
||||
|
assertEquals("12345", result.getId(), "Wrong UserId"); |
||||
|
assertEquals("testName", result.getName(), "Wrong Name"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void update(Observable o, Object arg) |
||||
|
{ |
||||
|
event = arg; |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
package de.fd.fh.shared; |
||||
|
|
||||
|
public class Utils |
||||
|
{ |
||||
|
public static final String AUTHENTICATION_HEADER = "Authorization"; |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package de.fd.fh.shared.network.messages; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class LoginRequest |
||||
|
{ |
||||
|
private String name; |
||||
|
private String userId; |
||||
|
private String token; |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
package de.fd.fh.shared.network.messages; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
@AllArgsConstructor(staticName = "of") |
||||
|
public class RegistrateRequest |
||||
|
{ |
||||
|
private String userName; |
||||
|
private String password; |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue