Browse Source

Add AccessService

pr-readme
Steffen Nitschke 3 years ago
parent
commit
f5752b9423
  1. 152
      fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java
  2. 62
      fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java
  3. 13
      fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java
  4. 12
      fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java
  5. 245
      fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java

152
fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java

@ -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;
}
}

62
fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java

@ -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();
}
}

13
fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java

@ -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;
}

12
fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java

@ -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;
}

245
fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java

@ -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;
}
}
Loading…
Cancel
Save