From ad21f708ad26db1eef9d8698bef9eb561869deab Mon Sep 17 00:00:00 2001
From: OZGCloud <ozgcloud@mgm-tp.com>
Date: Thu, 5 May 2022 15:44:12 +0200
Subject: [PATCH] OZG-1527 add currentuserservice to get active user from

---
 pluto-server/pom.xml                          |  5 ++
 .../ozg/pluto/PlutoServerApplication.java     |  8 ++++
 .../CallContextHandleInterceptor.java         |  2 +-
 .../common/callcontext/CallContextUser.java   |  3 +-
 .../callcontext/CurrentUserService.java       | 43 +++++++++++++++++
 .../CallContextUserTestFactory.java           |  2 +-
 .../callcontext/CurrentUserServiceITCase.java | 47 +++++++++++++++++++
 7 files changed, 107 insertions(+), 3 deletions(-)
 create mode 100644 pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java
 create mode 100644 pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java

diff --git a/pluto-server/pom.xml b/pluto-server/pom.xml
index 099275d17..2c899e3df 100644
--- a/pluto-server/pom.xml
+++ b/pluto-server/pom.xml
@@ -168,6 +168,11 @@
 				</exclusion>
 			</exclusions>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-test</artifactId>
+		</dependency>
+		
 		<dependency>
 			<groupId>org.junit.jupiter</groupId>
 			<artifactId>junit-jupiter-engine</artifactId>
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
index 77094c837..c3e9cbd21 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
@@ -5,9 +5,12 @@ import java.util.TimeZone;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
 
 import io.mongock.runner.springboot.EnableMongock;
 
@@ -23,4 +26,9 @@ public class PlutoServerApplication {
 		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
 		SpringApplication.run(PlutoServerApplication.class, args);
 	}
+
+	@Bean
+	public AuthenticationTrustResolver trustResolver() {
+		return new AuthenticationTrustResolverImpl();
+	}
 }
\ No newline at end of file
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
index 6342d627c..68c6072e3 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
@@ -94,12 +94,12 @@ class CallContextHandleInterceptor implements ServerInterceptor {
 
 		CallContextUser createUser() {
 			var builder = CallContextUser.builder()
+					.userId(getFromHeaders(KEY_USER_ID, headers))
 					.userName(getFromHeaders(KEY_USER_NAME, headers))
 					.organisatorischeEinheitenIds(getCollection(KEY_ACCESS_LIMITED_ORGAID, headers));
 
 			// TODO throw exception if missing required data as soon all clients are fine
 			// with using headers for auth data.
-			getFromHeaders(KEY_USER_ID, headers).ifPresentOrElse(builder::userId, () -> LOG.warn("Missing user id in grpc header."));
 			getFromHeaders(KEY_CLIENT_NAME, headers).ifPresentOrElse(builder::clientName, () -> LOG.warn("Missing client name in grpc header."));
 
 			return builder.build();
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
index 7a37d14d0..6f1b4b5a0 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
@@ -18,7 +18,8 @@ public class CallContextUser implements AuthenticatedPrincipal, Serializable {
 
 	private final String clientName;
 
-	private final String userId;
+	@Builder.Default
+	private final transient Optional<String> userId = Optional.empty();
 	@Builder.Default
 	private final transient Optional<String> userName = Optional.empty();
 	@Singular
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java
new file mode 100644
index 000000000..d6b15332f
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java
@@ -0,0 +1,43 @@
+package de.itvsh.ozg.pluto.common.callcontext;
+
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CurrentUserService {
+
+	@Autowired
+	private AuthenticationTrustResolver trustResolver;
+
+	public CallContextUser getUser() {
+		var auth = getAuthentication();
+
+		if (auth instanceof CallContextAuthenticationToken) {
+			return (CallContextUser) auth.getPrincipal();
+		} else {
+			return CallContextUser.builder()
+					.clientName(auth.getName())
+					.organisatorischeEinheitenIds(
+							auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toUnmodifiableSet()))
+					.build();
+		}
+
+	}
+
+	public Authentication getAuthentication() {
+		return findTrustedAuthentication().orElseThrow(() -> new IllegalStateException("No authenticated User found"));
+	}
+
+	Optional<Authentication> findTrustedAuthentication() {
+		return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
+				.filter(auth -> !trustResolver.isAnonymous(auth))
+				.filter(Authentication::isAuthenticated);
+	}
+}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
index 4aeb8415b..68de875e1 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
@@ -13,7 +13,7 @@ public class CallContextUserTestFactory {
 	static CallContextUser.CallContextUserBuilder createBuilder() {
 		return CallContextUser.builder()
 				.clientName(CallContextTestFactory.CLIENT)
-				.userId(UserTestFactory.ID)
+				.userId(Optional.of(UserTestFactory.ID))
 				.userName(Optional.of(UserTestFactory.NAME))
 				.organisatorischeEinheitenId(UserTestFactory.ORGANISATORISCHE_EINHEITEN_ID);
 	}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java
new file mode 100644
index 000000000..66bca90a4
--- /dev/null
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java
@@ -0,0 +1,47 @@
+package de.itvsh.ozg.pluto.common.callcontext;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.test.context.support.WithAnonymousUser;
+import org.springframework.security.test.context.support.WithMockUser;
+
+import de.itvsh.kop.common.test.ITCase;
+
+@ITCase
+class CurrentUserServiceITCase {
+
+	@Autowired
+	private CurrentUserService service;
+
+	@Test
+	void shouldThrowExceptionIfUserIsMissing() {
+		assertThatThrownBy(() -> service.getUser()).isInstanceOf(IllegalStateException.class);
+	}
+
+	@Test
+	@WithAnonymousUser
+	void shouldThrowExceptionIfAnonymouse() {
+		assertThatThrownBy(() -> service.getUser()).isInstanceOf(IllegalStateException.class);
+	}
+
+	@Test
+	@WithMockUser
+	void shouldReturnUser() {
+		var user = service.getUser();
+
+		assertThat(user.getName()).isEqualTo("user");
+	}
+
+	@Test
+	void shouldReturnUserFromToken() {
+		var inUser = CallContextUserTestFactory.create();
+		SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(inUser));
+
+		var user = service.getUser();
+
+		assertThat(user).isSameAs(inUser);
+	}
+}
-- 
GitLab