diff --git a/.github/workflows/dockerImage.yml b/.github/workflows/dockerImage.yml index 96eeb2c..ddcc5bb 100644 --- a/.github/workflows/dockerImage.yml +++ b/.github/workflows/dockerImage.yml @@ -28,7 +28,7 @@ jobs: - name: Setup JVM uses: actions/setup-java@v1 with: - java-version: 11.0.10 + java-version: 17.0.7 java-package: jdk architecture: x64 @@ -64,7 +64,7 @@ jobs: push_to_registry: strategy: matrix: - registry: ["docker.pkg.github.com", "ghcr.io"] + registry: ["ghcr.io"] needs: [test] name: Push Docker image to GitHub Packages runs-on: ubuntu-latest diff --git a/.github/workflows/feature-branch.yml b/.github/workflows/feature-branch.yml index efc6601..231959b 100644 --- a/.github/workflows/feature-branch.yml +++ b/.github/workflows/feature-branch.yml @@ -18,7 +18,7 @@ jobs: - name: Setup JVM uses: actions/setup-java@v1 with: - java-version: 11.0.10 + java-version: 17.0.7 java-package: jdk architecture: x64 diff --git a/Dockerfile b/Dockerfile index e58728a..c991a58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM adoptopenjdk/openjdk11 +FROM openjdk:17-oracle VOLUME ["/tmp","/log"] EXPOSE 8080 ARG JAR_FILE diff --git a/api/videoservice.yaml b/api/videoservice.yaml index df5996c..9594360 100644 --- a/api/videoservice.yaml +++ b/api/videoservice.yaml @@ -220,8 +220,6 @@ components: schemas: CreateVideoCallDTO: type: object - required: - - sessionId properties: sessionId: type: integer diff --git a/pom.xml b/pom.xml index 3e2649f..5a47f70 100644 --- a/pom.xml +++ b/pom.xml @@ -14,31 +14,33 @@ org.springframework.boot spring-boot-starter-parent - 2.5.12 + 3.0.6 UTF-8 UTF-8 - 11 + 17 17.0.0 2.19.0 - 6.2.1 - 3.0.0 + 6.6.0 + 0.2.3 - 2.10.0 - 5.7.5 + + 6.0.5 2.10.9.2 2.1.1 3.12.1 3.11 4.4 2.1.214 - 4.9.1 + 4.23.2 8.0.0.Final - 4.1.1 + 4.23.2 + 17 + 17 @@ -60,13 +62,33 @@ org.springframework.boot spring-boot-starter-cache + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + + org.springframework.security + spring-security-web + ${spring-security.version} + + + org.springframework.security + spring-security-config + ${spring-security.version} + org.springframework.security spring-security-core - ${spring-security-core.version} + ${spring-security.version} + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + net.sf.ehcache @@ -103,6 +125,26 @@ ${jackson-databind-nullable.version} + + org.codehaus.plexus + plexus-utils + 3.3.0 + + + + + io.swagger.core.v3 + swagger-annotations + 2.2.15 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.4.0 + + org.json @@ -110,12 +152,6 @@ 20220320 - - - io.springfox - springfox-boot-starter - ${springfox-boot-starter.version} - org.keycloak @@ -150,6 +186,12 @@ org.liquibase liquibase-maven-plugin ${liquibase.maven.plugin.version} + + + org.liquibase + liquibase-core + + @@ -206,6 +248,7 @@ spring-boot-starter-actuator + org.springframework.boot @@ -215,19 +258,14 @@ org.springframework.security spring-security-test + ${spring-security.version} test - powermock-module-junit4 - org.powermock + junit + junit + 4.13.2 test - 2.0.2 - - - powermock-api-mockito2 - org.powermock - test - 2.0.2 @@ -268,7 +306,10 @@ ${log4j.version} - + + org.apache.httpcomponents.client5 + httpclient5 + @@ -311,7 +352,9 @@ true / + true + ${project.basedir}/api/videoservice.yaml spring ${project.groupId}.${project.artifactId}.generated.api.controller diff --git a/src/main/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandler.java b/src/main/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandler.java index 7eab9f3..552d650 100644 --- a/src/main/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandler.java +++ b/src/main/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandler.java @@ -64,7 +64,6 @@ public ResponseEntity handleNoSuchElementException( * @param request web request * @return response entity */ - @Override @NonNull protected ResponseEntity handleHttpMessageNotReadable( final @NonNull HttpMessageNotReadableException ex, @@ -85,7 +84,6 @@ protected ResponseEntity handleHttpMessageNotReadable( * @param request web request * @return response entity */ - @Override @NonNull protected ResponseEntity handleMethodArgumentNotValid( final @NonNull MethodArgumentNotValidException ex, @@ -148,7 +146,7 @@ public ResponseEntity handleInternal( LogService.logWarning(ex); return handleExceptionInternal( - EMPTY_EXCEPTION, null, new HttpHeaders(), ex.getStatus(), request); + EMPTY_EXCEPTION, null, new HttpHeaders(), ex.getStatusCode(), request); } /** diff --git a/src/main/java/de/caritas/cob/videoservice/api/authorization/VideoUser.java b/src/main/java/de/caritas/cob/videoservice/api/authorization/AuthenticatedUser.java similarity index 95% rename from src/main/java/de/caritas/cob/videoservice/api/authorization/VideoUser.java rename to src/main/java/de/caritas/cob/videoservice/api/authorization/AuthenticatedUser.java index cd7b772..52bd0e7 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/authorization/VideoUser.java +++ b/src/main/java/de/caritas/cob/videoservice/api/authorization/AuthenticatedUser.java @@ -15,7 +15,7 @@ @NoArgsConstructor @Getter @Setter -public class VideoUser { +public class AuthenticatedUser { @NonNull private String userId; diff --git a/src/main/java/de/caritas/cob/videoservice/api/authorization/Authority.java b/src/main/java/de/caritas/cob/videoservice/api/authorization/Authority.java index 9571d30..cb2f349 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/authorization/Authority.java +++ b/src/main/java/de/caritas/cob/videoservice/api/authorization/Authority.java @@ -1,8 +1,12 @@ package de.caritas.cob.videoservice.api.authorization; +import com.google.common.collect.Lists; +import java.util.List; import java.util.stream.Stream; +import lombok.Getter; /** Definition of all authorities and of the role-authority-mapping. */ +@Getter public enum Authority { CONSULTANT(UserRole.CONSULTANT, "AUTHORIZATION_CONSULTANT_DEFAULT"), USER(UserRole.USER, "AUTHORIZATION_USER_DEFAULT"), @@ -10,11 +14,11 @@ public enum Authority { JITSI_TECHNICAL(UserRole.JITSI_TECHNICAL, "AUTHORIZATION_JITSI_TECHNICAL_DEFAULT"); private final UserRole role; - private final String authorityName; + private final List authorities; Authority(final UserRole role, final String authorityName) { this.role = role; - this.authorityName = authorityName; + this.authorities = Lists.newArrayList(authorityName); } /** @@ -30,12 +34,13 @@ public static Authority fromRoleName(String roleName) { .orElse(null); } - /** - * Returns the authority name for the given {@link Authority}. - * - * @return authority name for the given {@link Authority} - */ - public String getAuthority() { - return this.authorityName; + public static class AuthorityValue { + + private AuthorityValue() {} + + public static final String PREFIX = "AUTHORIZATION_"; + public static final String CONSULTANT = PREFIX + "CONSULTANT_DEFAULT"; + public static final String USER = PREFIX + "USER_DEFAULT"; + public static final String JITSI_TECHNICAL = PREFIX + "JITSI_TECHNICAL_DEFAULT"; } } diff --git a/src/main/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthorityMapper.java b/src/main/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthorityMapper.java index 2ff5cc7..71e71e0 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthorityMapper.java +++ b/src/main/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthorityMapper.java @@ -13,12 +13,6 @@ @Component public class RoleAuthorizationAuthorityMapper implements GrantedAuthoritiesMapper { - /** - * Maps all {@link Authority} definitions to the corresponding roles. - * - * @param authorities all given authorities - * @return mapped role authorities collections - */ @Override public Collection mapAuthorities( Collection authorities) { @@ -31,11 +25,12 @@ public Collection mapAuthorities( return mapAuthorities(roleNames); } - private Set mapAuthorities(Set roleNames) { + public Set mapAuthorities(Set roleNames) { return roleNames.stream() .map(Authority::fromRoleName) .filter(Objects::nonNull) - .map(Authority::getAuthority) + .map(Authority::getAuthorities) + .flatMap(Collection::parallelStream) .map(SimpleGrantedAuthority::new) .collect(Collectors.toSet()); } diff --git a/src/main/java/de/caritas/cob/videoservice/api/controller/CustomSwaggerApiResourceController.java b/src/main/java/de/caritas/cob/videoservice/api/controller/CustomSwaggerApiResourceController.java deleted file mode 100644 index 20c524d..0000000 --- a/src/main/java/de/caritas/cob/videoservice/api/controller/CustomSwaggerApiResourceController.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.caritas.cob.videoservice.api.controller; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import springfox.documentation.annotations.ApiIgnore; -import springfox.documentation.swagger.web.ApiResourceController; -import springfox.documentation.swagger.web.SwaggerResourcesProvider; - -@Controller -@ApiIgnore -@RequestMapping(value = "${springfox.docuPath}" + "/swagger-resources") -public class CustomSwaggerApiResourceController extends ApiResourceController { - - public static final String SWAGGER_UI_BASE_URL = "/videocalls/docs"; - - public CustomSwaggerApiResourceController(SwaggerResourcesProvider swaggerResources) { - super(swaggerResources, SWAGGER_UI_BASE_URL); - } -} diff --git a/src/main/java/de/caritas/cob/videoservice/api/controller/VideoController.java b/src/main/java/de/caritas/cob/videoservice/api/controller/VideoController.java index eb887c7..473e5f5 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/controller/VideoController.java +++ b/src/main/java/de/caritas/cob/videoservice/api/controller/VideoController.java @@ -10,8 +10,8 @@ import de.caritas.cob.videoservice.api.tenant.TenantContext; import de.caritas.cob.videoservice.generated.api.controller.VideocallsApi; import io.swagger.annotations.Api; +import jakarta.validation.Valid; import java.util.UUID; -import javax.validation.Valid; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -41,7 +41,7 @@ public class VideoController implements VideocallsApi { */ @Override public ResponseEntity createVideoCall( - @RequestHeader String rcUserId, @Valid CreateVideoCallDTO createVideoCallDto) { + @RequestHeader String rcUserId, CreateVideoCallDTO createVideoCallDto) { var response = videoCallFacade.startVideoCall(createVideoCallDto, rcUserId); return new ResponseEntity<>(response, HttpStatus.CREATED); diff --git a/src/main/java/de/caritas/cob/videoservice/api/facade/VideoCallFacade.java b/src/main/java/de/caritas/cob/videoservice/api/facade/VideoCallFacade.java index 8ab8049..fb63e9c 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/facade/VideoCallFacade.java +++ b/src/main/java/de/caritas/cob/videoservice/api/facade/VideoCallFacade.java @@ -4,7 +4,7 @@ import static java.util.Collections.singletonList; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.exception.httpresponse.BadRequestException; import de.caritas.cob.videoservice.api.model.CreateVideoCallDTO; import de.caritas.cob.videoservice.api.model.VideoCallResponseDTO; @@ -26,7 +26,6 @@ import de.caritas.cob.videoservice.liveservice.generated.web.model.VideoCallRequestDTO; import de.caritas.cob.videoservice.statisticsservice.generated.web.model.UserRole; import de.caritas.cob.videoservice.userservice.generated.web.model.ConsultantSessionDTO; -import java.util.stream.Collectors; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -43,7 +42,7 @@ public class VideoCallFacade { private final @NonNull ChatService chatService; private final @NonNull LiveEventNotificationService liveEventNotificationService; - private final @NonNull VideoUser authenticatedUser; + private final @NonNull AuthenticatedUser authenticatedUser; private final @NonNull VideoCallUrlGeneratorService videoCallUrlGeneratorService; private final @NonNull UuidRegistry uuidRegistry; private final @NonNull StatisticsService statisticsService; @@ -116,7 +115,7 @@ private VideoCallResponseDTO startGroupVideoCall( chatMembers.getMembers().stream() .filter(member -> !initiatorRcUserId.equals(member.getId())) .map(member -> member.getUserId()) - .collect(Collectors.toList()); + .toList(); this.liveEventNotificationService.sendVideoCallRequestLiveEvent( buildLiveEventMessage( chatById.getGroupId(), diff --git a/src/main/java/de/caritas/cob/videoservice/api/model/VideoRoomEntity.java b/src/main/java/de/caritas/cob/videoservice/api/model/VideoRoomEntity.java index 3b60d3d..62c3397 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/model/VideoRoomEntity.java +++ b/src/main/java/de/caritas/cob/videoservice/api/model/VideoRoomEntity.java @@ -1,13 +1,13 @@ package de.caritas.cob.videoservice.api.model; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; import java.time.LocalDateTime; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/UuidRegistry.java b/src/main/java/de/caritas/cob/videoservice/api/service/UuidRegistry.java index fb28a0b..521d31b 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/UuidRegistry.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/UuidRegistry.java @@ -10,7 +10,7 @@ @Component public class UuidRegistry { - private static final List GENERATED_UUIDS = new CopyOnWriteArrayList<>(); + protected static final List GENERATED_UUIDS = new CopyOnWriteArrayList<>(); /** * Generates an unique {@link UUID} string that is currently not registered and adds it to the diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/HttpHeadersResolver.java b/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/HttpHeadersResolver.java index 1cc2ed3..487af5d 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/HttpHeadersResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/HttpHeadersResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.videoservice.api.service.httpheader; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplier.java b/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplier.java index 0b522d3..08bc5d6 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplier.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplier.java @@ -1,6 +1,6 @@ package de.caritas.cob.videoservice.api.service.httpheader; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import java.util.UUID; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -13,7 +13,7 @@ @RequiredArgsConstructor public class SecurityHeaderSupplier { - private final @NonNull VideoUser authenticatedUser; + private final @NonNull AuthenticatedUser authenticatedUser; @Value("${csrf.header.property}") private String csrfHeaderProperty; diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/message/MessageService.java b/src/main/java/de/caritas/cob/videoservice/api/service/message/MessageService.java index e643782..0d72aa2 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/message/MessageService.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/message/MessageService.java @@ -12,9 +12,9 @@ import java.time.Duration; import java.time.LocalDateTime; import lombok.extern.slf4j.Slf4j; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -50,7 +50,7 @@ public MessageControllerApi getMessageControllerApi() { final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); final HttpClient httpClient = - HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build(); + HttpClientBuilder.create().setRedirectStrategy(new DefaultRedirectStrategy()).build(); factory.setHttpClient(httpClient); restTemplate.setRequestFactory(factory); de.caritas.cob.videoservice.messageservice.generated.ApiClient apiClient = diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsService.java b/src/main/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsService.java index acf732f..56ef77f 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsService.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsService.java @@ -2,8 +2,8 @@ import de.caritas.cob.videoservice.api.service.LogService; import de.caritas.cob.videoservice.api.service.statistics.event.StatisticsEvent; +import jakarta.validation.constraints.NotNull; import java.nio.charset.StandardCharsets; -import javax.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.MessageBuilder; diff --git a/src/main/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorService.java b/src/main/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorService.java index 7a6ef2e..fa8d131 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorService.java +++ b/src/main/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorService.java @@ -7,14 +7,13 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator.Builder; import com.auth0.jwt.algorithms.Algorithm; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.exception.httpresponse.InternalServerErrorException; import de.caritas.cob.videoservice.api.service.video.jwt.model.VideoCallToken; import java.sql.Date; import java.time.LocalDateTime; import lombok.NonNull; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; @@ -25,12 +24,11 @@ public class TokenGeneratorService { @Autowired - public TokenGeneratorService( - @NonNull @Qualifier("AuthenticatedOrAnonymousUser") VideoUser authenticatedUser) { + public TokenGeneratorService(@NonNull AuthenticatedUser authenticatedUser) { this.videoUser = authenticatedUser; } - private final @NonNull VideoUser videoUser; + private final @NonNull AuthenticatedUser videoUser; private static final String ROOM_CLAIM = "room"; private static final String MODERATOR_CLAIM = "moderator"; diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolver.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolver.java index 4eac676..0af83ea 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolver.java @@ -1,8 +1,8 @@ package de.caritas.cob.videoservice.api.tenant; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.keycloak.KeycloakSecurityContext; diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolver.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolver.java index 9744e79..0764b98 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolver.java @@ -1,8 +1,8 @@ package de.caritas.cob.videoservice.api.tenant; import de.caritas.cob.videoservice.api.service.httpheader.TenantHeaderSupplier; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.NonNull; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolver.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolver.java index 90e3988..45a510d 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolver.java @@ -5,8 +5,8 @@ import de.caritas.cob.videoservice.api.service.TenantService; import de.caritas.cob.videoservice.filter.SubdomainExtractor; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.NonNull; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolver.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolver.java index 9229e61..af74be1 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.videoservice.api.tenant; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.representations.AccessToken; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolver.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolver.java index 65629e2..2862b69 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolver.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.videoservice.api.tenant; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; public interface TenantResolver { diff --git a/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolverService.java b/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolverService.java index 252de6e..5e36b66 100644 --- a/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolverService.java +++ b/src/main/java/de/caritas/cob/videoservice/api/tenant/TenantResolverService.java @@ -2,10 +2,10 @@ import static com.google.common.collect.Lists.newArrayList; +import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/de/caritas/cob/videoservice/config/AuthenticatedUserConfig.java b/src/main/java/de/caritas/cob/videoservice/config/AuthenticatedUserConfig.java index ed4b9a6..6d96bef 100644 --- a/src/main/java/de/caritas/cob/videoservice/config/AuthenticatedUserConfig.java +++ b/src/main/java/de/caritas/cob/videoservice/config/AuthenticatedUserConfig.java @@ -2,117 +2,77 @@ import static java.util.Objects.isNull; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import com.google.common.collect.Lists; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.exception.KeycloakException; -import java.security.Principal; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Collection; +import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.springframework.beans.factory.annotation.Qualifier; +import java.util.stream.Collectors; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -/** Configuration for the {@link VideoUser}. */ +/** Configuration for the {@link AuthenticatedUser}. */ @Configuration public class AuthenticatedUserConfig { private static final String CLAIM_NAME_USER_ID = "userId"; private static final String CLAIM_NAME_USERNAME = "username"; - private static final VideoUser ANONYMOUS_USER = new VideoUser(); + private static final AuthenticatedUser ANONYMOUS_USER = new AuthenticatedUser(); /** * Returns the currently authenticated user. * - * @return {@link VideoUser} + * @return {@link AuthenticatedUser} */ @Bean @Primary @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public VideoUser getAuthenticatedUser() { - var userPrincipal = getRequest().getUserPrincipal(); - return createAuthenticatedUser(userPrincipal); - } - - /** - * Returns the currently authenticated user, or an anonymous representation. - * - * @return {@link VideoUser} - */ - @Bean - @Qualifier("AuthenticatedOrAnonymousUser") - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public VideoUser getAuthenticatedOrAnonymousUser() { + public AuthenticatedUser getAuthenticatedUser() { var userPrincipal = getRequest().getUserPrincipal(); if (isNull(userPrincipal)) { return ANONYMOUS_USER; } - return createAuthenticatedUser(userPrincipal); - } + JwtAuthenticationToken authenticationToken = + (JwtAuthenticationToken) getRequest().getUserPrincipal(); - private VideoUser createAuthenticatedUser(Principal userPrincipal) { - var keycloakUser = (KeycloakAuthenticationToken) userPrincipal; - var keycloakSecContext = keycloakUser.getAccount().getKeycloakSecurityContext(); - Map claimMap = keycloakSecContext.getToken().getOtherClaims(); - - var authenticatedUser = new VideoUser(); - authenticatedUser.setAccessToken(getUserAccessToken(keycloakSecContext)); + Map claimMap = authenticationToken.getToken().getClaims(); + AuthenticatedUser authenticatedUser = new AuthenticatedUser(); + authenticatedUser.setAccessToken(authenticationToken.getToken().getTokenValue()); authenticatedUser.setUserId(getUserAttribute(claimMap, CLAIM_NAME_USER_ID)); authenticatedUser.setUsername(getUserAttribute(claimMap, CLAIM_NAME_USERNAME)); - - var roles = keycloakSecContext.getToken().getRealmAccess().getRoles(); - authenticatedUser.setRoles(roles); - + authenticatedUser.setRoles( + extractRealmRoles(authenticationToken.getToken()).stream().collect(Collectors.toSet())); return authenticatedUser; } - private String getUserAccessToken(KeycloakSecurityContext keycloakSecContext) { - if (isNull(keycloakSecContext.getTokenString())) { - throw new KeycloakException("No valid Keycloak access token string found."); + public Collection extractRealmRoles(Jwt jwt) { + Map realmAccess = (Map) jwt.getClaims().get("realm_access"); + if (realmAccess != null) { + var roles = (List) realmAccess.get("roles"); + if (roles != null) { + return roles; + } } - - return keycloakSecContext.getTokenString(); + return Lists.newArrayList(); } private String getUserAttribute(Map claimMap, String claimValue) { if (!claimMap.containsKey(claimValue)) { throw new KeycloakException("Keycloak user attribute '" + claimValue + "' not found."); } - return claimMap.get(claimValue).toString(); } - /** - * Returns the {@link KeycloakAuthenticationToken} which represents the token for a Keycloak - * authentication. - * - * @return {@link KeycloakAuthenticationToken} - */ - @Bean - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public KeycloakAuthenticationToken getAccessToken() { - return (KeycloakAuthenticationToken) getRequest().getUserPrincipal(); - } - - /** - * Returns the {@link KeycloakSecurityContext}. - * - * @return {@link KeycloakSecurityContext} - */ - @Bean - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public KeycloakSecurityContext getKeycloakSecurityContext() { - return ((KeycloakAuthenticationToken) getRequest().getUserPrincipal()) - .getAccount() - .getKeycloakSecurityContext(); - } - private HttpServletRequest getRequest() { return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) .getRequest(); diff --git a/src/main/java/de/caritas/cob/videoservice/config/CacheManagerConfig.java b/src/main/java/de/caritas/cob/videoservice/config/CacheManagerConfig.java index 31e0ff6..6f32b37 100644 --- a/src/main/java/de/caritas/cob/videoservice/config/CacheManagerConfig.java +++ b/src/main/java/de/caritas/cob/videoservice/config/CacheManagerConfig.java @@ -2,9 +2,7 @@ import net.sf.ehcache.config.CacheConfiguration; import org.springframework.beans.factory.annotation.Value; -import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.ehcache.EhCacheCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -26,21 +24,10 @@ public class CacheManagerConfig { @Value("${cache.tenant.configuration.timeToLiveSeconds}") private long tenantTimeToLiveSeconds; - @Bean - public CacheManager cacheManager() { - return new EhCacheCacheManager(ehCacheManager()); - } - - /** - * Defines cache manager. - * - * @return - */ @Bean(destroyMethod = "shutdown") public net.sf.ehcache.CacheManager ehCacheManager() { var config = new net.sf.ehcache.config.Configuration(); config.addCache(buildTenantCacheConfiguration()); - return net.sf.ehcache.CacheManager.newInstance(config); } diff --git a/src/main/java/de/caritas/cob/videoservice/config/LoggingConfig.java b/src/main/java/de/caritas/cob/videoservice/config/LoggingConfig.java new file mode 100644 index 0000000..0f00aa4 --- /dev/null +++ b/src/main/java/de/caritas/cob/videoservice/config/LoggingConfig.java @@ -0,0 +1,20 @@ +package de.caritas.cob.videoservice.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.CommonsRequestLoggingFilter; + +@Configuration +public class LoggingConfig { + + @Bean + public CommonsRequestLoggingFilter logFilter() { + CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter(); + filter.setIncludeQueryString(true); + filter.setIncludePayload(true); + filter.setMaxPayloadLength(10000); + filter.setIncludeHeaders(false); + filter.setAfterMessagePrefix("REQUEST DATA: "); + return filter; + } +} diff --git a/src/main/java/de/caritas/cob/videoservice/config/SpringFoxConfig.java b/src/main/java/de/caritas/cob/videoservice/config/SpringFoxConfig.java deleted file mode 100644 index 29a030f..0000000 --- a/src/main/java/de/caritas/cob/videoservice/config/SpringFoxConfig.java +++ /dev/null @@ -1,112 +0,0 @@ -package de.caritas.cob.videoservice.config; - -import java.time.LocalTime; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.Contact; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; - -/** Provides the SpringFox (API documentation generation) configuration. */ -@Configuration -@Import(BeanValidatorPluginsConfiguration.class) -public class SpringFoxConfig { - - @Value("${springfox.docuTitle}") - private String docuTitle; - - @Value("${springfox.docuDescription}") - private String docuDescription; - - @Value("${springfox.docuVersion}") - private String docuVersion; - - @Value("${springfox.docuTermsUrl}") - private String docuTermsUrl; - - @Value("${springfox.docuContactName}") - private String docuContactName; - - @Value("${springfox.docuContactUrl}") - private String docuContactUrl; - - @Value("${springfox.docuContactEmail}") - private String docuContactEmail; - - @Value("${springfox.docuLicense}") - private String docuLicense; - - @Value("${springfox.docuLicenseUrl}") - private String docuLicenseUrl; - - /** - * White list for path patterns that should be white listed so that swagger UI can be accessed - * without authorization. - */ - public static final String[] WHITE_LIST = - new String[] { - "/videocalls/docs", - "/videocalls/docs/**", - "/videocalls/event/stop", - "/v2/api-docs", - "/configuration/ui", - "/swagger-resources/**", - "/configuration/security", - "/swagger-ui", - "/swagger-ui/**", - "/webjars/**", - "/actuator/health", - "/actuator/health/**" - }; - - /** - * SpringFox Docket Bean. - * - * @return {@link Docket} - */ - @Bean - public Docket apiDocket() { - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(RequestHandlerSelectors.basePackage("de.caritas.cob.videoservice.api")) - .build() - .consumes(getContentTypes()) - .produces(getContentTypes()) - .apiInfo(getApiInfo()) - .useDefaultResponseMessages(false) - .protocols(protocols()) - .directModelSubstitute(LocalTime.class, String.class); - } - - private Set protocols() { - Set protocols = new HashSet<>(); - protocols.add("https"); - return protocols; - } - - private Set getContentTypes() { - Set contentTypes = new HashSet<>(); - contentTypes.add("application/json"); - return contentTypes; - } - - private ApiInfo getApiInfo() { - return new ApiInfo( - docuTitle, - docuDescription, - docuVersion, - docuTermsUrl, - new Contact(docuContactName, docuContactUrl, docuContactEmail), - docuLicense, - docuLicenseUrl, - Collections.emptyList()); - } -} diff --git a/src/main/java/de/caritas/cob/videoservice/config/resttemplate/CustomResponseErrorHandler.java b/src/main/java/de/caritas/cob/videoservice/config/resttemplate/CustomResponseErrorHandler.java index 0ff7dd8..68bcd69 100644 --- a/src/main/java/de/caritas/cob/videoservice/config/resttemplate/CustomResponseErrorHandler.java +++ b/src/main/java/de/caritas/cob/videoservice/config/resttemplate/CustomResponseErrorHandler.java @@ -9,6 +9,7 @@ import lombok.NonNull; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.server.ResponseStatusException; @@ -28,7 +29,7 @@ public void handleError(@NonNull URI url, @NonNull HttpMethod method, ClientHttp throw new InternalServerErrorException(response.getStatusText()); } - private boolean isLoopThroughStatusCode(HttpStatus httpStatus) { + private boolean isLoopThroughStatusCode(HttpStatusCode httpStatus) { return LOOP_THROUGH_STATUS_CODES.contains(httpStatus); } } diff --git a/src/main/java/de/caritas/cob/videoservice/config/security/AuthorisationService.java b/src/main/java/de/caritas/cob/videoservice/config/security/AuthorisationService.java new file mode 100644 index 0000000..205a469 --- /dev/null +++ b/src/main/java/de/caritas/cob/videoservice/config/security/AuthorisationService.java @@ -0,0 +1,49 @@ +package de.caritas.cob.videoservice.config.security; + +import com.google.common.collect.Lists; +import de.caritas.cob.videoservice.api.authorization.RoleAuthorizationAuthorityMapper; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.stereotype.Service; + +@Service +public class AuthorisationService { + + private final RoleAuthorizationAuthorityMapper roleAuthorizationAuthorityMapper = + new RoleAuthorizationAuthorityMapper(); + + public Object getUsername() { + return getPrincipal().getClaims().get("username"); + } + + private Authentication getAuthentication() { + return SecurityContextHolder.getContext().getAuthentication(); + } + + private Jwt getPrincipal() { + return (Jwt) getAuthentication().getPrincipal(); + } + + public Collection extractRealmAuthorities(Jwt jwt) { + var roles = extractRealmRoles(jwt); + return roleAuthorizationAuthorityMapper.mapAuthorities( + roles.stream().collect(Collectors.toSet())); + } + + public Collection extractRealmRoles(Jwt jwt) { + Map realmAccess = (Map) jwt.getClaims().get("realm_access"); + if (realmAccess != null) { + var roles = (List) realmAccess.get("roles"); + if (roles != null) { + return roles; + } + } + return Lists.newArrayList(); + } +} diff --git a/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverter.java b/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverter.java new file mode 100644 index 0000000..3a9e1f7 --- /dev/null +++ b/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverter.java @@ -0,0 +1,60 @@ +package de.caritas.cob.videoservice.config.security; + +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtClaimNames; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class JwtAuthConverter implements Converter { + + private final @NonNull AuthorisationService authorisationService; + + private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = + new JwtGrantedAuthoritiesConverter(); + + private final JwtAuthConverterProperties properties; + + public JwtAuthConverter( + JwtAuthConverterProperties properties, AuthorisationService authorisationService) { + this.properties = properties; + this.authorisationService = authorisationService; + } + + @Override + public AbstractAuthenticationToken convert(Jwt jwt) { + var authorities = getGrantedAuthorities(jwt); + return new JwtAuthenticationToken(jwt, authorities, getPrincipalClaimName(jwt)); + } + + private Collection getGrantedAuthorities(Jwt jwt) { + Collection convertedGrantedAuthorities = + jwtGrantedAuthoritiesConverter.convert(jwt); + if (convertedGrantedAuthorities != null) { + return Stream.concat( + convertedGrantedAuthorities.stream(), + authorisationService.extractRealmAuthorities(jwt).stream()) + .collect(Collectors.toSet()); + } else { + return authorisationService.extractRealmAuthorities(jwt); + } + } + + private String getPrincipalClaimName(Jwt jwt) { + String claimName = JwtClaimNames.SUB; + if (properties.getPrincipalAttribute() != null) { + claimName = properties.getPrincipalAttribute(); + } + return jwt.getClaim(claimName); + } +} diff --git a/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverterProperties.java b/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverterProperties.java new file mode 100644 index 0000000..3cd0c1c --- /dev/null +++ b/src/main/java/de/caritas/cob/videoservice/config/security/JwtAuthConverterProperties.java @@ -0,0 +1,16 @@ +package de.caritas.cob.videoservice.config.security; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; + +@Data +@Validated +@Configuration +@ConfigurationProperties(prefix = "jwt.auth.converter") +public class JwtAuthConverterProperties { + + private String resourceId; + private String principalAttribute; +} diff --git a/src/main/java/de/caritas/cob/videoservice/config/security/WebSecurityConfig.java b/src/main/java/de/caritas/cob/videoservice/config/security/WebSecurityConfig.java index 4e0f86b..0a34962 100644 --- a/src/main/java/de/caritas/cob/videoservice/config/security/WebSecurityConfig.java +++ b/src/main/java/de/caritas/cob/videoservice/config/security/WebSecurityConfig.java @@ -1,185 +1,125 @@ package de.caritas.cob.videoservice.config.security; -import static de.caritas.cob.videoservice.api.authorization.Authority.CONSULTANT; -import static de.caritas.cob.videoservice.api.authorization.Authority.JITSI_TECHNICAL; -import static de.caritas.cob.videoservice.api.authorization.Authority.USER; - -import de.caritas.cob.videoservice.api.authorization.RoleAuthorizationAuthorityMapper; -import de.caritas.cob.videoservice.config.SpringFoxConfig; +import de.caritas.cob.videoservice.api.authorization.Authority.AuthorityValue; +import de.caritas.cob.videoservice.filter.HttpTenantFilter; import de.caritas.cob.videoservice.filter.StatelessCsrfFilter; -import org.keycloak.adapters.KeycloakConfigResolver; -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; +import jakarta.annotation.Nullable; +import java.util.List; +import lombok.RequiredArgsConstructor; import org.keycloak.adapters.springsecurity.KeycloakConfiguration; -import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter; -import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter; -import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter; -import org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.HttpStatusEntryPoint; -import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.csrf.CsrfFilter; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** Configuration class to provide the Keycloak security configuration. */ @KeycloakConfiguration -public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { +@EnableWebSecurity +@RequiredArgsConstructor +public class WebSecurityConfig implements WebMvcConfigurer { private static final String UUID_PATTERN = "\\b[0-9a-f]{8}\\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\\b[0-9a-f]{12}\\b"; + public static final List WHITE_LIST = + List.of( + "/videocalls/docs", + "/videocalls/docs/**", + "/videocalls/event/stop", + "/v2/api-docs", + "/configuration/ui", + "/swagger-resources/**", + "/configuration/security", + "/swagger-ui", + "/swagger-ui/**", + "/webjars/**", + "/actuator/health", + "/actuator/health/**"); + + @Autowired AuthorisationService authorisationService; + @Autowired JwtAuthConverterProperties jwtAuthConverterProperties; + + @Autowired(required = false) + @Nullable + private HttpTenantFilter httpTenantFilter; + @Value("${csrf.cookie.property}") private String csrfCookieProperty; @Value("${csrf.header.property}") private String csrfHeaderProperty; + @Value("${multitenancy.enabled}") + private boolean multitenancy; + /** - * Configures the basic HTTP security behavior. - * - * @param http {@link HttpSecurity} + * Configure spring security filter chain: disable default Spring Boot CSRF token behavior and add + * custom {@link StatelessCsrfFilter}, set all sessions to be fully stateless, define necessary + * Keycloak roles for specific REST API paths */ - @Override - protected void configure(HttpSecurity http) throws Exception { - super.configure(http); - http.csrf() - .disable() - .addFilterBefore( - new StatelessCsrfFilter(csrfCookieProperty, csrfHeaderProperty), CsrfFilter.class) - .sessionManagement() + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + + var httpSecurity = + http.csrf() + .disable() + .addFilterBefore( + new StatelessCsrfFilter(csrfCookieProperty, csrfHeaderProperty), CsrfFilter.class); + + if (multitenancy) { + httpSecurity = + httpSecurity.addFilterAfter(httpTenantFilter, BearerTokenAuthenticationFilter.class); + } + + http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .sessionAuthenticationStrategy(sessionAuthenticationStrategy()) .and() .authorizeRequests() - .antMatchers(SpringFoxConfig.WHITE_LIST) + .requestMatchers(WHITE_LIST.toArray(String[]::new)) .permitAll() - .antMatchers("/videocalls/new") - .hasAuthority(CONSULTANT.getAuthority()) - .antMatchers("/videocalls/stop/{sessionId:" + UUID_PATTERN + "}") - .hasAnyAuthority(CONSULTANT.getAuthority()) - .antMatchers("/videocalls/join/{sessionId:" + UUID_PATTERN + "}") - .hasAnyAuthority(CONSULTANT.getAuthority()) - .antMatchers("/videocalls/event/stop/*") - .hasAnyAuthority(JITSI_TECHNICAL.getAuthority()) - .antMatchers("/videocalls/reject") - .hasAnyAuthority(USER.getAuthority(), CONSULTANT.getAuthority()) - .antMatchers("/videocalls/*/jwt") + .requestMatchers("/videocalls/new") + .hasAuthority(AuthorityValue.CONSULTANT) + .requestMatchers("/videocalls/stop/{sessionId:" + UUID_PATTERN + "}") + .hasAnyAuthority(AuthorityValue.CONSULTANT) + .requestMatchers("/videocalls/join/{sessionId:" + UUID_PATTERN + "}") + .hasAnyAuthority(AuthorityValue.CONSULTANT) + .requestMatchers("/videocalls/event/stop/*") + .hasAnyAuthority(AuthorityValue.JITSI_TECHNICAL) + .requestMatchers("/videocalls/reject") + .hasAnyAuthority(AuthorityValue.USER, AuthorityValue.CONSULTANT) + .requestMatchers("/videocalls/*/jwt") .permitAll() .anyRequest() .denyAll() .and() .exceptionHandling() .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)); - } - /** - * Uses the KeycloakSpringBootConfigResolver to be able to save the Keycloak settings in the - * Spring application.properties. - * - * @return {@link KeycloakConfigResolver} - */ - @Bean - public KeycloakConfigResolver keyCloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); + httpSecurity.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthConverter()); + return httpSecurity.build(); } /** - * Changes springs authentication strategy to be stateless (no session is being created). - * - * @return {@link SessionAuthenticationStrategy} + * Configure trailing slash match for all endpoints (needed as Spring Boot 3.0.0 changed default + * behaviour for trailing slash match) https://www.baeldung.com/spring-boot-3-migration (section + * 3.1) */ - @Bean @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new NullAuthenticatedSessionStrategy(); + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setUseTrailingSlashMatch(true); } - /** - * Changes the default AuthenticationProvider to {@link KeycloakAuthenticationProvider} and - * register it in the Spring security context. This maps the Keycloak roles to match the Spring - * security roles (prefix ROLE_). - * - * @param auth {@link AuthenticationManagerBuilder} - * @param authorityMapper custom {@link RoleAuthorizationAuthorityMapper} - */ - @Autowired - public void configureGlobal( - AuthenticationManagerBuilder auth, RoleAuthorizationAuthorityMapper authorityMapper) { - var keyCloakAuthProvider = keycloakAuthenticationProvider(); - keyCloakAuthProvider.setGrantedAuthoritiesMapper(authorityMapper); - - auth.authenticationProvider(keyCloakAuthProvider); - } - - /** - * From the Keycloak documentation: "Spring Boot attempts to eagerly register filter beans with - * the web application context. Therefore, when running the Keycloak Spring Security adapter in a - * Spring Boot environment, it may be necessary to add FilterRegistrationBeans to your security - * configuration to prevent the Keycloak filters from being registered twice.": ... - * - * @param filter {@link KeycloakAuthenticationProcessingFilter} - * @return {@link FilterRegistrationBean} - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean( - KeycloakAuthenticationProcessingFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - /** - * See above method keycloakAuthenticationProcessingFilterRegistrationBean(). - * - * @param filter {@link KeycloakPreAuthActionsFilter} - * @return {@link FilterRegistrationBean} - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean( - KeycloakPreAuthActionsFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - /** - * See above method keycloakAuthenticationProcessingFilterRegistrationBean(). - * - * @param filter {@link KeycloakAuthenticatedActionsFilter} - * @return {@link FilterRegistrationBean} - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean( - KeycloakAuthenticatedActionsFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - - /** - * See above method keycloakAuthenticationProcessingFilterRegistrationBean(). - * - * @param filter {@link KeycloakSecurityContextRequestFilter} - * @return {@link FilterRegistrationBean} - */ - @SuppressWarnings({"rawtypes", "unchecked"}) @Bean - public FilterRegistrationBean keycloakSecurityContextRequestFilterBean( - KeycloakSecurityContextRequestFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; + public JwtAuthConverter jwtAuthConverter() { + return new JwtAuthConverter(jwtAuthConverterProperties, authorisationService); } } diff --git a/src/main/java/de/caritas/cob/videoservice/filter/HttpTenantFilter.java b/src/main/java/de/caritas/cob/videoservice/filter/HttpTenantFilter.java index d044ddf..ea26042 100644 --- a/src/main/java/de/caritas/cob/videoservice/filter/HttpTenantFilter.java +++ b/src/main/java/de/caritas/cob/videoservice/filter/HttpTenantFilter.java @@ -2,14 +2,14 @@ import de.caritas.cob.videoservice.api.tenant.TenantContext; import de.caritas.cob.videoservice.api.tenant.TenantResolverService; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; diff --git a/src/main/java/de/caritas/cob/videoservice/filter/StatelessCsrfFilter.java b/src/main/java/de/caritas/cob/videoservice/filter/StatelessCsrfFilter.java index 99730ef..ac18c35 100644 --- a/src/main/java/de/caritas/cob/videoservice/filter/StatelessCsrfFilter.java +++ b/src/main/java/de/caritas/cob/videoservice/filter/StatelessCsrfFilter.java @@ -1,17 +1,17 @@ package de.caritas.cob.videoservice.filter; +import static de.caritas.cob.videoservice.config.security.WebSecurityConfig.WHITE_LIST; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; -import de.caritas.cob.videoservice.config.SpringFoxConfig; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.regex.Pattern; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.NonNull; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; @@ -73,8 +73,7 @@ public static final class DefaultRequiresCsrfMatcher implements RequestMatcher { */ @Override public boolean matches(HttpServletRequest request) { - - if (Arrays.stream(SpringFoxConfig.WHITE_LIST) + if (Arrays.stream(WHITE_LIST.toArray(String[]::new)) .parallel() .anyMatch(request.getRequestURI().toLowerCase()::contains)) { return false; diff --git a/src/main/resources/application-testing.properties b/src/main/resources/application-testing.properties index cb637d2..6999e1e 100644 --- a/src/main/resources/application-testing.properties +++ b/src/main/resources/application-testing.properties @@ -31,7 +31,9 @@ spring.liquibase.enabled=false spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.schema=classpath*:database/VideoServiceDatabase.sql,classpath*:database/VideoData.sql +spring.sql.init.schema-locations=classpath*:database/VideoServiceDatabase.sql,classpath*:database/VideoData.sql spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect + spring.jpa.open-in-view=false spring.jpa.hibernate.ddl-auto=none spring.data.jpa.repositories.bootstrap-mode=default diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b542b10..586fa72 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -72,4 +72,12 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDB103Dialect spring.datasource.url=jdbc:mariadb://localhost:3306/videoservice spring.datasource.username=videoservice -spring.datasource.password= \ No newline at end of file +spring.datasource.password= + +spring.security.oauth2.resourceserver.jwt.issuer-uri: https://localhost/auth/realms/onlineberatung +spring.security.oauth2.resourceserver.jwt.jwk-set-uri: https://localhost/auth/realms/onlineberatung/protocol/openid-connect/certs +spring.jwt.auth.converter.resource-id: app +spring.jwt.auth.converter.principal-attribute: preferred_username + +springdoc.api-docs.enabled=false +logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG diff --git a/src/test/java/de/caritas/cob/videoservice/ApiDefaultResponseEntityExceptionHandlerTest.java b/src/test/java/de/caritas/cob/videoservice/ApiDefaultResponseEntityExceptionHandlerTest.java index 44a165c..6eee9c7 100644 --- a/src/test/java/de/caritas/cob/videoservice/ApiDefaultResponseEntityExceptionHandlerTest.java +++ b/src/test/java/de/caritas/cob/videoservice/ApiDefaultResponseEntityExceptionHandlerTest.java @@ -1,41 +1,29 @@ package de.caritas.cob.videoservice; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.powermock.reflect.Whitebox.setInternalState; -import de.caritas.cob.videoservice.api.service.LogService; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.context.request.WebRequest; -@RunWith(MockitoJUnitRunner.class) -public class ApiDefaultResponseEntityExceptionHandlerTest { +@ExtendWith(MockitoExtension.class) +class ApiDefaultResponseEntityExceptionHandlerTest { @InjectMocks private ApiDefaultResponseEntityExceptionHandler exceptionHandler; - @Mock private Logger logger; - - @Before - public void setup() { - setInternalState(LogService.class, "LOGGER", logger); - } - @Test - public void handleInternal_Should_logInternalServerError_When_exceptionIsGiven() { + void handleInternal_Should_respondWithStatusInternalServerError_When_exceptionIsGiven() { RuntimeException exception = new RuntimeException("error"); - this.exceptionHandler.handleInternal(exception, mock(WebRequest.class)); + ResponseEntity objectResponseEntity = + this.exceptionHandler.handleInternal(exception, mock(WebRequest.class)); - verify(this.logger, times(1)) - .error(eq("VideoService API: 500 Internal Server Error: {}"), anyString()); + assertThat(objectResponseEntity.getStatusCode(), equalTo(HttpStatus.INTERNAL_SERVER_ERROR)); } } diff --git a/src/test/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandlerTest.java b/src/test/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandlerTest.java deleted file mode 100644 index e3eb640..0000000 --- a/src/test/java/de/caritas/cob/videoservice/ApiResponseEntityExceptionHandlerTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package de.caritas.cob.videoservice; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.powermock.reflect.Whitebox.setInternalState; -import static org.springframework.http.HttpStatus.NOT_FOUND; - -import de.caritas.cob.videoservice.api.exception.httpresponse.BadRequestException; -import de.caritas.cob.videoservice.api.exception.httpresponse.InternalServerErrorException; -import de.caritas.cob.videoservice.api.service.LogService; -import java.util.NoSuchElementException; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; -import org.springframework.http.HttpHeaders; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.server.ResponseStatusException; - -@RunWith(MockitoJUnitRunner.class) -public class ApiResponseEntityExceptionHandlerTest { - - @InjectMocks private ApiResponseEntityExceptionHandler exceptionHandler; - - @Mock private Logger logger; - - @Before - public void setup() { - setInternalState(LogService.class, "LOGGER", logger); - } - - @Test - public void handleCustomBadRequest_Should_executeLogging_When_badRequestIsGiven() { - BadRequestException badRequestException = - new BadRequestException("test", LogService::logWarning); - - this.exceptionHandler.handleCustomBadRequest(badRequestException, mock(WebRequest.class)); - - verify(logger, times(1)).warn(eq("VideoService API: {}"), anyString()); - } - - @Test - public void - handleNoSuchElementException_Should_executeLogging_When_noSuchElementExceptionRequestIsGiven() { - NoSuchElementException noSuchElementException = new NoSuchElementException("test"); - - this.exceptionHandler.handleNoSuchElementException( - noSuchElementException, mock(WebRequest.class)); - - verify(logger, times(1)).warn(eq("VideoService API: {}: {}"), eq("Not Found"), anyString()); - } - - @Test - public void handleMethodArgumentNotValid_Should_executeLogging() { - this.exceptionHandler.handleMethodArgumentNotValid( - mock(MethodArgumentNotValidException.class), - new HttpHeaders(), - NOT_FOUND, - mock(WebRequest.class)); - - verify(logger, times(1)).warn(eq("VideoService API: {}: {}"), eq("Not Found"), anyString()); - } - - @Test - public void handleInternal_Should_executeLogging_When_RuntimeExceptionIsGiven() { - RuntimeException runtimeException = new RuntimeException("test"); - - this.exceptionHandler.handleInternal(runtimeException, mock(WebRequest.class)); - - verify(logger, times(1)) - .error(eq("VideoService API: 500 Internal Server Error: {}"), anyString()); - } - - @Test - public void handleInternal_Should_executeLogging_When_InternalServerErrorIsGiven() { - InternalServerErrorException exception = new InternalServerErrorException("error"); - - this.exceptionHandler.handleInternal(exception, mock(WebRequest.class)); - - verify(logger, times(1)) - .error(eq("VideoService API: 500 Internal Server Error: {}"), anyString()); - } - - @Test - public void handleInternal_Should_executeLogging_When_ResponseStatusExceptionIsGiven() { - ResponseStatusException exception = new ResponseStatusException(NOT_FOUND); - - this.exceptionHandler.handleInternal(exception, mock(WebRequest.class)); - - verify(logger, times(1)).warn(eq("VideoService API: {}"), anyString()); - } - - @Test - public void handleInternal_Should_executeLogging_When_HttpClientErrorExceptionIsGiven() { - HttpClientErrorException exception = new HttpClientErrorException(NOT_FOUND); - - this.exceptionHandler.handleInternal(exception, mock(WebRequest.class)); - - verify(logger, times(1)).error(eq("VideoService API: {}"), anyString()); - } -} diff --git a/src/test/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthoritiesMapperTest.java b/src/test/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthoritiesMapperTest.java index 7beac9d..fefa86b 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthoritiesMapperTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/authorization/RoleAuthorizationAuthoritiesMapperTest.java @@ -1,12 +1,12 @@ package de.caritas.cob.videoservice.api.authorization; -import static de.caritas.cob.videoservice.api.authorization.Authority.CONSULTANT; import static de.caritas.cob.videoservice.api.testhelper.TestConstants.ROLE_CONSULTANT; import static java.util.Collections.emptyList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import de.caritas.cob.videoservice.api.authorization.Authority.AuthorityValue; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -32,7 +32,7 @@ public void mapAuthorities_Should_returnGrantedConsultantAuthority_When_authorit this.roleAuthorizationAuthorityMapper.mapAuthorities(grantedAuthorities); assertThat(mappedAuthorities, hasSize(1)); - assertThat(mappedAuthorities.iterator().next().getAuthority(), is(CONSULTANT.getAuthority())); + assertThat(mappedAuthorities.iterator().next().getAuthority(), is(AuthorityValue.CONSULTANT)); } @Test @@ -47,7 +47,7 @@ public void mapAuthorities_Should_returnGrantedConsultantAuthority_When_authorit this.roleAuthorizationAuthorityMapper.mapAuthorities(grantedAuthorities); assertThat(mappedAuthorities, hasSize(1)); - assertThat(mappedAuthorities.iterator().next().getAuthority(), is(CONSULTANT.getAuthority())); + assertThat(mappedAuthorities.iterator().next().getAuthority(), is(AuthorityValue.CONSULTANT)); } @Test diff --git a/src/test/java/de/caritas/cob/videoservice/api/config/resttemplate/CustomResponseErrorHandlerTest.java b/src/test/java/de/caritas/cob/videoservice/api/config/resttemplate/CustomResponseErrorHandlerTest.java index c1e9426..d1c13ad 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/config/resttemplate/CustomResponseErrorHandlerTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/config/resttemplate/CustomResponseErrorHandlerTest.java @@ -46,7 +46,7 @@ public class CustomResponseErrorHandlerTest { handleErrorGet(url); fail("Exception was not thrown"); } catch (ResponseStatusException e) { - assertThat(e.getStatus(), is(HttpStatus.FORBIDDEN)); + assertThat(e.getStatusCode(), is(HttpStatus.FORBIDDEN)); assertThat(e.getReason(), is("GET http://test.de")); } } @@ -62,7 +62,7 @@ public class CustomResponseErrorHandlerTest { handleErrorGet(url); fail("Exception was not thrown"); } catch (ResponseStatusException e) { - assertThat(e.getStatus(), is(HttpStatus.NOT_FOUND)); + assertThat(e.getStatusCode(), is(HttpStatus.NOT_FOUND)); assertThat(e.getReason(), is("GET http://test.de")); } } @@ -86,7 +86,7 @@ private void handleErrorPost(URL url) throws IOException, URISyntaxException { handleErrorPost(url); fail("Exception was not thrown"); } catch (ResponseStatusException e) { - assertThat(e.getStatus(), is(HttpStatus.BAD_REQUEST)); + assertThat(e.getStatusCode(), is(HttpStatus.BAD_REQUEST)); assertThat(e.getReason(), is("POST http://test.de")); } } diff --git a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerAuthorizationIT.java b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerAuthorizationIT.java index f9001cc..e20e87b 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerAuthorizationIT.java +++ b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerAuthorizationIT.java @@ -28,7 +28,7 @@ import de.caritas.cob.videoservice.api.model.RejectVideoCallDTO; import de.caritas.cob.videoservice.api.service.RejectVideoCallService; import de.caritas.cob.videoservice.api.service.video.jwt.TokenGeneratorService; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerE2eIT.java b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerE2eIT.java index 82bf2a5..1d88810 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerE2eIT.java +++ b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerE2eIT.java @@ -9,11 +9,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.model.RejectVideoCallDTO; import de.caritas.cob.videoservice.api.service.RejectVideoCallService; import de.caritas.cob.videoservice.api.service.session.ChatService; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ class VideoControllerE2eIT { @MockBean @SuppressWarnings("unused") - private VideoUser authenticatedUser; + private AuthenticatedUser authenticatedUser; @MockBean ChatService chatService; diff --git a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerIT.java b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerIT.java index b57a6fd..1662d63 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerIT.java +++ b/src/test/java/de/caritas/cob/videoservice/api/controller/VideoControllerIT.java @@ -20,6 +20,8 @@ import de.caritas.cob.videoservice.api.model.RejectVideoCallDTO; import de.caritas.cob.videoservice.api.service.RejectVideoCallService; import de.caritas.cob.videoservice.api.service.video.VideoCallUrlGeneratorService; +import de.caritas.cob.videoservice.config.security.AuthorisationService; +import de.caritas.cob.videoservice.config.security.JwtAuthConverterProperties; import java.util.UUID; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,6 +44,10 @@ public class VideoControllerIT { @MockBean private RejectVideoCallService rejectVideoCallService; + @MockBean private AuthorisationService authorisationService; + + @MockBean private JwtAuthConverterProperties jwtAuthConverterProperties; + @MockBean @SuppressWarnings("unused") private RoleAuthorizationAuthorityMapper roleAuthorizationAuthorityMapper; diff --git a/src/test/java/de/caritas/cob/videoservice/api/facade/VideoCallFacadeTest.java b/src/test/java/de/caritas/cob/videoservice/api/facade/VideoCallFacadeTest.java index 43efecc..6e3b89e 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/facade/VideoCallFacadeTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/facade/VideoCallFacadeTest.java @@ -11,6 +11,7 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -19,7 +20,7 @@ import static org.mockito.Mockito.when; import com.google.common.collect.Lists; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.exception.httpresponse.BadRequestException; import de.caritas.cob.videoservice.api.model.CreateVideoCallDTO; import de.caritas.cob.videoservice.api.model.VideoCallResponseDTO; @@ -47,24 +48,24 @@ import java.util.Objects; import java.util.Optional; import org.jeasy.random.EasyRandom; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.security.access.AccessDeniedException; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.util.ReflectionTestUtils; -@RunWith(SpringRunner.class) -public class VideoCallFacadeTest { +@ExtendWith(SpringExtension.class) +class VideoCallFacadeTest { @InjectMocks private VideoCallFacade videoCallFacade; @Mock private SessionService sessionService; @Mock private LiveEventNotificationService liveEventNotificationService; @Mock private VideoCallUrlGeneratorService videoCallUrlGeneratorService; - @Mock private VideoUser authenticatedUser; + @Mock private AuthenticatedUser authenticatedUser; @Mock private UuidRegistry uuidRegistry; @Mock private StatisticsService statisticsService; @@ -75,12 +76,13 @@ public class VideoCallFacadeTest { @Mock private MessageService messageService; @Test - public void startVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { + void startVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); ConsultantSessionDTO consultantSessionDto = mock(ConsultantSessionDTO.class); when(consultantSessionDto.getStatus()).thenReturn(IN_PROGRESS.getValue()); + when(consultantSessionDto.getAskerId()).thenReturn("askerId"); VideoCallUrls videoCallUrls = new EasyRandom().nextObject(VideoCallUrls.class); when(sessionService.findSessionOfCurrentConsultant(SESSION_ID)) @@ -96,8 +98,7 @@ public void startVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGenerated } @Test - public void - startGroupVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { + void startGroupVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); @@ -132,8 +133,8 @@ public void startVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGenerated assertThat(captor.getValue()).containsExactlyInAnyOrder("anotherUserId"); } - @Test(expected = AccessDeniedException.class) - public void startGroupVideoCall_Should_ThrowForbiddenException_When_UserDoesNotHavePermissions() { + @Test + void startGroupVideoCall_Should_ThrowForbiddenException_When_UserDoesNotHavePermissions() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); @@ -142,13 +143,15 @@ public void startGroupVideoCall_Should_ThrowForbiddenException_When_UserDoesNotH .when(chatService) .assertCanModerateChat(GROUP_CHAT_ID); - // when - videoCallFacade.startVideoCall(new CreateVideoCallDTO().groupChatId(GROUP_CHAT_ID), "rcUserId"); + // when, then + CreateVideoCallDTO createVideoCallRequest = new CreateVideoCallDTO().groupChatId(GROUP_CHAT_ID); + assertThrows( + AccessDeniedException.class, + () -> videoCallFacade.startVideoCall(createVideoCallRequest, "rcUserId")); } @Test - public void - joinGroupVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { + void joinGroupVideoCall_Should_ReturnCorrectVideoCallUrl_When_UrlWasGeneratedSuccessfully() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); @@ -159,6 +162,7 @@ public void startGroupVideoCall_Should_ThrowForbiddenException_When_UserDoesNotH VideoRoomEntity videoRoomEntity = new EasyRandom().nextObject(VideoRoomEntity.class); videoRoomEntity.setGroupChatId(GROUP_CHAT_ID); + videoRoomEntity.setSessionId(null); when(videoRoomService.findByJitsiRoomId(VIDEO_CALL_UUID)) .thenReturn(Optional.of(videoRoomEntity)); @@ -172,18 +176,19 @@ public void startGroupVideoCall_Should_ThrowForbiddenException_When_UserDoesNotH assertThat(result.getModeratorVideoCallUrl()).isEqualTo(videoCallUrls.getModeratorVideoUrl()); } - @Test(expected = NoSuchElementException.class) - public void joinGroupVideoCall_Should_ThrowNoSuchElementException_When_GivenChatNotFound() { - // when - videoCallFacade.joinGroupVideoCall(VIDEO_CALL_UUID); + @Test + void joinGroupVideoCall_Should_ThrowNoSuchElementException_When_GivenChatNotFound() { + assertThrows( + NoSuchElementException.class, () -> videoCallFacade.joinGroupVideoCall(VIDEO_CALL_UUID)); } - @Test(expected = AccessDeniedException.class) - public void joinGroupVideoCall_Should_ThrowForbiddenException_When_UserIsNotModerator() { + @Test + void joinGroupVideoCall_Should_ThrowForbiddenException_When_UserIsNotModerator() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); VideoRoomEntity videoRoomEntity = new EasyRandom().nextObject(VideoRoomEntity.class); + videoRoomEntity.setSessionId(null); videoRoomEntity.setGroupChatId(GROUP_CHAT_ID); when(videoRoomService.findByJitsiRoomId(VIDEO_CALL_UUID)) .thenReturn(Optional.of(videoRoomEntity)); @@ -193,11 +198,12 @@ public void joinGroupVideoCall_Should_ThrowForbiddenException_When_UserIsNotMode .assertCanModerateChat(GROUP_CHAT_ID); // when - videoCallFacade.joinGroupVideoCall(VIDEO_CALL_UUID); + assertThrows( + AccessDeniedException.class, () -> videoCallFacade.joinGroupVideoCall(VIDEO_CALL_UUID)); } @Test - public void + void startVideoCall_Should_CallLiveServiceAndBuildCorrectLiveEventMessageWithVideoCallRequestDto() { // given @@ -228,8 +234,8 @@ public void joinGroupVideoCall_Should_ThrowForbiddenException_When_UserIsNotMode assertEquals(USERNAME, eventContent.getInitiatorUsername()); } - @Test(expected = BadRequestException.class) - public void startVideoCall_Should_throwBadRequestException_When_sessionIsNotInProgress() { + @Test + void startVideoCall_Should_throwBadRequestException_When_sessionIsNotInProgress() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); @@ -239,17 +245,21 @@ public void startVideoCall_Should_throwBadRequestException_When_sessionIsNotInPr .thenReturn(consultantSessionDto); // when - videoCallFacade.startVideoCall(new CreateVideoCallDTO().sessionId(SESSION_ID), ""); + CreateVideoCallDTO createVideoCallRequest = new CreateVideoCallDTO().sessionId(SESSION_ID); + assertThrows( + BadRequestException.class, + () -> videoCallFacade.startVideoCall(createVideoCallRequest, "")); } @Test - public void startVideoCall_Should_FireAssignSessionStatisticsEvent() { + void startVideoCall_Should_FireAssignSessionStatisticsEvent() { // given when(authenticatedUser.getUserId()).thenReturn(CONSULTANT_ID); when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); ConsultantSessionDTO consultantSessionDto = mock(ConsultantSessionDTO.class); when(consultantSessionDto.getStatus()).thenReturn(IN_PROGRESS.getValue()); + when(consultantSessionDto.getAskerId()).thenReturn("askerId"); VideoCallUrls videoCallUrls = new EasyRandom().nextObject(VideoCallUrls.class); when(sessionService.findSessionOfCurrentConsultant(SESSION_ID)) @@ -283,7 +293,7 @@ public void startVideoCall_Should_FireAssignSessionStatisticsEvent() { } @Test - public void + void startVideoCall_Should_FireAssignSessionStatisticsEventWithDisplayName_When_initiatorDisplayNameIsSet() { // given @@ -291,6 +301,7 @@ public void startVideoCall_Should_FireAssignSessionStatisticsEvent() { when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); ConsultantSessionDTO consultantSessionDto = mock(ConsultantSessionDTO.class); when(consultantSessionDto.getStatus()).thenReturn(IN_PROGRESS.getValue()); + when(consultantSessionDto.getAskerId()).thenReturn("askerId"); VideoCallUrls videoCallUrls = new EasyRandom().nextObject(VideoCallUrls.class); when(sessionService.findSessionOfCurrentConsultant(SESSION_ID)) @@ -315,7 +326,7 @@ public void startVideoCall_Should_FireAssignSessionStatisticsEvent() { } @Test - public void handleVideoCallStoppedEvent_Should_StopPeristentVideoCallRoom() { + void handleVideoCallStoppedEvent_Should_StopPeristentVideoCallRoom() { // given when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); @@ -338,7 +349,7 @@ public void handleVideoCallStoppedEvent_Should_StopPeristentVideoCallRoom() { } @Test - public void handleVideoCallStoppedEvent_Should_StopPeristentVideoCallRoomForOneToOneCall() { + void handleVideoCallStoppedEvent_Should_StopPeristentVideoCallRoomForOneToOneCall() { // given when(uuidRegistry.generateUniqueUuid()).thenReturn(VIDEO_CALL_UUID); diff --git a/src/test/java/de/caritas/cob/videoservice/api/helper/JsonHelperTest.java b/src/test/java/de/caritas/cob/videoservice/api/helper/JsonHelperTest.java index afc0fa7..a0b0070 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/helper/JsonHelperTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/helper/JsonHelperTest.java @@ -63,7 +63,9 @@ public void serialize_Should_returnOptionalWithSerializedObject() { + "\"," + " \"videoCallUuid\":\"" + uuid - + "\"" + + "\"," + + "\"adviceSeekerId\": null," + + "\"tenantId\": null" + "}"; assertThat(result.get(), jsonEquals(expectedJson)); diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/LogServiceTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/LogServiceTest.java deleted file mode 100644 index e976379..0000000 --- a/src/test/java/de/caritas/cob/videoservice/api/service/LogServiceTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package de.caritas.cob.videoservice.api.service; - -import static de.caritas.cob.videoservice.api.service.LogService.STATISTICS_EVENT_PROCESSING_ERROR; -import static de.caritas.cob.videoservice.api.service.LogService.STATISTICS_EVENT_PROCESSING_WARNING; -import static javax.servlet.RequestDispatcher.ERROR_MESSAGE; -import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.powermock.reflect.Whitebox.setInternalState; - -import java.io.PrintWriter; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; -import org.springframework.http.HttpStatus; - -@RunWith(MockitoJUnitRunner.class) -public class LogServiceTest { - - @Mock Exception exception; - - @Mock private Logger logger; - - public static final Exception EXCEPTION = new Exception(); - - @Before - public void setup() { - setInternalState(LogService.class, "LOGGER", logger); - } - - @Test - public void logInfo_Should_LogInfoMessage() { - LogService.logInfo("info message"); - - verify(logger, atLeastOnce()).info("info message"); - } - - @Test - public void logWarning_Should_LogWarnMessage_When_onlyExceptionIsProvided() { - LogService.logWarning(exception); - - verify(logger, atLeastOnce()).warn(eq("VideoService API: {}"), anyString()); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logWarning_Should_LogWarnMessage_When_onlyExceptionAndStatusProvided() { - LogService.logWarning(HttpStatus.MULTI_STATUS, exception); - - verify(logger, atLeastOnce()) - .warn(eq("VideoService API: {}: {}"), eq("Multi-Status"), anyString()); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logInternalServerError_Should_LogError() { - LogService.logInternalServerError(exception); - - verify(logger, atLeastOnce()) - .error(eq("VideoService API: 500 Internal Server Error: {}"), anyString()); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logError_Should_LogError() { - LogService.logError(exception); - - verify(logger, atLeastOnce()).error(eq("VideoService API: {}"), anyString()); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logStatisticEventError_Should_LogExceptionStackTraceAndErrorMessage() { - - LogService.logStatisticsEventError(EXCEPTION); - verify(logger, times(1)) - .error(anyString(), eq(STATISTICS_EVENT_PROCESSING_ERROR), eq(getStackTrace(EXCEPTION))); - } - - @Test - public void logStatisticEventWarning_Should_LogErrorMessageAsWarning() { - - LogService.logStatisticsEventWarning(ERROR_MESSAGE); - verify(logger, times(1)) - .warn(anyString(), eq(STATISTICS_EVENT_PROCESSING_WARNING), eq(ERROR_MESSAGE)); - } -} diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/SessionServiceTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/SessionServiceTest.java index f4b719a..a26cab3 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/SessionServiceTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/SessionServiceTest.java @@ -21,9 +21,9 @@ import de.caritas.cob.videoservice.userservice.generated.ApiClient; import de.caritas.cob.videoservice.userservice.generated.web.UserControllerApi; import de.caritas.cob.videoservice.userservice.generated.web.model.ConsultantSessionDTO; +import jakarta.servlet.http.HttpServletRequest; import java.util.Enumeration; import java.util.List; -import javax.servlet.http.HttpServletRequest; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/TenantHeaderSupplierTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/TenantHeaderSupplierTest.java index 8fecfc0..5461149 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/TenantHeaderSupplierTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/TenantHeaderSupplierTest.java @@ -9,7 +9,7 @@ import de.caritas.cob.videoservice.api.service.httpheader.TenantHeaderSupplier; import de.caritas.cob.videoservice.api.tenant.TenantContext; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.web.context.request.RequestContextHolder; diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/UuidRegistryTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/UuidRegistryTest.java index 0e55ffa..d969148 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/UuidRegistryTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/UuidRegistryTest.java @@ -1,31 +1,24 @@ package de.caritas.cob.videoservice.api.service; -import static de.caritas.cob.videoservice.api.testhelper.FieldConstants.FIELD_NAME_GENERATED_UUIDS; +import static de.caritas.cob.videoservice.api.service.UuidRegistry.GENERATED_UUIDS; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.powermock.reflect.Whitebox.setInternalState; -import java.util.List; import java.util.UUID; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; -@RunWith(PowerMockRunner.class) +@RunWith(MockitoJUnitRunner.class) public class UuidRegistryTest { - @InjectMocks private UuidRegistry uuidRegistry; - @Mock private List uuidList; + private UuidRegistry uuidRegistry = new UuidRegistry(); @Before public void setUp() { - setInternalState(UuidRegistry.class, FIELD_NAME_GENERATED_UUIDS, uuidList); uuidRegistry.cleanUpUuidRegistry(); } @@ -41,15 +34,12 @@ public void generateUniqueUuid_Should_AddGeneratedUuidToRegistry() { String response = uuidRegistry.generateUniqueUuid(); assertThat(UUID.fromString(response), instanceOf(UUID.class)); - verify(uuidList, times(1)).add(UUID.fromString(response)); + assertThat(GENERATED_UUIDS.size(), equalTo(1)); } @Test public void cleanUpEntireList_Should_cleanListOfUuids() { - uuidList.add(UUID.randomUUID()); - uuidRegistry.cleanUpUuidRegistry(); - - assertEquals(0, uuidList.size()); + assertEquals(0, GENERATED_UUIDS.size()); } } diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplierTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplierTest.java index a494056..5ef34ab 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplierTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/httpheader/SecurityHeaderSupplierTest.java @@ -10,7 +10,7 @@ import static org.mockito.Mockito.when; import static org.springframework.test.util.ReflectionTestUtils.setField; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,7 +24,7 @@ public class SecurityHeaderSupplierTest { @InjectMocks private SecurityHeaderSupplier securityHeaderSupplier; - @Mock private VideoUser videoUser; + @Mock private AuthenticatedUser videoUser; @Before public void setup() { diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceIT.java b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceIT.java index 9d97617..5bb151e 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceIT.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceIT.java @@ -44,7 +44,7 @@ public void fireEvent_Should_Send_ExpectedAssignSessionStatisticsEventMessageToQ UUID uuid = UUID.randomUUID(); StartVideoCallStatisticsEvent startVideoCallStatisticsEvent = new StartVideoCallStatisticsEvent( - CONSULTANT_ID, UserRole.CONSULTANT, SESSION_ID, uuid.toString(), ADVICESEEKER_ID); + CONSULTANT_ID, UserRole.CONSULTANT, SESSION_ID, uuid.toString(), ADVICESEEKER_ID, 1L); statisticsService.fireEvent(startVideoCallStatisticsEvent); Message message = @@ -73,7 +73,8 @@ public void fireEvent_Should_Send_ExpectedAssignSessionStatisticsEventMessageToQ + "\"," + " \"videoCallUuid\":\"" + uuid - + "\"" + + "\"," + + "\"tenantId\":1" + "}"; assertThat( diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceTest.java index 65a3ddb..af1b3cb 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/StatisticsServiceTest.java @@ -4,29 +4,27 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import static org.powermock.reflect.Whitebox.setInternalState; import static org.springframework.test.util.ReflectionTestUtils.setField; -import de.caritas.cob.videoservice.api.service.LogService; import de.caritas.cob.videoservice.api.service.statistics.event.StartVideoCallStatisticsEvent; import de.caritas.cob.videoservice.statisticsservice.generated.web.model.EventType; import java.nio.charset.StandardCharsets; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessageProperties; -@RunWith(MockitoJUnitRunner.class) -public class StatisticsServiceTest { +@ExtendWith(MockitoExtension.class) +class StatisticsServiceTest { private static final String FIELD_NAME_STATISTICS_ENABLED = "statisticsEnabled"; private static final String FIELD_NAME_RABBIT_EXCHANGE_NAME = "rabbitMqExchangeName"; @@ -38,19 +36,15 @@ public class StatisticsServiceTest { @InjectMocks private StatisticsService statisticsService; @Mock private AmqpTemplate amqpTemplate; - @Mock Logger logger; - @Before - public void setup() { + @BeforeEach + void setup() { startVideoCallStatisticsEvent = Mockito.mock(StartVideoCallStatisticsEvent.class); - when(startVideoCallStatisticsEvent.getEventType()).thenReturn(eventType); - when(startVideoCallStatisticsEvent.getPayload()).thenReturn(Optional.of(PAYLOAD)); - setInternalState(LogService.class, "LOGGER", logger); setField(statisticsService, FIELD_NAME_RABBIT_EXCHANGE_NAME, RABBIT_EXCHANGE_NAME); } @Test - public void fireEvent_Should_NotSendStatisticsMessage_WhenStatisticsIsDisabled() { + void fireEvent_Should_NotSendStatisticsMessage_WhenStatisticsIsDisabled() { setField(statisticsService, FIELD_NAME_STATISTICS_ENABLED, false); statisticsService.fireEvent(startVideoCallStatisticsEvent); @@ -59,8 +53,10 @@ public void fireEvent_Should_NotSendStatisticsMessage_WhenStatisticsIsDisabled() } @Test - public void fireEvent_Should_SendStatisticsMessage_WhenStatisticsIsEnabled() { + void fireEvent_Should_SendStatisticsMessage_WhenStatisticsIsEnabled() { + when(startVideoCallStatisticsEvent.getEventType()).thenReturn(eventType); + when(startVideoCallStatisticsEvent.getPayload()).thenReturn(Optional.of(PAYLOAD)); setField(statisticsService, FIELD_NAME_STATISTICS_ENABLED, true); when(startVideoCallStatisticsEvent.getEventType()).thenReturn(eventType); when(startVideoCallStatisticsEvent.getPayload()).thenReturn(Optional.of(PAYLOAD)); @@ -71,17 +67,19 @@ public void fireEvent_Should_SendStatisticsMessage_WhenStatisticsIsEnabled() { } @Test - public void fireEvent_Should_LogWarning_WhenPayloadIsEmpty() { + void fireEvent_Should_NotSendAmqpMessage_WhenPayloadIsEmpty() { setField(statisticsService, FIELD_NAME_STATISTICS_ENABLED, true); when(startVideoCallStatisticsEvent.getPayload()).thenReturn(Optional.empty()); statisticsService.fireEvent(startVideoCallStatisticsEvent); - verify(logger, times(1)).warn(anyString(), anyString(), anyString()); + verifyNoInteractions(amqpTemplate); } @Test - public void fireEvent_Should_UseEventTypeAsTopicAndSendPayloadOfEvent() { + void fireEvent_Should_UseEventTypeAsTopicAndSendPayloadOfEvent() { + when(startVideoCallStatisticsEvent.getEventType()).thenReturn(eventType); + when(startVideoCallStatisticsEvent.getPayload()).thenReturn(Optional.of(PAYLOAD)); setField(statisticsService, FIELD_NAME_STATISTICS_ENABLED, true); statisticsService.fireEvent(startVideoCallStatisticsEvent); verify(amqpTemplate, times(1)) diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/event/StartVideoCallStatisticsEventTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/event/StartVideoCallStatisticsEventTest.java index 93c7fc2..52b8b31 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/statistics/event/StartVideoCallStatisticsEventTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/statistics/event/StartVideoCallStatisticsEventTest.java @@ -27,13 +27,15 @@ public class StartVideoCallStatisticsEventTest { @Before public void setup() { uuid = UUID.randomUUID(); + adviceSeekerUuid = UUID.randomUUID(); startVideoCallStatisticsEvent = new StartVideoCallStatisticsEvent( CONSULTANT_ID, UserRole.CONSULTANT, SESSION_ID, uuid.toString(), - adviceSeekerUuid.toString()); + adviceSeekerUuid.toString(), + 1L); } @Test @@ -64,7 +66,11 @@ public void getPayload_Should_ReturnValidJsonPayload() { + "\"," + " \"videoCallUuid\":\"" + uuid - + "\"" + + "\"," + + " \"adviceSeekerId\":\"" + + adviceSeekerUuid + + "\"," + + " \"tenantId\":1" + "}"; Optional result = startVideoCallStatisticsEvent.getPayload(); diff --git a/src/test/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorServiceTest.java b/src/test/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorServiceTest.java index 7e2c519..8765edd 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorServiceTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/service/video/jwt/TokenGeneratorServiceTest.java @@ -13,7 +13,7 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.impl.NullClaim; import com.auth0.jwt.interfaces.DecodedJWT; -import de.caritas.cob.videoservice.api.authorization.VideoUser; +import de.caritas.cob.videoservice.api.authorization.AuthenticatedUser; import de.caritas.cob.videoservice.api.exception.httpresponse.InternalServerErrorException; import de.caritas.cob.videoservice.api.service.video.jwt.model.VideoCallToken; import org.junit.Before; @@ -32,7 +32,7 @@ public class TokenGeneratorServiceTest { @InjectMocks private TokenGeneratorService tokenGeneratorService; - @Mock private VideoUser authenticatedUser; + @Mock private AuthenticatedUser authenticatedUser; @Before public void setup() { diff --git a/src/test/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolverTest.java b/src/test/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolverTest.java index 539333d..06fc083 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/tenant/AccessTokenTenantResolverTest.java @@ -4,9 +4,9 @@ import static org.mockito.Mockito.when; import com.google.common.collect.Maps; +import jakarta.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; diff --git a/src/test/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolverTest.java b/src/test/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolverTest.java index a765077..52d3e1d 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/tenant/CustomHeaderTenantResolverTest.java @@ -4,8 +4,8 @@ import static org.mockito.Mockito.when; import de.caritas.cob.videoservice.api.service.httpheader.TenantHeaderSupplier; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; diff --git a/src/test/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolverTest.java b/src/test/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolverTest.java index 5b19aa8..c83d80e 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/tenant/SubdomainTenantResolverTest.java @@ -5,8 +5,8 @@ import de.caritas.cob.videoservice.api.service.TenantService; import de.caritas.cob.videoservice.filter.SubdomainExtractor; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; diff --git a/src/test/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolverTest.java b/src/test/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolverTest.java index 87b365c..19694f1 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/tenant/TechnicalUserTenantResolverTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.assertj.core.util.Sets; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/src/test/java/de/caritas/cob/videoservice/api/tenant/TenantResolverServiceTest.java b/src/test/java/de/caritas/cob/videoservice/api/tenant/TenantResolverServiceTest.java index a704387..2bbb9b9 100644 --- a/src/test/java/de/caritas/cob/videoservice/api/tenant/TenantResolverServiceTest.java +++ b/src/test/java/de/caritas/cob/videoservice/api/tenant/TenantResolverServiceTest.java @@ -4,8 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; +import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; diff --git a/src/test/java/de/caritas/cob/videoservice/config/apiclient/LiveServiceApiClientConfigIT.java b/src/test/java/de/caritas/cob/videoservice/config/apiclient/LiveServiceApiClientConfigIT.java index d17ce5e..94696d3 100644 --- a/src/test/java/de/caritas/cob/videoservice/config/apiclient/LiveServiceApiClientConfigIT.java +++ b/src/test/java/de/caritas/cob/videoservice/config/apiclient/LiveServiceApiClientConfigIT.java @@ -5,18 +5,18 @@ import de.caritas.cob.videoservice.VideoServiceApplication; import de.caritas.cob.videoservice.liveservice.generated.web.LiveControllerApi; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest(classes = VideoServiceApplication.class) @TestPropertySource(properties = "spring.profiles.active=testing") -public class LiveServiceApiClientConfigIT { +class LiveServiceApiClientConfigIT { @Autowired private LiveControllerApi liveControllerApi; @@ -24,7 +24,7 @@ public class LiveServiceApiClientConfigIT { private String liveServiceApiUrl; @Test - public void configureLiveControllerApi_Should_setCorrectApiUrl() { + void configureLiveControllerApi_Should_setCorrectApiUrl() { String apiClientUrl = this.liveControllerApi.getApiClient().getBasePath(); assertThat(apiClientUrl, is(this.liveServiceApiUrl)); diff --git a/src/test/java/de/caritas/cob/videoservice/config/apiclient/UserServiceApiClientConfigIT.java b/src/test/java/de/caritas/cob/videoservice/config/apiclient/UserServiceApiClientConfigIT.java index 1f50045..66794ce 100644 --- a/src/test/java/de/caritas/cob/videoservice/config/apiclient/UserServiceApiClientConfigIT.java +++ b/src/test/java/de/caritas/cob/videoservice/config/apiclient/UserServiceApiClientConfigIT.java @@ -5,18 +5,18 @@ import de.caritas.cob.videoservice.VideoServiceApplication; import de.caritas.cob.videoservice.userservice.generated.web.UserControllerApi; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest(classes = VideoServiceApplication.class) @TestPropertySource(properties = "spring.profiles.active=testing") -public class UserServiceApiClientConfigIT { +class UserServiceApiClientConfigIT { @Autowired private UserControllerApi userControllerApi; @@ -24,7 +24,7 @@ public class UserServiceApiClientConfigIT { private String userServiceApiUrl; @Test - public void configureLiveControllerApi_Should_setCorrectApiUrl() { + void configureLiveControllerApi_Should_setCorrectApiUrl() { String apiClientUrl = this.userControllerApi.getApiClient().getBasePath(); assertThat(apiClientUrl, is(this.userServiceApiUrl)); diff --git a/src/test/java/de/caritas/cob/videoservice/filter/HttpTenantFilterTest.java b/src/test/java/de/caritas/cob/videoservice/filter/HttpTenantFilterTest.java index e9a1aa6..0361377 100644 --- a/src/test/java/de/caritas/cob/videoservice/filter/HttpTenantFilterTest.java +++ b/src/test/java/de/caritas/cob/videoservice/filter/HttpTenantFilterTest.java @@ -1,11 +1,11 @@ package de.caritas.cob.videoservice.filter; import de.caritas.cob.videoservice.api.tenant.TenantResolverService; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks;