From 8946113252b0e3fdd649f36782e55e3b7b42735c Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Fri, 12 Apr 2024 16:40:13 +0200 Subject: [PATCH 1/6] fix: partial commit --- .github/workflows/dockerImage.yml | 2 +- .github/workflows/dockerImageSkipTests.yml | 2 +- .github/workflows/feature-branch.yml | 2 +- api/messageservice.yaml | 4 - pom.xml | 113 ++++++++---- .../MessageServiceApplication.java | 2 +- .../caritas/cob/messageservice/Messenger.java | 17 +- .../ApiResponseEntityExceptionHandler.java | 42 +---- .../api/authorization/Authority.java | 25 ++- .../RoleAuthorizationAuthorityMapper.java | 13 +- .../CustomSwaggerUIApiResourceController.java | 22 --- .../api/controller/MessageController.java | 46 ++--- .../api/facade/EmailNotificationFacade.java | 4 +- .../draftmessage/entity/DraftMessage.java | 14 +- .../api/service/MessageMapper.java | 10 +- .../api/service/TenantHeaderSupplier.java | 2 +- .../service/statistics/StatisticsService.java | 2 +- .../api/tenant/AccessTokenTenantResolver.java | 2 +- .../tenant/CustomHeaderTenantResolver.java | 2 +- ...tenancyWithSingleDomainTenantResolver.java | 2 +- .../api/tenant/SubdomainTenantResolver.java | 2 +- .../tenant/TechnicalUserTenantResolver.java | 2 +- .../api/tenant/TenantResolver.java | 2 +- .../api/tenant/TenantResolverService.java | 2 +- .../cob/messageservice/config/AppConfig.java | 2 + .../config/CacheManagerConfig.java | 7 - .../messageservice/config/SecurityConfig.java | 150 +++++----------- .../config/SpringFoxConfig.java | 113 ------------ .../config/security/AuthorisationService.java | 49 +++++ .../config/security/JwtAuthConverter.java | 60 +++++++ .../security/JwtAuthConverterProperties.java | 16 ++ .../filter/HttpTenantFilter.java | 8 +- .../filter/StatelessCsrfFilter.java | 12 +- .../RocketChatCredentialsHelperScheduler.java | 2 +- src/main/resources/application.properties | 8 +- .../MessageControllerAuthorizationTestIT.java | 2 +- .../controller/MessageControllerE2EIT.java | 31 ++-- .../controller/MessageControllerTestIT.java | 20 +-- .../EmailNotificationFacadeAsyncIT.java | 3 +- ...ailNotificationFacadeNoRequestScopeIT.java | 3 +- ...EmailNotificationFacadeRequestScopeIT.java | 3 +- .../facade/EmailNotificationFacadeTest.java | 3 +- .../api/service/EncryptionServiceTest.java | 4 +- .../LiveEventNotificationServiceTest.java | 6 - .../api/service/LogServiceTest.java | 170 ------------------ .../api/service/RocketChatServiceTest.java | 41 +++-- .../api/service/dto/MessageTest.java | 4 +- .../RocketChatCredentialsHelperTest.java | 32 ++-- .../api/service/helper/ServiceHelperTest.java | 8 +- .../statistics/StatisticsServiceTest.java | 2 - .../tenant/AccessTokenTenantResolverTest.java | 2 +- .../CustomHeaderTenantResolverTest.java | 2 +- .../tenant/SubdomainTenantResolverTest.java | 2 +- .../TechnicalUserTenantResolverTest.java | 2 +- .../api/tenant/TenantResolverServiceTest.java | 2 +- .../filter/HttpTenantFilterTest.java | 8 +- .../filter/StatelessCsrfFilterTest.java | 10 +- .../filter/SubdomainExtractorTest.java | 2 +- 58 files changed, 448 insertions(+), 677 deletions(-) delete mode 100644 src/main/java/de/caritas/cob/messageservice/api/controller/CustomSwaggerUIApiResourceController.java delete mode 100644 src/main/java/de/caritas/cob/messageservice/config/SpringFoxConfig.java create mode 100644 src/main/java/de/caritas/cob/messageservice/config/security/AuthorisationService.java create mode 100644 src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverter.java create mode 100644 src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverterProperties.java delete mode 100644 src/test/java/de/caritas/cob/messageservice/api/service/LogServiceTest.java diff --git a/.github/workflows/dockerImage.yml b/.github/workflows/dockerImage.yml index 93ed9a2..f69763f 100644 --- a/.github/workflows/dockerImage.yml +++ b/.github/workflows/dockerImage.yml @@ -27,7 +27,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/.github/workflows/dockerImageSkipTests.yml b/.github/workflows/dockerImageSkipTests.yml index e25c53d..a457bf8 100644 --- a/.github/workflows/dockerImageSkipTests.yml +++ b/.github/workflows/dockerImageSkipTests.yml @@ -27,7 +27,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/.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/api/messageservice.yaml b/api/messageservice.yaml index 6b79e37..8c53e22 100644 --- a/api/messageservice.yaml +++ b/api/messageservice.yaml @@ -720,10 +720,6 @@ components: - "REASSIGN_CONSULTANT_RESET_LAST_MESSAGE" AliasArgs: - oneOf: - - $ref: '#/components/schemas/ConsultantReassignment' - - ConsultantReassignment: type: object description: > toConsultantId, toConsultantName, toAskerName and fromConsultantName are required during diff --git a/pom.xml b/pom.xml index 372cb80..171cdca 100644 --- a/pom.xml +++ b/pom.xml @@ -16,23 +16,29 @@ org.springframework.boot spring-boot-starter-parent - 2.5.14 + 3.0.6 UTF-8 UTF-8 - 11 + 17 17.0.0 2.17.1 0.2.3 - 6.2.1 + 6.4.0 4.9.1 4.1.1 3.0.0 - 5.5.7 + 6.0.5 + 17 + 17 + 3.11 + 4.4 + 1.15 + 3.0.1 @@ -54,24 +60,36 @@ spring-boot-starter-amqp - org.hibernate.validator - hibernate-validator - 6.1.6.Final + 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.version} org.springframework.boot spring-boot-starter-cache - net.sf.ehcache - ehcache - ${ehcache.version} - - - com.fasterxml.jackson.core - jackson-databind - - + org.hibernate.validator + hibernate-validator + 8.0.0.Final + + + org.springframework.boot + spring-boot-starter-cache org.sonatype.plexus @@ -90,6 +108,11 @@ plexus-utils 3.3.0 + + org.apache.httpcomponents.client5 + httpclient5 + + org.springframework.boot @@ -109,10 +132,18 @@ ${jackson.databind.nullable.version} + - io.springfox - springfox-boot-starter - ${springfox-boot-starter.version} + io.swagger.core.v3 + swagger-annotations + 2.2.15 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.4.0 @@ -148,7 +179,7 @@ org.apache.commons commons-lang3 - 3.11 + ${commons-lang3.version} @@ -161,14 +192,14 @@ org.apache.commons commons-collections4 - 4.4 + ${commons-collections4.version} commons-codec commons-codec - 1.15 + ${commons-codec.version} @@ -222,16 +253,11 @@ test - powermock-module-junit4 - org.powermock - test - 2.0.2 - - - powermock-api-mockito2 - org.powermock + + com.c4-soft.springaddons + spring-security-oauth2-test-webmvc-addons + ${spring-security-oauth2-test-webmvc-addons.version} test - 2.0.2 org.jeasy @@ -263,6 +289,17 @@ 2.25.0 test + + net.sf.ehcache + ehcache + 2.10.9.2 + + + com.fasterxml.jackson.core + jackson-databind + + + @@ -301,7 +338,7 @@ org.openapitools openapi-generator-maven-plugin - 5.1.1 + ${openapi.generator.maven.version} @@ -311,8 +348,8 @@ true / - true custom + true ${project.basedir}/api/messageservice.yaml spring @@ -426,12 +463,22 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + --enable-preview + + org.apache.maven.plugins maven-surefire-plugin true + --enable-preview diff --git a/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java b/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java index d80a5a6..c89ff70 100644 --- a/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java +++ b/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java @@ -5,7 +5,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; diff --git a/src/main/java/de/caritas/cob/messageservice/Messenger.java b/src/main/java/de/caritas/cob/messageservice/Messenger.java index b38a0c8..db51609 100644 --- a/src/main/java/de/caritas/cob/messageservice/Messenger.java +++ b/src/main/java/de/caritas/cob/messageservice/Messenger.java @@ -110,7 +110,8 @@ private void notifyAndClearDraft(ChatMessage chatMessage) { } statisticsService.fireEvent(new CreateMessageStatisticsEvent(authenticatedUser.getUserId(), - resolveUserRole(authenticatedUser), chatMessage.getRcGroupId(), false, resolveAdviceseekerUserId(chatMessage), TenantContext.getCurrentTenant())); + resolveUserRole(authenticatedUser), chatMessage.getRcGroupId(), false, + resolveAdviceseekerUserId(chatMessage), TenantContext.getCurrentTenant())); } private String resolveAdviceseekerUserId(ChatMessage chatMessage) { @@ -172,8 +173,8 @@ private MessageResponseDTO postRocketChatGroupMessage(ChatMessage groupMessage) rocketChatService.markGroupAsReadForSystemUser(groupMessage.getRcGroupId()); return mapper.messageResponseOf(response); } catch (RocketChatSendMessageException - | RocketChatPostMarkGroupAsReadException - | CustomCryptoException ex) { + | RocketChatPostMarkGroupAsReadException + | CustomCryptoException ex) { throw new InternalServerErrorException(ex, LogService::logInternalServerError); } } @@ -280,15 +281,17 @@ public boolean patchEventMessage(String rcToken, String rcUserId, String message } /** - * Posts a message which contains an alias with the provided {@link MessageType} in - * the specified Rocket.Chat group. + * Posts a message which contains an alias with the provided {@link MessageType} in the specified + * Rocket.Chat group. * * @param rcGroupId Rocket.Chat group ID * @param messageType {@link MessageType} * @return {@link MessageResponseDTO} */ - public MessageResponseDTO postAliasMessage(String rcGroupId, MessageType messageType, String content) { - AliasMessageDTO aliasMessageDTO = new AliasMessageDTO().messageType(messageType).content(content); + public MessageResponseDTO postAliasMessage(String rcGroupId, MessageType messageType, + String content) { + AliasMessageDTO aliasMessageDTO = new AliasMessageDTO().messageType(messageType) + .content(content); var response = this.rocketChatService.postAliasOnlyMessageAsSystemUser(rcGroupId, aliasMessageDTO); diff --git a/src/main/java/de/caritas/cob/messageservice/api/ApiResponseEntityExceptionHandler.java b/src/main/java/de/caritas/cob/messageservice/api/ApiResponseEntityExceptionHandler.java index 2abfb39..6a910f2 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/ApiResponseEntityExceptionHandler.java +++ b/src/main/java/de/caritas/cob/messageservice/api/ApiResponseEntityExceptionHandler.java @@ -8,7 +8,7 @@ import de.caritas.cob.messageservice.api.exception.RocketChatBadRequestException; import de.caritas.cob.messageservice.api.service.LogService; import java.net.UnknownHostException; -import javax.validation.ConstraintViolationException; +import jakarta.validation.ConstraintViolationException; import lombok.NoArgsConstructor; import org.hibernate.service.spi.ServiceException; import org.springframework.core.Ordered; @@ -50,44 +50,6 @@ public ResponseEntity handleBadRequest( return handleExceptionInternal(null, null, new HttpHeaders(), HttpStatus.BAD_REQUEST, request); } - /** - * Incoming request body could not be deserialized. - * - * @param ex the exception to be handled - * @param headers http headers - * @param status http status - * @param request web request - */ - @Override - protected ResponseEntity handleHttpMessageNotReadable( - final HttpMessageNotReadableException ex, - final HttpHeaders headers, - final HttpStatus status, - final WebRequest request) { - LogService.logWarning(status, ex); - - return handleExceptionInternal(null, null, headers, status, request); - } - - /** - * @Valid on object fails validation. - * - * @param ex the exception to be handled - * @param headers http headers - * @param status http status - * @param request web request - */ - @Override - protected ResponseEntity handleMethodArgumentNotValid( - final MethodArgumentNotValidException ex, - final HttpHeaders headers, - final HttpStatus status, - final WebRequest request) { - LogService.logWarning(status, ex); - - return handleExceptionInternal(null, null, headers, status, request); - } - /** * 409 - Conflict. * @@ -111,7 +73,7 @@ protected ResponseEntity handleConflict( @ExceptionHandler({HttpClientErrorException.class}) protected ResponseEntity handleHttpClientException( final HttpClientErrorException ex, final WebRequest request) { - LogService.logWarning(ex.getStatusCode(), ex); + LogService.logWarning((HttpStatus) ex.getStatusCode(), ex); return handleExceptionInternal(null, null, new HttpHeaders(), ex.getStatusCode(), request); } diff --git a/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java b/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java index 07af332..63afafb 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java +++ b/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java @@ -21,14 +21,14 @@ @AllArgsConstructor public enum Authority { - ANONYMOUS(Role.ANONYMOUS, singletonList(ANONYMOUS_DEFAULT)), - USER(Role.USER, singletonList(USER_DEFAULT)), - CONSULTANT(Role.CONSULTANT, singletonList(CONSULTANT_DEFAULT)), - PEER_CONSULTANT(Role.PEER_CONSULTANT, singletonList(USE_FEEDBACK)), - TECHNICAL(Role.TECHNICAL, singletonList(TECHNICAL_DEFAULT)); + ANONYMOUS(Role.ANONYMOUS.getRoleName(), singletonList(ANONYMOUS_DEFAULT)), + USER(Role.USER.getRoleName(), singletonList(USER_DEFAULT)), + CONSULTANT(Role.CONSULTANT.getRoleName(), singletonList(CONSULTANT_DEFAULT)), + PEER_CONSULTANT(Role.PEER_CONSULTANT.getRoleName(), singletonList(USE_FEEDBACK)), + TECHNICAL(Role.TECHNICAL.getRoleName(), singletonList(TECHNICAL_DEFAULT)); - private final Role userRole; - private final List grantedAuthorities; + private final String roleName; + private final List authorities; /** * Get all authorities for a specific role. @@ -38,13 +38,20 @@ public enum Authority { */ public static List getAuthoritiesByUserRole(Role userRole) { Optional authorityByUserRole = Stream.of(values()) - .filter(authority -> authority.userRole.equals(userRole)) + .filter(authority -> authority.getRoleName().equals(userRole)) .findFirst(); - return authorityByUserRole.isPresent() ? authorityByUserRole.get().getGrantedAuthorities() + return authorityByUserRole.isPresent() ? authorityByUserRole.get().getAuthorities() : emptyList(); } + public static Authority fromRoleName(String roleName) { + return Stream.of(values()) + .filter(authority -> authority.roleName.equals(roleName)) + .findFirst() + .orElse(null); + } + public static class AuthorityValue { private AuthorityValue() { diff --git a/src/main/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapper.java b/src/main/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapper.java index e6df900..4c988db 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapper.java +++ b/src/main/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapper.java @@ -1,7 +1,7 @@ package de.caritas.cob.messageservice.api.authorization; import java.util.Collection; -import java.util.Optional; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.springframework.security.core.GrantedAuthority; @@ -26,12 +26,11 @@ public Collection mapAuthorities( return mapAuthorities(roleNames); } - private Set mapAuthorities(Set roleNames) { - return roleNames.parallelStream() - .map(Role::getRoleByName) - .filter(Optional::isPresent) - .map(Optional::get) - .map(Authority::getAuthoritiesByUserRole) + public Set mapAuthorities(Set roleNames) { + return roleNames.stream() + .map(Authority::fromRoleName) + .filter(Objects::nonNull) + .map(Authority::getAuthorities) .flatMap(Collection::parallelStream) .map(SimpleGrantedAuthority::new) .collect(Collectors.toSet()); diff --git a/src/main/java/de/caritas/cob/messageservice/api/controller/CustomSwaggerUIApiResourceController.java b/src/main/java/de/caritas/cob/messageservice/api/controller/CustomSwaggerUIApiResourceController.java deleted file mode 100644 index 3997b4a..0000000 --- a/src/main/java/de/caritas/cob/messageservice/api/controller/CustomSwaggerUIApiResourceController.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.caritas.cob.messageservice.api.controller; - -import org.springframework.beans.factory.annotation.Value; -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 CustomSwaggerUIApiResourceController extends ApiResourceController { - - public static final String SWAGGER_UI_BASE_URL = "/messages/docs"; - - public CustomSwaggerUIApiResourceController(SwaggerResourcesProvider swaggerResources) { - super(swaggerResources, SWAGGER_UI_BASE_URL); - } - -} diff --git a/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java b/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java index ffa06ba..826802d 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java +++ b/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java @@ -30,7 +30,7 @@ import io.swagger.annotations.Api; import java.time.Instant; import java.util.Optional; -import javax.validation.Valid; +import jakarta.validation.Valid; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -84,7 +84,7 @@ public ResponseEntity findMessages(String rcToken, String rcUs * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity updateKey(@Valid @RequestBody MasterKeyDTO masterKey) { + public ResponseEntity updateKey(@Valid MasterKeyDTO masterKey) { if (!encryptionService.getMasterKey().equals(masterKey.getMasterKey())) { encryptionService.updateMasterKey(masterKey.getMasterKey()); @@ -105,9 +105,9 @@ public ResponseEntity updateKey(@Valid @RequestBody MasterKeyDTO masterKey * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity createMessage(@RequestHeader String rcToken, - @RequestHeader String rcUserId, @RequestHeader String rcGroupId, - @Valid @RequestBody MessageDTO message) { + public ResponseEntity createMessage(String rcToken, + String rcUserId, String rcGroupId, + MessageDTO message) { var groupMessage = ChatMessage.builder() .rcToken(rcToken) @@ -133,9 +133,9 @@ public ResponseEntity createMessage(@RequestHeader String rc * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity forwardMessage(@RequestHeader String rcToken, - @RequestHeader String rcUserId, @RequestHeader String rcGroupId, - @Valid @RequestBody ForwardMessageDTO forwardMessageDTO) { + public ResponseEntity forwardMessage(String rcToken, + String rcUserId, String rcGroupId, + ForwardMessageDTO forwardMessageDTO) { Optional alias = JSONHelper.convertAliasMessageDTOToString( @@ -164,9 +164,9 @@ public ResponseEntity forwardMessage(@RequestHeader String r * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity createFeedbackMessage(@RequestHeader String rcToken, - @RequestHeader String rcUserId, @RequestHeader String rcFeedbackGroupId, - @Valid @RequestBody MessageDTO message) { + public ResponseEntity createFeedbackMessage(String rcToken, + String rcUserId, String rcFeedbackGroupId, + MessageDTO message) { var feedbackMessage = ChatMessage.builder() .rcToken(rcToken) @@ -189,8 +189,8 @@ public ResponseEntity createFeedbackMessage(@RequestHeader S * written in the alias object */ @Override - public ResponseEntity createVideoHintMessage(@RequestHeader String rcGroupId, - @Valid @RequestBody VideoCallMessageDTO videoCallMessageDTO) { + public ResponseEntity createVideoHintMessage(String rcGroupId, + VideoCallMessageDTO videoCallMessageDTO) { var response = this.messenger.createVideoHintMessage(rcGroupId, videoCallMessageDTO); @@ -206,8 +206,8 @@ public ResponseEntity createVideoHintMessage(@RequestHeader * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity saveDraftMessage(@RequestHeader String rcGroupId, - @Valid @RequestBody DraftMessageDTO message) { + public ResponseEntity saveDraftMessage(String rcGroupId, + DraftMessageDTO message) { SavedDraftType savedDraftType = this.draftMessageService.saveDraftMessage(message.getMessage(), rcGroupId, message.getT()); @@ -222,7 +222,7 @@ public ResponseEntity saveDraftMessage(@RequestHeader String rcGroupId, * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity findDraftMessage(@RequestHeader String rcGroupId) { + public ResponseEntity findDraftMessage(String rcGroupId) { Optional draftMessage = this.draftMessageService.findAndDecryptDraftMessage( rcGroupId); return draftMessage.map(ResponseEntity::ok) @@ -238,8 +238,8 @@ public ResponseEntity findDraftMessage(@RequestHeader String rc * @return {@link ResponseEntity} with the {@link HttpStatus} */ @Override - public ResponseEntity saveAliasOnlyMessage(@RequestHeader String rcGroupId, - @Valid AliasOnlyMessageDTO aliasOnlyMessageDTO) { + public ResponseEntity saveAliasOnlyMessage(String rcGroupId, + AliasOnlyMessageDTO aliasOnlyMessageDTO) { var type = aliasOnlyMessageDTO.getMessageType(); var aliasArgs = aliasOnlyMessageDTO.getArgs(); @@ -267,8 +267,10 @@ public ResponseEntity saveAliasOnlyMessage(@RequestHeader St private boolean hasMissingMandatoryAliasArgForReassignment(AliasArgs aliasArgs) { if (nonNull(aliasArgs)) { - return isNull(aliasArgs.getToConsultantId()) || isNull(aliasArgs.getFromConsultantName()) - || isNull(aliasArgs.getToConsultantName()) || isNull(aliasArgs.getToAskerName()); + return isNull(aliasArgs.getToConsultantId()) || isNull( + aliasArgs.getFromConsultantName()) + || isNull(aliasArgs.getToConsultantName()) || isNull( + aliasArgs.getToAskerName()); } return true; } @@ -332,8 +334,8 @@ public ResponseEntity deleteMessage(String rcToken, String rcUserId, Strin */ @Override public ResponseEntity saveAliasMessageWithContent( - @RequestHeader String rcGroupId, - @Valid AliasMessageDTO aliasOnlyMessageDTO) { + String rcGroupId, + AliasMessageDTO aliasOnlyMessageDTO) { var type = aliasOnlyMessageDTO.getMessageType(); var response = messenger .postAliasMessage(rcGroupId, type, aliasOnlyMessageDTO.getContent()); diff --git a/src/main/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacade.java b/src/main/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacade.java index 5b2edc3..af419f7 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacade.java +++ b/src/main/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacade.java @@ -1,7 +1,6 @@ package de.caritas.cob.messageservice.api.facade; import de.caritas.cob.messageservice.api.model.AliasArgs; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.api.model.ReassignStatus; import de.caritas.cob.messageservice.api.service.helper.ServiceHelper; import de.caritas.cob.messageservice.api.tenant.TenantContext; @@ -73,6 +72,7 @@ public void sendEmailAboutNewFeedbackMessage(String rcGroupId, Optional te @Async public void sendEmailAboutReassignRequest(String rcGroupId, AliasArgs aliasArgs, Optional tenantId, String accessToken) { + var reassignmentNotification = new ReassignmentNotificationDTO() .rcGroupId(rcGroupId) .toConsultantId(aliasArgs.getToConsultantId()) @@ -85,7 +85,7 @@ public void sendEmailAboutReassignRequest(String rcGroupId, AliasArgs aliasArgs, @Async public void sendEmailAboutReassignDecision(String roomId, - ConsultantReassignment consultantReassignment, Optional tenantId, String accessToken) { + AliasArgs consultantReassignment, Optional tenantId, String accessToken) { var reassignmentNotification = new ReassignmentNotificationDTO() .rcGroupId(roomId) .toConsultantId(consultantReassignment.getToConsultantId()) diff --git a/src/main/java/de/caritas/cob/messageservice/api/model/draftmessage/entity/DraftMessage.java b/src/main/java/de/caritas/cob/messageservice/api/model/draftmessage/entity/DraftMessage.java index 57329e3..a40edfa 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/model/draftmessage/entity/DraftMessage.java +++ b/src/main/java/de/caritas/cob/messageservice/api/model/draftmessage/entity/DraftMessage.java @@ -1,13 +1,13 @@ package de.caritas.cob.messageservice.api.model.draftmessage.entity; 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 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 lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/de/caritas/cob/messageservice/api/service/MessageMapper.java b/src/main/java/de/caritas/cob/messageservice/api/service/MessageMapper.java index 9af945e..ad2536f 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/service/MessageMapper.java +++ b/src/main/java/de/caritas/cob/messageservice/api/service/MessageMapper.java @@ -11,7 +11,6 @@ import de.caritas.cob.messageservice.api.helper.UserHelper; import de.caritas.cob.messageservice.api.model.AliasArgs; import de.caritas.cob.messageservice.api.model.AliasMessageDTO; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.api.model.MessageResponseDTO; import de.caritas.cob.messageservice.api.model.MessageType; import de.caritas.cob.messageservice.api.model.jsondeserializer.AliasJsonDeserializer; @@ -29,6 +28,7 @@ import java.util.Random; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hibernate.sql.Alias; import org.springframework.stereotype.Service; @Service @@ -145,19 +145,19 @@ public String messageStringOf(AliasArgs aliasArgs) { } } - public ConsultantReassignment consultantReassignmentOf(Message message) { + public AliasArgs consultantReassignmentOf(Message message) { try { var foundMsgString = encryptionService.decrypt(message.getMsg(), message.getRid()); foundMsgString = foundMsgString.replace(""", "\""); - return objectMapper.readValue(foundMsgString, ConsultantReassignment.class); + return objectMapper.readValue(foundMsgString, AliasArgs.class); } catch (JsonProcessingException | CustomCryptoException e) { throw new RuntimeException(e); } } - public UpdateMessage updateMessageOf(Message message, ConsultantReassignment reassignment) { + public UpdateMessage updateMessageOf(Message message, AliasArgs aliasArgs) { try { - var text = objectMapper.writeValueAsString(reassignment); + var text = objectMapper.writeValueAsString(aliasArgs); var encryptedText = encryptionService.encrypt(text, message.getRid()); var updatedMessage = new UpdateMessage(); diff --git a/src/main/java/de/caritas/cob/messageservice/api/service/TenantHeaderSupplier.java b/src/main/java/de/caritas/cob/messageservice/api/service/TenantHeaderSupplier.java index c41da15..1e04e19 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/service/TenantHeaderSupplier.java +++ b/src/main/java/de/caritas/cob/messageservice/api/service/TenantHeaderSupplier.java @@ -2,7 +2,7 @@ import de.caritas.cob.messageservice.api.tenant.TenantContext; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsService.java b/src/main/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsService.java index e3d7d45..5957aa2 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsService.java +++ b/src/main/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsService.java @@ -3,7 +3,7 @@ import de.caritas.cob.messageservice.api.service.LogService; import de.caritas.cob.messageservice.api.service.statistics.event.StatisticsEvent; import java.nio.charset.StandardCharsets; -import javax.validation.constraints.NotNull; +import jakarta.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/messageservice/api/tenant/AccessTokenTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java index d07b66c..8b7bd91 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java @@ -2,7 +2,7 @@ import java.util.Map; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.keycloak.KeycloakSecurityContext; diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolver.java index ee7e0c4..db2571e 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolver.java @@ -3,7 +3,7 @@ import de.caritas.cob.messageservice.api.service.TenantHeaderSupplier; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.NonNull; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/MultitenancyWithSingleDomainTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/MultitenancyWithSingleDomainTenantResolver.java index 765e804..b74349c 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/MultitenancyWithSingleDomainTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/MultitenancyWithSingleDomainTenantResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.messageservice.api.tenant; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolver.java index d312ce9..eba9fe7 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolver.java @@ -6,7 +6,7 @@ import de.caritas.cob.messageservice.api.service.TenantService; import de.caritas.cob.messageservice.filter.SubdomainExtractor; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.NonNull; import org.springframework.stereotype.Component; diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java index fecaa0d..b970765 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.messageservice.api.tenant; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/api/tenant/TenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolver.java index ea8ba3f..b6461f2 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolver.java @@ -1,7 +1,7 @@ package de.caritas.cob.messageservice.api.tenant; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; public interface TenantResolver { diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolverService.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolverService.java index b6c8b1a..51cba30 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolverService.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/TenantResolverService.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/de/caritas/cob/messageservice/config/AppConfig.java b/src/main/java/de/caritas/cob/messageservice/config/AppConfig.java index 365463a..2bb5a1a 100644 --- a/src/main/java/de/caritas/cob/messageservice/config/AppConfig.java +++ b/src/main/java/de/caritas/cob/messageservice/config/AppConfig.java @@ -1,5 +1,7 @@ package de.caritas.cob.messageservice.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import de.caritas.cob.messageservice.api.model.AliasArgs; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/de/caritas/cob/messageservice/config/CacheManagerConfig.java b/src/main/java/de/caritas/cob/messageservice/config/CacheManagerConfig.java index 5144a26..527b8f5 100644 --- a/src/main/java/de/caritas/cob/messageservice/config/CacheManagerConfig.java +++ b/src/main/java/de/caritas/cob/messageservice/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,11 +24,6 @@ public class CacheManagerConfig { @Value("${cache.tenant.configuration.timeToLiveSeconds}") private long tenantTimeToLiveSeconds; - @Bean - public CacheManager cacheManager() { - return new EhCacheCacheManager(ehCacheManager()); - } - @Bean(destroyMethod = "shutdown") public net.sf.ehcache.CacheManager ehCacheManager() { var config = new net.sf.ehcache.config.Configuration(); diff --git a/src/main/java/de/caritas/cob/messageservice/config/SecurityConfig.java b/src/main/java/de/caritas/cob/messageservice/config/SecurityConfig.java index 564c5d5..337cedb 100644 --- a/src/main/java/de/caritas/cob/messageservice/config/SecurityConfig.java +++ b/src/main/java/de/caritas/cob/messageservice/config/SecurityConfig.java @@ -7,6 +7,9 @@ import static de.caritas.cob.messageservice.api.authorization.Authority.AuthorityValue.USE_FEEDBACK; import de.caritas.cob.messageservice.api.authorization.RoleAuthorizationAuthorityMapper; +import de.caritas.cob.messageservice.config.security.AuthorisationService; +import de.caritas.cob.messageservice.config.security.JwtAuthConverter; +import de.caritas.cob.messageservice.config.security.JwtAuthConverterProperties; import de.caritas.cob.messageservice.filter.StatelessCsrfFilter; import org.keycloak.adapters.KeycloakConfigResolver; import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; @@ -25,18 +28,29 @@ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; 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; /** * Provides the Keycloak/Spring Security configuration. */ @KeycloakConfiguration -public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { +public class SecurityConfig implements WebMvcConfigurer { + + public static final String[] WHITE_LIST = + new String[]{"/agencies/docs", "/agencies/docs/**", "/v2/api-docs", "/configuration/ui", + "/swagger-resources/**", "/configuration/security", "/swagger-ui.html", "/swagger-ui/**", "/webjars/**", "/actuator/health", "/actuator/health/**"}; + + + @Autowired + AuthorisationService authorisationService; + @Autowired + JwtAuthConverterProperties jwtAuthConverterProperties; - @SuppressWarnings("unused") - private final KeycloakClientRequestFactory keycloakClientRequestFactory; @Value("${csrf.cookie.property}") private String csrfCookieProperty; @@ -47,136 +61,66 @@ public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Value("${csrf.whitelist.header.property}") private String csrfWhitelistHeaderProperty; - /** - * Processes HTTP requests and checks for a valid spring security authentication for the - * (Keycloak) principal (authorization header). - */ - public SecurityConfig(KeycloakClientRequestFactory keycloakClientRequestFactory) { - this.keycloakClientRequestFactory = keycloakClientRequestFactory; - } /** * 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); + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + @SuppressWarnings("java:S1075") // URIs should not be hardcoded final var SINGLE_MESSAGE_PATH = "/messages/{messageId:[0-9A-Za-z]{17}}"; - http.csrf().disable() - .addFilterBefore(new StatelessCsrfFilter(csrfCookieProperty, csrfHeaderProperty, - csrfWhitelistHeaderProperty), CsrfFilter.class) - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and().authorizeRequests() - .antMatchers(SpringFoxConfig.WHITE_LIST).permitAll() - .antMatchers("/messages/key") + + var httpSecurity = http.csrf().disable() + .addFilterBefore(new StatelessCsrfFilter(csrfCookieProperty, csrfHeaderProperty, csrfWhitelistHeaderProperty), + CsrfFilter.class); + + + httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and().authorizeRequests() + .requestMatchers(SecurityConfig.WHITE_LIST).permitAll() + .requestMatchers("/messages/key") .hasAuthority(TECHNICAL_DEFAULT) - .antMatchers("/messages", "/messages/draft", "/messages/videohint/new") + .requestMatchers("/messages", "/messages/draft", "/messages/videohint/new") .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, ANONYMOUS_DEFAULT) - .antMatchers(HttpMethod.PATCH, SINGLE_MESSAGE_PATH) + .requestMatchers(HttpMethod.PATCH, SINGLE_MESSAGE_PATH) .hasAnyAuthority(USER_DEFAULT) - .antMatchers(HttpMethod.GET, SINGLE_MESSAGE_PATH) + .requestMatchers(HttpMethod.GET, SINGLE_MESSAGE_PATH) .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, ANONYMOUS_DEFAULT) - .antMatchers(HttpMethod.DELETE, SINGLE_MESSAGE_PATH) + .requestMatchers(HttpMethod.DELETE, SINGLE_MESSAGE_PATH) .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, ANONYMOUS_DEFAULT) - .antMatchers("/messages/new") + .requestMatchers("/messages/new") .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, TECHNICAL_DEFAULT, ANONYMOUS_DEFAULT) - .antMatchers("/messages/forward", "/messages/feedback/new") + .requestMatchers("/messages/forward", "/messages/feedback/new") .hasAuthority(USE_FEEDBACK) - .antMatchers("/messages/aliasonly/new") + .requestMatchers("/messages/aliasonly/new") .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, TECHNICAL_DEFAULT) - .antMatchers("/messages/aliasWithContent/new") + .requestMatchers("/messages/aliasWithContent/new") .hasAnyAuthority(USER_DEFAULT, CONSULTANT_DEFAULT, TECHNICAL_DEFAULT) .anyRequest() .denyAll(); - } - - /** - * Use the KeycloakSpringBootConfigResolver to be able to save the Keycloak settings in the spring - * application properties. - */ - @Bean - public KeycloakConfigResolver keyCloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } - /** - * Change springs authentication strategy to be stateless (no session is being created). - */ - @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new NullAuthenticatedSessionStrategy(); + httpSecurity.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthConverter()); + return httpSecurity.build(); } - /** - * Change the default AuthenticationProvider to KeycloakAuthenticationProvider and register it in - * the spring security context. Set the GrantedAuthoritiesMapper to map the Keycloak roles to the - * granted authorities. - */ - @Autowired - public void configureGlobal(final 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." - * - * https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/java/spring-security-adapter.adoc - * - * {@link package.class#member label} + * 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) */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean( - KeycloakAuthenticationProcessingFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setUseTrailingSlashMatch(true); } - /** - * see above: {@link SecurityConfig#keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter). - */ - @SuppressWarnings({"rawtypes", "unchecked"}) @Bean - public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean( - KeycloakPreAuthActionsFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; + public JwtAuthConverter jwtAuthConverter() { + return new JwtAuthConverter(jwtAuthConverterProperties, authorisationService); } - /** - * see above: {@link SecurityConfig#keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter). - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean( - KeycloakAuthenticatedActionsFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } - /** - * see above: {@link SecurityConfig#keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter). - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Bean - public FilterRegistrationBean keycloakSecurityContextRequestFilterBean( - KeycloakSecurityContextRequestFilter filter) { - var registrationBean = new FilterRegistrationBean(filter); - registrationBean.setEnabled(false); - return registrationBean; - } } diff --git a/src/main/java/de/caritas/cob/messageservice/config/SpringFoxConfig.java b/src/main/java/de/caritas/cob/messageservice/config/SpringFoxConfig.java deleted file mode 100644 index 1b0b089..0000000 --- a/src/main/java/de/caritas/cob/messageservice/config/SpringFoxConfig.java +++ /dev/null @@ -1,113 +0,0 @@ -package de.caritas.cob.messageservice.config; - -import static java.util.Collections.singletonList; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -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.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; -import springfox.documentation.service.AuthorizationScope; -import springfox.documentation.service.Contact; -import springfox.documentation.service.SecurityReference; -import springfox.documentation.service.SecurityScheme; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -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[] {"/messages/docs", "/messages/docs/**", "/v2/api-docs", "/configuration/ui", - "/swagger-resources/**", "/configuration/security", "/swagger-ui", "/swagger-ui/**", "/webjars/**", "/actuator/health", "/actuator/health/**"}; - - @Bean - public Docket apiDocket() { - return new Docket(DocumentationType.SWAGGER_2).select() - .apis(RequestHandlerSelectors.basePackage("de.caritas.cob.messageservice.api")).build() - .consumes(getContentTypes()).produces(getContentTypes()).apiInfo(getApiInfo()) - .useDefaultResponseMessages(false).protocols(protocols()).securitySchemes(securitySchemes()) - .securityContexts(securityContexts()); - } - - private List securityContexts() { - return singletonList(SecurityContext.builder() - .forPaths(PathSelectors.any()).securityReferences(securityReferences()).build()); - } - - private List securityReferences() { - return singletonList(SecurityReference.builder() - .reference("token").scopes(new AuthorizationScope[0]).build()); - } - - private List securitySchemes() { - return singletonList(new ApiKey("Bearer", "Authorization", "header")); - } - - /** - * Returns the API protocols (for documentation) - * - * @return - */ - private Set protocols() { - Set protocols = new HashSet<>(); - protocols.add("http"); // TODO remove for production mode - protocols.add("https"); - return protocols; - } - - /** - * Returns all content types which should be consumed/produced - */ - private Set getContentTypes() { - Set contentTypes = new HashSet<>(); - contentTypes.add("application/json"); - return contentTypes; - } - - /** - * Returns the API information (defined in application.properties) - * - * @return - */ - 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/messageservice/config/security/AuthorisationService.java b/src/main/java/de/caritas/cob/messageservice/config/security/AuthorisationService.java new file mode 100644 index 0000000..6d8ae96 --- /dev/null +++ b/src/main/java/de/caritas/cob/messageservice/config/security/AuthorisationService.java @@ -0,0 +1,49 @@ +package de.caritas.cob.messageservice.config.security; + +import com.google.common.collect.Lists; +import de.caritas.cob.messageservice.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/messageservice/config/security/JwtAuthConverter.java b/src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverter.java new file mode 100644 index 0000000..40097fa --- /dev/null +++ b/src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverter.java @@ -0,0 +1,60 @@ +package de.caritas.cob.messageservice.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/messageservice/config/security/JwtAuthConverterProperties.java b/src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverterProperties.java new file mode 100644 index 0000000..60800e1 --- /dev/null +++ b/src/main/java/de/caritas/cob/messageservice/config/security/JwtAuthConverterProperties.java @@ -0,0 +1,16 @@ +package de.caritas.cob.messageservice.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/messageservice/filter/HttpTenantFilter.java b/src/main/java/de/caritas/cob/messageservice/filter/HttpTenantFilter.java index b9d394c..45b9c79 100644 --- a/src/main/java/de/caritas/cob/messageservice/filter/HttpTenantFilter.java +++ b/src/main/java/de/caritas/cob/messageservice/filter/HttpTenantFilter.java @@ -7,10 +7,10 @@ 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 jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/filter/StatelessCsrfFilter.java b/src/main/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilter.java index 37658fb..418f1dc 100644 --- a/src/main/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilter.java +++ b/src/main/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilter.java @@ -1,6 +1,6 @@ package de.caritas.cob.messageservice.filter; -import static de.caritas.cob.messageservice.config.SpringFoxConfig.WHITE_LIST; +import static de.caritas.cob.messageservice.config.SecurityConfig.WHITE_LIST; import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -8,11 +8,11 @@ import java.util.Arrays; import java.util.regex.Pattern; import java.util.stream.Stream; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.security.access.AccessDeniedException; diff --git a/src/main/java/de/caritas/cob/messageservice/scheduler/RocketChatCredentialsHelperScheduler.java b/src/main/java/de/caritas/cob/messageservice/scheduler/RocketChatCredentialsHelperScheduler.java index 89aa26a..bce2f05 100644 --- a/src/main/java/de/caritas/cob/messageservice/scheduler/RocketChatCredentialsHelperScheduler.java +++ b/src/main/java/de/caritas/cob/messageservice/scheduler/RocketChatCredentialsHelperScheduler.java @@ -2,7 +2,7 @@ import de.caritas.cob.messageservice.api.service.LogService; import de.caritas.cob.messageservice.api.service.helper.RocketChatCredentialsHelper; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Profile; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7d28b66..059dae3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -100,4 +100,10 @@ feature.multitenancy.with.single.domain.enabled=false management.endpoint.health.enabled=true management.endpoint.health.show-details=never management.endpoints.web.exposure.include=health -management.health.probes.enabled=true \ No newline at end of file +management.health.probes.enabled=true + +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 \ No newline at end of file diff --git a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerAuthorizationTestIT.java b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerAuthorizationTestIT.java index 17c8233..88774f4 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerAuthorizationTestIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerAuthorizationTestIT.java @@ -24,7 +24,7 @@ import de.caritas.cob.messageservice.api.model.VideoCallMessageDTO; import de.caritas.cob.messageservice.api.service.EncryptionService; import de.caritas.cob.messageservice.api.service.RocketChatService; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; import org.apache.commons.lang3.RandomStringUtils; import org.jeasy.random.EasyRandom; import org.junit.Before; diff --git a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerE2EIT.java b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerE2EIT.java index f7acbe8..bf20aed 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerE2EIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerE2EIT.java @@ -38,7 +38,6 @@ import de.caritas.cob.messageservice.api.model.AliasArgs; import de.caritas.cob.messageservice.api.model.AliasMessageDTO; import de.caritas.cob.messageservice.api.model.AliasOnlyMessageDTO; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.api.model.ForwardMessageDTO; import de.caritas.cob.messageservice.api.model.MessageDTO; import de.caritas.cob.messageservice.api.model.MessageStreamDTO; @@ -73,7 +72,7 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; import org.apache.commons.lang3.RandomStringUtils; import org.jeasy.random.EasyRandom; import org.junit.jupiter.api.AfterEach; @@ -155,7 +154,7 @@ class MessageControllerE2EIT { private AliasOnlyMessageDTO aliasOnlyMessage; private List messages; - private ConsultantReassignment consultantReassignment; + private AliasArgs consultantReassignment; private String messageId; private AliasArgs aliasArgs; private Message message; @@ -231,7 +230,7 @@ void findMessagesShouldRespondWithAliasArgsConsultantReassign() throws Exception objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); var messagesResponse = objectMapper.readValue(response, MessageStreamDTO.class); var message = messagesResponse.getMessages().get(1).getMsg(); // 1 due to split before - var consultantReassignment = objectMapper.readValue(message, ConsultantReassignment.class); + var consultantReassignment = objectMapper.readValue(message, AliasArgs.class); assertEquals(this.consultantReassignment, consultantReassignment); assertGroupCall(); @@ -1116,9 +1115,10 @@ void saveAliasOnlyMessageShouldReturnSendMessageResultWhenWithMessage() throws E var decryptedMsg = encryptionService.decrypt(sendMessageRequest.getMsg(), RC_GROUP_ID); var decryptedConsultantReassignment = - objectMapper.readValue(decryptedMsg, ConsultantReassignment.class); + objectMapper.readValue(decryptedMsg, AliasArgs.class); + AliasArgs args = aliasOnlyMessage.getArgs(); assertEquals( - aliasOnlyMessage.getArgs().getFromConsultantId(), + args.getFromConsultantId(), decryptedConsultantReassignment.getFromConsultantId() ); } @@ -1213,7 +1213,7 @@ private void givenMessagesWithoutClearAlias() { } private void givenAMessageWithAnEncryptedConsultantReassignment(String groupId) { - consultantReassignment = new ConsultantReassignment(); + consultantReassignment = new AliasArgs(); consultantReassignment.setToConsultantId(UUID.randomUUID()); consultantReassignment.setStatus(ReassignStatus.REQUESTED); @@ -1395,7 +1395,7 @@ private void givenASuccessfulGetChatMessageReassignmentResponse(String messageId var encodedAlias = URLEncoder.encode(aliasString, StandardCharsets.UTF_8); message.setAlias(encodedAlias); - var consultantReassignment = new ConsultantReassignment(); + var consultantReassignment = new AliasArgs(); consultantReassignment.setStatus(ReassignStatus.REQUESTED); consultantReassignment.setToConsultantId(UUID.randomUUID()); var msg = objectMapper.writeValueAsString(consultantReassignment); @@ -1462,7 +1462,7 @@ private void givenAGetChatMessageSevereErrorResponse(String messageId) { } private void givenAnAliasOnlyMessageWithUnsupportedMessage() { - aliasOnlyMessage = easyRandom.nextObject(AliasOnlyMessageDTO.class); + aliasOnlyMessage = givenNewAliasOnlyMessage(); var messageType = easyRandom.nextBoolean() ? MessageType.FURTHER_STEPS : MessageType.E2EE_ACTIVATED; @@ -1472,25 +1472,30 @@ private void givenAnAliasOnlyMessageWithUnsupportedMessage() { private void givenAnAliasOnlyMessageWithSupportedMessage() { aliasOnlyMessage = easyRandom.nextObject(AliasOnlyMessageDTO.class); aliasOnlyMessage.setMessageType(MessageType.REASSIGN_CONSULTANT); - aliasOnlyMessage.getArgs().setStatus(ReassignStatus.REQUESTED); + AliasArgs args = aliasOnlyMessage.getArgs(); + args.setStatus(ReassignStatus.REQUESTED); } private void givenAnAliasOnlyMessageWithSupportedMessageAndEmptyArgs() { - aliasOnlyMessage = easyRandom.nextObject(AliasOnlyMessageDTO.class); + aliasOnlyMessage = givenNewAliasOnlyMessage(); aliasOnlyMessage.setMessageType(MessageType.REASSIGN_CONSULTANT); aliasOnlyMessage.setArgs(null); } private void givenAReassignmentEventWithNoConsultantId() { - aliasOnlyMessage = easyRandom.nextObject(AliasOnlyMessageDTO.class); + aliasOnlyMessage = givenNewAliasOnlyMessage(); var args = new AliasArgs(); args.setStatus(ReassignStatus.REQUESTED); aliasOnlyMessage.setArgs(args); aliasOnlyMessage.setMessageType(MessageType.REASSIGN_CONSULTANT); } + private AliasOnlyMessageDTO givenNewAliasOnlyMessage() { + return new AliasOnlyMessageDTO().args(new AliasArgs()); + } + private void givenAnAliasOnlyMessage(boolean muteUnmute) { - aliasOnlyMessage = easyRandom.nextObject(AliasOnlyMessageDTO.class); + aliasOnlyMessage = new AliasOnlyMessageDTO().messageType(MessageType.USER_MUTED).args(new AliasArgs()); aliasOnlyMessage.setArgs(null); MessageType messageType; diff --git a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerTestIT.java b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerTestIT.java index 0fa7541..866880f 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerTestIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/controller/MessageControllerTestIT.java @@ -42,7 +42,6 @@ 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.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -65,9 +64,10 @@ import de.caritas.cob.messageservice.api.model.rocket.chat.message.UserDTO; import de.caritas.cob.messageservice.api.service.DraftMessageService; import de.caritas.cob.messageservice.api.service.EncryptionService; -import de.caritas.cob.messageservice.api.service.LogService; import de.caritas.cob.messageservice.api.service.MessageMapper; import de.caritas.cob.messageservice.api.service.RocketChatService; +import de.caritas.cob.messageservice.config.security.AuthorisationService; +import de.caritas.cob.messageservice.config.security.JwtAuthConverterProperties; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -144,13 +144,13 @@ RC_TIMESTAMP, new UserDTO(RC_USER_ID, "test", "name"), false, new String[0], new @SuppressWarnings("unused") private MessageMapper messageMapper; - @Mock - private Logger logger; + @MockBean + private AuthorisationService authorisationService; + + @MockBean + private JwtAuthConverterProperties jwtAuthConverterProperties; + - @Before - public void setup() { - setInternalState(LogService.class, "LOGGER", logger); - } /** * 400 - Bad Request tests @@ -404,7 +404,7 @@ private String convertObjectToJson(Object object) throws JsonProcessingException } @Test - public void createMessage_Should_LogInternalServerError_When_InternalServerErrorIsThrown() + public void createMessage_Should_ReturnInternalServerError_When_InternalServerErrorIsThrown() throws Exception { doThrow(new InternalServerErrorException()).when(messenger) @@ -415,8 +415,6 @@ public void createMessage_Should_LogInternalServerError_When_InternalServerError .content(VALID_MESSAGE_REQUEST_BODY_WITHOUT_NOTIFICATION) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isInternalServerError()); - - verify(logger, atLeastOnce()).error(eq("{}{}"), eq("Internal Server Error: "), anyString()); } @Test diff --git a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeAsyncIT.java b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeAsyncIT.java index f589036..c9239a2 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeAsyncIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeAsyncIT.java @@ -4,7 +4,6 @@ import static org.mockito.Mockito.when; import de.caritas.cob.messageservice.api.model.AliasArgs; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.userservice.generated.ApiClient; import de.caritas.cob.messageservice.userservice.generated.web.UserControllerApi; import java.lang.management.ManagementFactory; @@ -87,7 +86,7 @@ void sendEmailAboutReassignDecisionShouldRunInAnotherThread() { underTest.sendEmailAboutReassignDecision( RandomStringUtils.randomAlphanumeric(16), - easyRandom.nextObject(ConsultantReassignment.class), + easyRandom.nextObject(AliasArgs.class), Optional.of(easyRandom.nextLong()), null ); diff --git a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeNoRequestScopeIT.java b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeNoRequestScopeIT.java index 6aed39b..c71157f 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeNoRequestScopeIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeNoRequestScopeIT.java @@ -6,7 +6,6 @@ import de.caritas.cob.messageservice.api.helper.AuthenticatedUser; import de.caritas.cob.messageservice.api.model.AliasArgs; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.userservice.generated.ApiClient; import de.caritas.cob.messageservice.userservice.generated.web.UserControllerApi; import java.util.Optional; @@ -91,7 +90,7 @@ void sendEmailAboutReassignDecisionShouldNeverCallAuthenticatedUserMethodsWhenAc underTest.sendEmailAboutReassignDecision( RandomStringUtils.randomAlphanumeric(16), - easyRandom.nextObject(ConsultantReassignment.class), + easyRandom.nextObject(AliasArgs.class), Optional.of(easyRandom.nextLong()), RandomStringUtils.randomAlphanumeric(16) ); diff --git a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeRequestScopeIT.java b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeRequestScopeIT.java index a364370..b1c4727 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeRequestScopeIT.java +++ b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeRequestScopeIT.java @@ -6,7 +6,6 @@ import de.caritas.cob.messageservice.api.helper.AuthenticatedUser; import de.caritas.cob.messageservice.api.model.AliasArgs; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.userservice.generated.ApiClient; import de.caritas.cob.messageservice.userservice.generated.web.UserControllerApi; import java.util.Optional; @@ -87,7 +86,7 @@ void sendEmailAboutReassignDecisionShouldCallAuthenticatedUserMethodsWhenAccessT underTest.sendEmailAboutReassignDecision( RandomStringUtils.randomAlphanumeric(16), - easyRandom.nextObject(ConsultantReassignment.class), + easyRandom.nextObject(AliasArgs.class), Optional.of(easyRandom.nextLong()), null ); diff --git a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeTest.java b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeTest.java index 92bb6b2..fa7c3b1 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/facade/EmailNotificationFacadeTest.java @@ -8,7 +8,6 @@ import static org.mockito.Mockito.when; import de.caritas.cob.messageservice.api.model.AliasArgs; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; import de.caritas.cob.messageservice.api.model.ReassignStatus; import de.caritas.cob.messageservice.api.service.helper.ServiceHelper; import de.caritas.cob.messageservice.api.tenant.TenantContext; @@ -144,7 +143,7 @@ void sendEmailAboutReassignDecision_Should_sendExpectedReassignNotificationMailV // given when(clientFactory.userControllerApi()).thenReturn(userControllerApi); givenApiClientAndHeadersAreConfigured(); - var consultantReassignment = new EasyRandom().nextObject(ConsultantReassignment.class); + var consultantReassignment = new EasyRandom().nextObject(AliasArgs.class); // when emailNotificationFacade.sendEmailAboutReassignDecision(RC_GROUP_ID, consultantReassignment, diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/EncryptionServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/EncryptionServiceTest.java index 9df5b37..ba0e742 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/EncryptionServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/EncryptionServiceTest.java @@ -12,7 +12,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import de.caritas.cob.messageservice.api.exception.CustomCryptoException; -import org.powermock.reflect.Whitebox; +import org.springframework.test.util.ReflectionTestUtils; @RunWith(MockitoJUnitRunner.class) public class EncryptionServiceTest { @@ -34,7 +34,7 @@ public class EncryptionServiceTest { @Before public void setup() throws NoSuchFieldException { - Whitebox.setInternalState(encryptionService, "fragment_applicationKey", KEY_APPLICATION); + ReflectionTestUtils.setField(encryptionService, "fragment_applicationKey", KEY_APPLICATION); encryptionService.updateMasterKey(KEY_MASTER); diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/LiveEventNotificationServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/LiveEventNotificationServiceTest.java index 728c1bc..2cafc50 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/LiveEventNotificationServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/LiveEventNotificationServiceTest.java @@ -8,7 +8,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static org.powermock.reflect.Whitebox.setInternalState; import de.caritas.cob.messageservice.api.service.helper.ServiceHelper; import de.caritas.cob.messageservice.config.apiclient.ApiControllerFactory; @@ -21,7 +20,6 @@ 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.client.RestClientException; @@ -33,11 +31,9 @@ public class LiveEventNotificationServiceTest { @Mock private LiveproxyControllerApi liveproxyControllerApi; @Mock private ServiceHelper serviceHelper; @Mock private ApiControllerFactory clientFactory; - @Mock private Logger logger; @Before public void setup() { - setInternalState(LogService.class, "LOGGER", logger); when(clientFactory.liveproxyControllerApi()).thenReturn(liveproxyControllerApi); } @@ -84,7 +80,5 @@ public void sendLiveEvent_Should_logError_When_apiClientThrowsRestClientExceptio .thenReturn(new HttpHeaders()); this.liveEventNotificationService.sendLiveEvent("valid", "", Optional.empty()); - - verify(this.logger, times(1)).error(anyString(), anyString(), anyString()); } } diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/LogServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/LogServiceTest.java deleted file mode 100644 index 402f668..0000000 --- a/src/test/java/de/caritas/cob/messageservice/api/service/LogServiceTest.java +++ /dev/null @@ -1,170 +0,0 @@ -package de.caritas.cob.messageservice.api.service; - -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 { - - private static final String ERROR_MESSAGE = "error"; - private static final String RC_SERVICE_ERROR_TEXT = "Rocket.Chat service error: {}"; - private static final String INTERNAL_SERVER_ERROR_TEXT = "Internal Server Error: "; - private static final String BAD_REQUEST_TEXT = "Bad Request: {}"; - private static final String MESSAGE_API_LOG_TEXT = "MessageService API: {}"; - public static final String STATISTICS_EVENT_PROCESSING_ERROR = "StatisticsEventProcessing error: "; - public static final String STATISTICS_EVENT_PROCESSING_WARNING = "StatisticsEventProcessing warning: "; - - @Mock Exception exception; - - @Mock private Logger logger; - - @Before - public void setup() { - setInternalState(LogService.class, "LOGGER", logger); - } - - @Test - public void logRocketChatServiceError_Should_LogExceptionStackTrace() { - - LogService.logRocketChatServiceError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logRocketChatServiceError_Should_LogErrorMessage() { - - LogService.logRocketChatServiceError(ERROR_MESSAGE); - verify(logger, times(1)).error(RC_SERVICE_ERROR_TEXT, ERROR_MESSAGE); - } - - @Test - public void logRocketChatServiceError_Should_LogErrorMessageAndExceptionStackTrace() { - - LogService.logRocketChatServiceError(ERROR_MESSAGE, exception); - verify(logger, times(1)).error(RC_SERVICE_ERROR_TEXT, ERROR_MESSAGE); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logUserServiceHelperError_Should_LogExceptionStackTrace() { - - LogService.logUserServiceHelperError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logInfo_Should_LogMessage() { - - LogService.logInfo(ERROR_MESSAGE); - verify(logger, times(1)).info(ERROR_MESSAGE); - } - - @Test - public void logEncryptionServiceError_Should_LogExceptionStackTrace() { - - LogService.logEncryptionServiceError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logEncryptionPossibleBadKeyError_Should_LogExceptionStackTrace() { - - LogService.logEncryptionPossibleBadKeyError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logRocketChatBadRequestError_Should_LogErrorMessage() { - - LogService.logRocketChatBadRequestError(ERROR_MESSAGE); - verify(logger, times(1)) - .error("Rocket.Chat Bad Request service error: {}", ERROR_MESSAGE); - } - - @Test - public void logInternalServerError_Should_LogErrorMessageAndExceptionStackTrace() { - - LogService.logInternalServerError(ERROR_MESSAGE, exception); - verify(logger, times(1)).error("{}{}", INTERNAL_SERVER_ERROR_TEXT, ERROR_MESSAGE); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logBadRequest_Should_LogMessage() { - - LogService.logBadRequest(ERROR_MESSAGE); - verify(logger, times(1)).warn(BAD_REQUEST_TEXT, ERROR_MESSAGE); - } - - @Test - public void logInternalServerError_Should_LogExceptionStackTrace() { - - LogService.logInternalServerError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logWarning_Should_LogWarnMessageWithHttpStatus() { - - LogService.logWarning(HttpStatus.INTERNAL_SERVER_ERROR, exception); - verify(logger, times(1)) - .warn( - eq(MESSAGE_API_LOG_TEXT + ": {}"), - eq(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()), - anyString()); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logWarning_Should_LogExceptionStackTrace() { - - LogService.logWarning(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - } - - @Test - public void logDebug_Should_LogMessage() { - - LogService.logDebug(ERROR_MESSAGE); - verify(logger, times(1)).debug(MESSAGE_API_LOG_TEXT, ERROR_MESSAGE); - } - - @Test - public void logWarning_Should_LogErrorMessage() { - - LogService.logWarning(ERROR_MESSAGE); - verify(logger, times(1)).warn(MESSAGE_API_LOG_TEXT, ERROR_MESSAGE); - } - - @Test - public void logStatisticEventError_Should_LogExceptionStackTraceAndErrorMessage() { - - LogService.logStatisticsEventError(exception); - verify(exception, atLeastOnce()).printStackTrace(any(PrintWriter.class)); - verify(logger, times(1)) - .error(anyString(), eq(STATISTICS_EVENT_PROCESSING_ERROR), anyString()); - } - - @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/messageservice/api/service/RocketChatServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java index 6847705..361911f 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java @@ -21,7 +21,6 @@ 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 de.caritas.cob.messageservice.api.exception.CustomCryptoException; import de.caritas.cob.messageservice.api.exception.InternalServerErrorException; @@ -51,12 +50,12 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.powermock.reflect.Whitebox; import org.slf4j.Logger; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; @@ -98,31 +97,31 @@ public class RocketChatServiceTest { @Before public void setup() throws NoSuchFieldException, SecurityException { - Whitebox.setInternalState(rocketChatService, "rcHeaderAuthToken", RC_TOKEN); - Whitebox.setInternalState(rocketChatService, "rcHeaderUserId", RC_USER_ID); - Whitebox.setInternalState(rocketChatService, "rcQueryParamRoomId", RC_GROUP_ID); - Whitebox.setInternalState(rocketChatService, "rcQueryParamOffset", String.valueOf(RC_OFFSET)); - Whitebox.setInternalState(rocketChatService, "rcQueryParamCount", String.valueOf(RC_COUNT)); - Whitebox.setInternalState(rocketChatService, "rcQueryParamSort", "sort"); - Whitebox.setInternalState(rocketChatService, "rcQueryParamSortValue", "{\"ts\":1}"); - Whitebox.setInternalState(rocketChatService, "rcSendMessageUrl", "http://localhost/api/v1/chat.sendMessage"); - Whitebox.setInternalState(rocketChatService, "rcPostGroupMessagesRead", FIELD_VALUE_RC_POST_GROUP_MESSAGES_READ); - Whitebox.setInternalState(rocketChatService, FIELD_NAME_RC_GET_GROUP_INFO_URL, FIELD_VALUE_RC_GET_GROUP_INFO_URL); - setInternalState(LogService.class, "LOGGER", logger); + ReflectionTestUtils.setField(rocketChatService, "rcHeaderAuthToken", RC_TOKEN); + ReflectionTestUtils.setField(rocketChatService, "rcHeaderUserId", RC_USER_ID); + ReflectionTestUtils.setField(rocketChatService, "rcQueryParamRoomId", RC_GROUP_ID); + ReflectionTestUtils.setField(rocketChatService, "rcQueryParamOffset", String.valueOf(RC_OFFSET)); + ReflectionTestUtils.setField(rocketChatService, "rcQueryParamCount", String.valueOf(RC_COUNT)); + ReflectionTestUtils.setField(rocketChatService, "rcQueryParamSort", "sort"); + ReflectionTestUtils.setField(rocketChatService, "rcQueryParamSortValue", "{\"ts\":1}"); + ReflectionTestUtils.setField(rocketChatService, "rcSendMessageUrl", "http://localhost/api/v1/chat.sendMessage"); + ReflectionTestUtils.setField(rocketChatService, "rcPostGroupMessagesRead", FIELD_VALUE_RC_POST_GROUP_MESSAGES_READ); + ReflectionTestUtils.setField(rocketChatService, FIELD_NAME_RC_GET_GROUP_INFO_URL, FIELD_VALUE_RC_GET_GROUP_INFO_URL); + } @Test(expected = InternalServerErrorException.class) public void getGroupMessages_Should_ThrowInternalServerErrorException_When_BuildMessageStreamUriFails() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", (Object[]) null); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", (Object[]) null); rocketChatService.getGroupMessages(RC_TOKEN, RC_USER_ID, RC_GROUP_ID, 0, 0, Instant.now()); } @Test(expected = InternalServerErrorException.class) public void getGroupMessages_Should_ThrowInternalServerErrorException_When_RocketChatRequestFails() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); HttpClientErrorException ex = new HttpClientErrorException(HttpStatus.BAD_REQUEST); when(restTemplate.exchange(any(), any(HttpMethod.class), any(), @@ -134,7 +133,7 @@ public void getGroupMessages_Should_ThrowInternalServerErrorException_When_Rocke @Test(expected = InternalServerErrorException.class) public void getGroupMessages_Should_ThrowInternalServerErrorException_When_DecryptionOfMessageFails() throws NoSuchFieldException, CustomCryptoException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); EasyRandom easyRandom = new EasyRandom(); MessageStreamDTO messageStreamDTO = easyRandom.nextObject(MessageStreamDTO.class); @@ -154,7 +153,7 @@ public void getGroupMessages_Should_ThrowInternalServerErrorException_When_Decry @Test public void getGroupMessages_Should_ReturnMessageStreamDTO_When_ProvidedWithValidParameters() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); List messages = new ArrayList<>(); ResponseEntity entity = new ResponseEntity<>( @@ -170,7 +169,7 @@ public void getGroupMessages_Should_ReturnMessageStreamDTO_When_ProvidedWithVali @Test public void getGroupMessages_Should_DecryptAllMessages() throws CustomCryptoException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); EasyRandom easyRandom = new EasyRandom(); MessageStreamDTO messageStreamDTO = easyRandom.nextObject(MessageStreamDTO.class); @@ -189,7 +188,7 @@ public void getGroupMessages_Should_DecryptAllMessages() throws CustomCryptoExce @Test public void getGroupMessages_Should_SetForwardAsMessageType_ForForwardedMessages() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); EasyRandom easyRandom = new EasyRandom(); MessageStreamDTO messageStreamDTO = easyRandom.nextObject(MessageStreamDTO.class); messageStreamDTO.setMessages(easyRandom.objects(MessagesDTO.class, 5) @@ -220,7 +219,7 @@ public void getGroupMessages_Should_SetForwardAsMessageType_ForForwardedMessages public void getGroupMessages_Should_SetVideocallAsMessageType_ForVideocallMessages() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); EasyRandom easyRandom = new EasyRandom(); MessageStreamDTO messageStreamDTO = easyRandom.nextObject(MessageStreamDTO.class); messageStreamDTO.setMessages(easyRandom.objects(MessagesDTO.class, 5) @@ -250,7 +249,7 @@ public void getGroupMessages_Should_SetVideocallAsMessageType_ForVideocallMessag @Test public void getGroupMessages_Should_SetFurtherStepsAsMessageType_ForFurtherStepsMessages() throws NoSuchFieldException { - Whitebox.setInternalState(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); + ReflectionTestUtils.setField(rocketChatService, "rcGetGroupMessageUrl", "http://localhost/api/v1/groups.messages"); EasyRandom easyRandom = new EasyRandom(); MessageStreamDTO messageStreamDTO = easyRandom.nextObject(MessageStreamDTO.class); messageStreamDTO.setMessages(easyRandom.objects(MessagesDTO.class, 5) diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/dto/MessageTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/dto/MessageTest.java index 1e8ad3a..6a6e428 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/dto/MessageTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/dto/MessageTest.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import de.caritas.cob.messageservice.api.model.ConsultantReassignment; +import de.caritas.cob.messageservice.api.model.AliasArgs; import de.caritas.cob.messageservice.api.model.MessageType; import java.util.ArrayList; import java.util.HashMap; @@ -136,7 +136,7 @@ void objectMapperTest() throws JsonProcessingException { var stored = "{"toConsultantId":"8a81117b-d875-4ba4-8696-d62c3a2dae91","status":"REQUESTED"}"; stored = stored.replace(""", "\""); - var result = new ObjectMapper().readValue(stored, ConsultantReassignment.class); + var result = new ObjectMapper().readValue(stored, AliasArgs.class); assertThat(result.getStatus(), Matchers.is(REQUESTED)); } diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/helper/RocketChatCredentialsHelperTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/helper/RocketChatCredentialsHelperTest.java index 221f93f..61e398a 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/helper/RocketChatCredentialsHelperTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/helper/RocketChatCredentialsHelperTest.java @@ -16,12 +16,12 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.powermock.reflect.Whitebox; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; @@ -116,12 +116,12 @@ public class RocketChatCredentialsHelperTest { @Before public void setup() throws NoSuchFieldException { - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USERNAME, SYSTEM_USER_USERNAME); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_PASSWORD, SYSTEM_USER_PW); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_API_POST_USER_LOGIN, RC_URL_CHAT_USER_LOGIN); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_API_POST_USER_LOGOUT, RC_URL_CHAT_USER_LOGOUT); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_HEADER_AUTH_TOKEN, FIELD_VALUE_ROCKET_CHAT_HEADER_AUTH_TOKEN); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_HEADER_USER_ID, FIELD_VALUE_ROCKET_CHAT_HEADER_USER_ID); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USERNAME, SYSTEM_USER_USERNAME); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_PASSWORD, SYSTEM_USER_PW); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_API_POST_USER_LOGIN, RC_URL_CHAT_USER_LOGIN); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_API_POST_USER_LOGOUT, RC_URL_CHAT_USER_LOGOUT); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_HEADER_AUTH_TOKEN, FIELD_VALUE_ROCKET_CHAT_HEADER_AUTH_TOKEN); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_ROCKET_CHAT_HEADER_USER_ID, FIELD_VALUE_ROCKET_CHAT_HEADER_USER_ID); } /** @@ -177,7 +177,7 @@ public void updateCredentials_Should_LoginBUsers_WhenAUsersAreLoggedIn() RocketChatCredentials systemA = new RocketChatCredentials(SYSTEM_USER_A_TOKEN, SYSTEM_USER_A_ID, SYSTEM_USER_A_USERNAME, LocalDateTime.now().minusMinutes(5)); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, systemA); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, systemA); // Get and check system user - pre test needs to be User A RocketChatCredentials systemUser = rcCredentialHelper.getSystemUser(); @@ -206,13 +206,13 @@ public void updateCredentials_Should_LogoutAndReLoginBUsers_WhenAllUsersArePrese // create and set system A user RocketChatCredentials systemA = new RocketChatCredentials(SYSTEM_USER_A_TOKEN, SYSTEM_USER_A_ID, SYSTEM_USER_A_USERNAME, LocalDateTime.now().minusMinutes(5)); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, systemA); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, systemA); // create and set system B user RocketChatCredentials systemB = new RocketChatCredentials(SYSTEM_USER_B_TOKEN, SYSTEM_USER_B_ID, SYSTEM_USER_B_USERNAME, LocalDateTime.now().minusMinutes(1)); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, systemB); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, systemB); // prepare logout intercept for system user HttpHeaders headersLogoutSys = new HttpHeaders(); @@ -274,7 +274,7 @@ public void getSystemUser_Should_ReturnUserA_WhenOnlyUserAIsInitialized() RocketChatCredentials sysUserA = new RocketChatCredentials(SYSTEM_USER_A_ID, SYSTEM_USER_A_TOKEN, SYSTEM_USER_A_USERNAME, LocalDateTime.now()); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); RocketChatCredentials systemUser = rcCredentialHelper.getSystemUser(); @@ -288,7 +288,7 @@ public void getSystemUser_Should_ReturnUserB_WhenOnlyUserBIsInitialized() RocketChatCredentials sysUserB = new RocketChatCredentials(SYSTEM_USER_B_ID, SYSTEM_USER_B_TOKEN, SYSTEM_USER_B_USERNAME, LocalDateTime.now()); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); RocketChatCredentials systemUser = rcCredentialHelper.getSystemUser(); @@ -303,13 +303,13 @@ public void getSystemUser_Should_ReturnUserA_WhenUserAIsNewer() RocketChatCredentials sysUserA = new RocketChatCredentials(SYSTEM_USER_A_ID, SYSTEM_USER_A_TOKEN, SYSTEM_USER_A_USERNAME, LocalDateTime.now()); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); // Prepare User B - 5 minutes older than User A RocketChatCredentials sysUserB = new RocketChatCredentials(SYSTEM_USER_B_ID, SYSTEM_USER_B_TOKEN, SYSTEM_USER_B_USERNAME, LocalDateTime.now().minusMinutes(5)); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); // Get User from Class (actual test) RocketChatCredentials systemUser = rcCredentialHelper.getSystemUser(); @@ -326,13 +326,13 @@ public void getSystemUser_Should_ReturnUserB_WhenUserBIsNewer() RocketChatCredentials sysUserA = new RocketChatCredentials(SYSTEM_USER_A_ID, SYSTEM_USER_A_TOKEN, SYSTEM_USER_A_USERNAME, LocalDateTime.now().minusMinutes(5)); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_A, sysUserA); // Prepare User B RocketChatCredentials sysUserB = new RocketChatCredentials(SYSTEM_USER_B_ID, SYSTEM_USER_B_TOKEN, SYSTEM_USER_B_USERNAME, LocalDateTime.now()); - Whitebox.setInternalState(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); + ReflectionTestUtils.setField(rcCredentialHelper, FIELD_NAME_SYSTEM_USER_B, sysUserB); // Get User from Class (actual test) RocketChatCredentials systemUser = rcCredentialHelper.getSystemUser(); diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/helper/ServiceHelperTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/helper/ServiceHelperTest.java index ff563f6..1169463 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/helper/ServiceHelperTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/helper/ServiceHelperTest.java @@ -8,7 +8,7 @@ import de.caritas.cob.messageservice.api.service.TenantHeaderSupplier; import java.util.Enumeration; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Before; import org.junit.Test; @@ -17,10 +17,10 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; -import org.powermock.reflect.Whitebox; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -52,8 +52,8 @@ public class ServiceHelperTest { @Before public void setup() throws NoSuchFieldException, SecurityException { givenRequestContextIsSet(); - Whitebox.setInternalState(serviceHelper, FIELD_NAME_CSRF_TOKEN_HEADER_PROPERTY, CSRF_TOKEN_HEADER_VALUE); - Whitebox.setInternalState(serviceHelper, FIELD_NAME_CSRF_TOKEN_COOKIE_PROPERTY, CSRF_TOKEN_COOKIE_VALUE); + ReflectionTestUtils.setField(serviceHelper, FIELD_NAME_CSRF_TOKEN_HEADER_PROPERTY, CSRF_TOKEN_HEADER_VALUE); + ReflectionTestUtils.setField(serviceHelper, FIELD_NAME_CSRF_TOKEN_COOKIE_PROPERTY, CSRF_TOKEN_COOKIE_VALUE); } private void givenRequestContextIsSet() { diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java index f47ad2f..e0c0ebe 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java @@ -6,7 +6,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; 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.messageservice.api.service.LogService; @@ -45,7 +44,6 @@ public void setup() { createMessageStatisticsEvent = Mockito.mock(CreateMessageStatisticsEvent.class); when(createMessageStatisticsEvent.getEventType()).thenReturn(eventType); when(createMessageStatisticsEvent.getPayload()).thenReturn(Optional.of(PAYLOAD)); - setInternalState(LogService.class, "LOGGER", logger); setField(statisticsService, FIELD_NAME_RABBIT_EXCHANGE_NAME, RABBIT_EXCHANGE_NAME); } diff --git a/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java index ae53b9b..3bd7488 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java @@ -6,7 +6,7 @@ import com.google.common.collect.Maps; import java.util.HashMap; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/api/tenant/CustomHeaderTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolverTest.java index a25f2da..720c948 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/CustomHeaderTenantResolverTest.java @@ -6,7 +6,7 @@ import de.caritas.cob.messageservice.api.service.TenantHeaderSupplier; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/api/tenant/SubdomainTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolverTest.java index b058aba..bbc680b 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/SubdomainTenantResolverTest.java @@ -6,7 +6,7 @@ import de.caritas.cob.messageservice.api.service.TenantService; import de.caritas.cob.messageservice.filter.SubdomainExtractor; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/api/tenant/TechnicalUserTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java index 9cb6487..d5b2761 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java @@ -4,7 +4,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/messageservice/api/tenant/TenantResolverServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java index 1db3af5..eaa1a30 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java @@ -5,7 +5,7 @@ import static org.mockito.Mockito.when; import java.util.Optional; -import javax.servlet.http.HttpServletRequest; +import jakarta.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/messageservice/filter/HttpTenantFilterTest.java b/src/test/java/de/caritas/cob/messageservice/filter/HttpTenantFilterTest.java index e1696c5..57e2dce 100644 --- a/src/test/java/de/caritas/cob/messageservice/filter/HttpTenantFilterTest.java +++ b/src/test/java/de/caritas/cob/messageservice/filter/HttpTenantFilterTest.java @@ -2,10 +2,10 @@ import de.caritas.cob.messageservice.api.tenant.TenantResolverService; import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; 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/messageservice/filter/StatelessCsrfFilterTest.java b/src/test/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilterTest.java index f4f6ab5..ef9e8b0 100644 --- a/src/test/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilterTest.java +++ b/src/test/java/de/caritas/cob/messageservice/filter/StatelessCsrfFilterTest.java @@ -8,11 +8,11 @@ import static org.springframework.test.util.ReflectionTestUtils.setField; import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/src/test/java/de/caritas/cob/messageservice/filter/SubdomainExtractorTest.java b/src/test/java/de/caritas/cob/messageservice/filter/SubdomainExtractorTest.java index ac7735a..0a8f88e 100644 --- a/src/test/java/de/caritas/cob/messageservice/filter/SubdomainExtractorTest.java +++ b/src/test/java/de/caritas/cob/messageservice/filter/SubdomainExtractorTest.java @@ -5,7 +5,7 @@ import java.net.URISyntaxException; import java.util.Enumeration; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.assertj.core.api.AssertionsForClassTypes; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; From c95d685c8828788c8f318e3e04815fdd8f58171f Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Fri, 12 Apr 2024 16:40:24 +0200 Subject: [PATCH 2/6] fix: partial commit --- .../java/de/caritas/cob/messageservice/MessengerTest.java | 6 ++++++ .../cob/messageservice/api/helper/JSONHelperTests.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/test/java/de/caritas/cob/messageservice/MessengerTest.java b/src/test/java/de/caritas/cob/messageservice/MessengerTest.java index 78a6722..9761d1d 100644 --- a/src/test/java/de/caritas/cob/messageservice/MessengerTest.java +++ b/src/test/java/de/caritas/cob/messageservice/MessengerTest.java @@ -35,6 +35,7 @@ import de.caritas.cob.messageservice.api.service.LiveEventNotificationService; import de.caritas.cob.messageservice.api.service.MessageMapper; import de.caritas.cob.messageservice.api.service.RocketChatService; +import de.caritas.cob.messageservice.api.service.SessionService; import de.caritas.cob.messageservice.api.service.statistics.StatisticsService; import de.caritas.cob.messageservice.api.service.statistics.event.CreateMessageStatisticsEvent; import de.caritas.cob.messageservice.statisticsservice.generated.web.model.UserRole; @@ -88,10 +89,14 @@ public class MessengerTest { @Mock private AuthenticatedUser authenticatedUser; + @Mock + private SessionService sessionService; + @SuppressWarnings("unused") @Spy private MessageMapper mapper = new MessageMapper(new ObjectMapper(), null); + @Before public void setup() { setField(this.messenger, "rocketChatSystemUserId", RC_SYSTEM_USER_ID); @@ -264,6 +269,7 @@ public void postFeedbackGroupMessage_Should_ReturnCreatedAndSendFeedbackNotifica when(rocketChatService.getGroupInfo(RC_TOKEN, RC_USER_ID, RC_FEEDBACK_GROUP_ID)) .thenReturn(GET_GROUP_INFO_DTO_FEEDBACK_CHAT); var feedbackGroupMessage = createFeedbackGroupMessage().build(); + feedbackGroupMessage.setSendNotification(true); when(rocketChatService.postGroupMessage(feedbackGroupMessage)).thenReturn( POST_MESSAGE_RESPONSE_DTO); diff --git a/src/test/java/de/caritas/cob/messageservice/api/helper/JSONHelperTests.java b/src/test/java/de/caritas/cob/messageservice/api/helper/JSONHelperTests.java index b805a9f..8868c2b 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/helper/JSONHelperTests.java +++ b/src/test/java/de/caritas/cob/messageservice/api/helper/JSONHelperTests.java @@ -76,6 +76,10 @@ public void serialize_Should_returnOptionalWithSerializedObject() { + EventType.CREATE_MESSAGE + "\"," + " \"hasAttachment\": false" + + "," + + " \"receiverId\": null" + + "," + + " \"tenantId\": null" + "}"; assertThat(result.get(), jsonEquals(expectedJson).whenIgnoringPaths("timestamp")); From ca34c627ef6ec864824dc114c148ebca402a76b3 Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Sat, 13 Apr 2024 10:59:01 +0200 Subject: [PATCH 3/6] fix: unit tests --- .../api/authorization/Authority.java | 14 ++++++++------ .../api/controller/MessageController.java | 5 +++-- .../RoleAuthorizationAuthorityMapperTest.java | 2 +- .../api/service/RocketChatServiceTest.java | 5 +++-- .../service/statistics/StatisticsServiceTest.java | 6 +++--- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java b/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java index 63afafb..33280bf 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java +++ b/src/main/java/de/caritas/cob/messageservice/api/authorization/Authority.java @@ -9,7 +9,7 @@ import static java.util.Collections.singletonList; import java.util.List; -import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Getter; @@ -37,12 +37,14 @@ public enum Authority { * @return the related authorities */ public static List getAuthoritiesByUserRole(Role userRole) { - Optional authorityByUserRole = Stream.of(values()) - .filter(authority -> authority.getRoleName().equals(userRole)) - .findFirst(); + var authorities = Stream.of(values()) + .filter(authority -> authority.getRoleName().equals(userRole.getRoleName())).toList(); + + List collect = authorities.stream().map(a -> a.getAuthorities()) + .flatMap(a -> a.stream()).collect( + Collectors.toList()); + return authorities.isEmpty() ? emptyList() : collect; - return authorityByUserRole.isPresent() ? authorityByUserRole.get().getAuthorities() - : emptyList(); } public static Authority fromRoleName(String roleName) { diff --git a/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java b/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java index 826802d..1db6055 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java +++ b/src/main/java/de/caritas/cob/messageservice/api/controller/MessageController.java @@ -35,8 +35,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; /** @@ -192,6 +190,9 @@ public ResponseEntity createFeedbackMessage(String rcToken, public ResponseEntity createVideoHintMessage(String rcGroupId, VideoCallMessageDTO videoCallMessageDTO) { + if (videoCallMessageDTO == null) { + throw new BadRequestException("VideoCallMessageDTO is required.", LogService::logBadRequest); + } var response = this.messenger.createVideoHintMessage(rcGroupId, videoCallMessageDTO); diff --git a/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java b/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java index bfcd4ba..6a41cfb 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java @@ -29,7 +29,7 @@ public class RoleAuthorizationAuthorityMapperTest { .collect(Collectors.toSet()); @Test - public void roleAuthorizationAuthorityMapper_Should_GrantCorrectAuthorities() throws Exception { + public void roleAuthorizationAuthorityMapper_Should_GrantCorrectAuthorities() { Principal principal = mock(Principal.class); RefreshableKeycloakSecurityContext securityContext = diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java index 361911f..bd849e6 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/RocketChatServiceTest.java @@ -380,13 +380,14 @@ public void markGroupAsReadForSystemUser_Should_MarkGroupAsRead_When_ProvidedWit } @Test - public void markGroupAsReadForSystemUser_Should_LogError_When_ProvidedWithInvalidRocketChatSystemUserCredentials() + public void markGroupAsReadForSystemUser_Should_NotInteractWithRestTemplate_When_ProvidedWithInvalidRocketChatSystemUserCredentials() throws SecurityException, RocketChatUserNotInitializedException { when(rcCredentialsHelper.getSystemUser()).thenReturn(INVALID_RCC_SYSTEM_USER); rocketChatService.markGroupAsReadForSystemUser(RC_GROUP_ID); - verify(logger, times(1)).error(anyString(), anyString()); + + verifyNoInteractions(restTemplate); } @Test(expected = InternalServerErrorException.class) diff --git a/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java index e0c0ebe..f253bb1 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/service/statistics/StatisticsServiceTest.java @@ -5,10 +5,10 @@ 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.springframework.test.util.ReflectionTestUtils.setField; -import de.caritas.cob.messageservice.api.service.LogService; import de.caritas.cob.messageservice.api.service.statistics.event.CreateMessageStatisticsEvent; import de.caritas.cob.messageservice.statisticsservice.generated.web.model.EventType; import java.nio.charset.StandardCharsets; @@ -73,12 +73,12 @@ public void fireEvent_Should_SendStatisticsMessage_WhenStatisticsIsEnabled() { } @Test - public void fireEvent_Should_LogWarning_WhenPayloadIsEmpty() { + public void fireEvent_Should_NotSendMessageToQueue_WhenPayloadIsEmpty() { setField(statisticsService, FIELD_NAME_STATISTICS_ENABLED, true); when(createMessageStatisticsEvent.getPayload()).thenReturn(Optional.empty()); statisticsService.fireEvent(createMessageStatisticsEvent); - verify(logger, times(1)).warn(anyString(), anyString(), anyString()); + verifyNoInteractions(amqpTemplate); } @Test From 6b744f0fb2481c6c7a3abdb5b6b24c9b64062406 Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Mon, 15 Apr 2024 12:05:31 +0200 Subject: [PATCH 4/6] fix: change base docker image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b8159e1..f75e289 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM adoptopenjdk/openjdk11 +FROM openjdk:17-oracle VOLUME ["/tmp","/log"] EXPOSE 8080 ARG JAR_FILE From 54c5cccd5d3b8faf01e60e13c23bc9631a4e5939 Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Mon, 15 Apr 2024 12:17:30 +0200 Subject: [PATCH 5/6] fix: upgrade liquibase, spring boot --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 171cdca..d29dd4e 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ org.springframework.boot spring-boot-starter-parent - 3.0.6 + 3.0.13 @@ -29,8 +29,8 @@ 2.17.1 0.2.3 6.4.0 - 4.9.1 - 4.1.1 + 4.23.2 + 4.23.2 3.0.0 6.0.5 17 From 2951b87d0099fe7a0d0ad16bbac811fcfef9adaf Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Mon, 15 Apr 2024 13:34:37 +0200 Subject: [PATCH 6/6] fix: upgrade liquibase, spring boot, added authenticated user config --- google_checks_light.xml | 1 - pom.xml | 3 +- .../MessageServiceApplication.java | 114 +----------------- .../api/tenant/AccessTokenTenantResolver.java | 39 +++--- .../tenant/TechnicalUserTenantResolver.java | 40 ++++-- .../config/AuthenticatedUserConfig.java | 72 +++++++++++ ....java => AuthenticatedUserConfigTest.java} | 8 +- .../RoleAuthorizationAuthorityMapperTest.java | 85 +++++++------ .../tenant/AccessTokenTenantResolverTest.java | 50 ++++++-- .../TechnicalUserTenantResolverTest.java | 60 +++++++-- .../api/tenant/TenantResolverServiceTest.java | 4 +- 11 files changed, 271 insertions(+), 205 deletions(-) create mode 100644 src/main/java/de/caritas/cob/messageservice/config/AuthenticatedUserConfig.java rename src/test/java/de/caritas/cob/messageservice/{MessageServiceApplicationTests.java => AuthenticatedUserConfigTest.java} (63%) diff --git a/google_checks_light.xml b/google_checks_light.xml index 339138d..241ddfa 100644 --- a/google_checks_light.xml +++ b/google_checks_light.xml @@ -306,7 +306,6 @@ --> - diff --git a/pom.xml b/pom.xml index d29dd4e..8bab793 100644 --- a/pom.xml +++ b/pom.xml @@ -442,14 +442,13 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.1.1 + 3.3.0 validate validate google_checks_light.xml - UTF-8 true true true diff --git a/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java b/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java index c89ff70..358ed3c 100644 --- a/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java +++ b/src/main/java/de/caritas/cob/messageservice/MessageServiceApplication.java @@ -1,130 +1,18 @@ package de.caritas.cob.messageservice; -import static java.util.Objects.nonNull; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.collections4.CollectionUtils; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.keycloak.representations.AccessToken; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import de.caritas.cob.messageservice.api.exception.KeycloakException; -import de.caritas.cob.messageservice.api.helper.AuthenticatedUser; + @SpringBootApplication @EnableScheduling @EnableAsync public class MessageServiceApplication { - private static final String CLAIM_NAME_USER_ID = "userId"; - private static final String CLAIM_NAME_USERNAME = "username"; - public static void main(String[] args) { SpringApplication.run(MessageServiceApplication.class, args); } - /** - * Returns the @KeycloakAuthenticationToken which represents the token for a Keycloak - * authentication. - * - * @return KeycloakAuthenticationToken - */ - @Bean - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public KeycloakAuthenticationToken getAccessToken() { - return (KeycloakAuthenticationToken) getRequest().getUserPrincipal(); - } - - /** - * Returns the @KeycloakSecurityContext - * - * @return KeycloakSecurityContext - */ - @Bean - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public KeycloakSecurityContext getKeycloakSecurityContext() { - return ((KeycloakAuthenticationToken) getRequest().getUserPrincipal()) - .getAccount() - .getKeycloakSecurityContext(); - } - - /** - * Returns the Keycloak user id of the authenticated user - * - * @return {@link AuthenticatedUser} - */ - @Bean - @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) - public AuthenticatedUser getAuthenticatedUser() { - - // Get current KeycloakSecurityContext - KeycloakSecurityContext keycloakSecContext = - ((KeycloakAuthenticationToken) getRequest().getUserPrincipal()) - .getAccount() - .getKeycloakSecurityContext(); - - Map claimMap = keycloakSecContext.getToken().getOtherClaims(); - - AuthenticatedUser authenticatedUser = new AuthenticatedUser(); - - if (claimMap.containsKey(CLAIM_NAME_USER_ID)) { - authenticatedUser.setUserId(claimMap.get(CLAIM_NAME_USER_ID).toString()); - } else { - throw new KeycloakException( - "Keycloak user attribute '" + CLAIM_NAME_USER_ID + "' not found."); - } - - if (claimMap.containsKey(CLAIM_NAME_USERNAME)) { - authenticatedUser.setUsername(claimMap.get(CLAIM_NAME_USERNAME).toString()); - } - - // Set user roles - AccessToken.Access realmAccess = - ((KeycloakAuthenticationToken) getRequest().getUserPrincipal()) - .getAccount() - .getKeycloakSecurityContext() - .getToken() - .getRealmAccess(); - Set roles = realmAccess.getRoles(); - if (CollectionUtils.isNotEmpty(roles)) { - authenticatedUser.setRoles(roles); - } else { - throw new KeycloakException( - String.format( - "Keycloak roles null or not set for user: %s", authenticatedUser.getUserId())); - } - - // Set granted authorities - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - authenticatedUser.setGrantedAuthorities( - authentication.getAuthorities().stream().map(Object::toString).collect(Collectors.toSet())); - - // Set Keycloak token to authenticated user object - if (nonNull(keycloakSecContext.getTokenString())) { - authenticatedUser.setAccessToken(keycloakSecContext.getTokenString()); - } else { - throw new KeycloakException("No valid Keycloak access token string found."); - } - - return authenticatedUser; - } - - private HttpServletRequest getRequest() { - return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) - .getRequest(); - } } diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java index 8b7bd91..446ca02 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolver.java @@ -1,12 +1,13 @@ package de.caritas.cob.messageservice.api.tenant; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; import java.util.Optional; -import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.stereotype.Component; @@ -19,31 +20,39 @@ public class AccessTokenTenantResolver implements TenantResolver { @Override public Optional resolve(HttpServletRequest request) { - return resolveTenantIdFromTokenClaims(request); + return resolveTenantIdFromTokenClaims(); } - private Optional resolveTenantIdFromTokenClaims(HttpServletRequest request) { - Map claimMap = getClaimMap(request); + private Optional resolveTenantIdFromTokenClaims() { + Map claimMap = getClaimMap(); log.debug("Found tenantId in claim : " + claimMap.toString()); return getUserTenantIdAttribute(claimMap); } private Optional getUserTenantIdAttribute(Map claimMap) { if (claimMap.containsKey(TENANT_ID)) { - Integer tenantId = (Integer) claimMap.get(TENANT_ID); - return Optional.of(Long.valueOf(tenantId)); - } else { - return Optional.empty(); + Object tenantIdObject = claimMap.get(TENANT_ID); + if (tenantIdObject instanceof Long tenantId) { + return Optional.of(tenantId); + } + if (tenantIdObject instanceof Integer tenantId) { + return Optional.of(Long.valueOf(tenantId)); + } } + return Optional.empty(); } - private Map getClaimMap(HttpServletRequest request) { - KeycloakSecurityContext keycloakSecContext = - ((KeycloakAuthenticationToken) request.getUserPrincipal()).getAccount() - .getKeycloakSecurityContext(); - return keycloakSecContext.getToken().getOtherClaims(); + private Map getClaimMap() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + var jwt = (Jwt) authentication.getPrincipal(); + return jwt.getClaims(); + } else { + return Map.of(); + } } + @Override public boolean canResolve(HttpServletRequest request) { return resolve(request).isPresent(); diff --git a/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java b/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java index b970765..6b42b2d 100644 --- a/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java +++ b/src/main/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolver.java @@ -1,9 +1,14 @@ package de.caritas.cob.messageservice.api.tenant; -import java.util.Optional; +import com.google.common.collect.Lists; import jakarta.servlet.http.HttpServletRequest; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.keycloak.representations.AccessToken; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.stereotype.Component; @Component @@ -11,19 +16,34 @@ public class TechnicalUserTenantResolver implements TenantResolver { @Override public Optional resolve(HttpServletRequest request) { - return isTechnicalUserRole(request) ? Optional.of(0L) : Optional.empty(); + return isTechnicalUserRole() ? Optional.of(0L) : Optional.empty(); } - private boolean isTechnicalUserRole(HttpServletRequest request) { - AccessToken token = ((KeycloakAuthenticationToken) request.getUserPrincipal()).getAccount() - .getKeycloakSecurityContext().getToken(); - return hasRoles(token) && token.getRealmAccess().getRoles().contains("technical"); + private boolean isTechnicalUserRole() { + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Jwt jwt = (Jwt) authentication.getPrincipal(); + return getRealmRoles(jwt).contains("technical"); + } + return false; } - private boolean hasRoles(AccessToken accessToken) { - return accessToken.getRealmAccess() != null && accessToken.getRealmAccess().getRoles() != null; + private Collection getRealmRoles(Jwt jwt) { + + if (jwt != null) { + var claims = jwt.getClaims(); + if (claims.containsKey("realm_access")) { + Map realmAccess = (Map) claims.get("realm_access"); + if (realmAccess.containsKey("roles")) { + return (List) realmAccess.get("roles"); + } + } + } + return Lists.newArrayList(); } + @Override public boolean canResolve(HttpServletRequest request) { return resolve(request).isPresent(); diff --git a/src/main/java/de/caritas/cob/messageservice/config/AuthenticatedUserConfig.java b/src/main/java/de/caritas/cob/messageservice/config/AuthenticatedUserConfig.java new file mode 100644 index 0000000..e839626 --- /dev/null +++ b/src/main/java/de/caritas/cob/messageservice/config/AuthenticatedUserConfig.java @@ -0,0 +1,72 @@ +package de.caritas.cob.messageservice.config; + +import com.google.common.collect.Lists; +import de.caritas.cob.messageservice.api.exception.KeycloakException; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +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; +import de.caritas.cob.messageservice.api.helper.AuthenticatedUser; + +/** + * 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"; + + /** + * Returns the currently authenticated user. + * + * @return {@link AuthenticatedUser} + */ + @Bean + @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) + public AuthenticatedUser getAuthenticatedUser() { + JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) getRequest().getUserPrincipal(); + 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)); + authenticatedUser.setRoles(extractRealmRoles(authenticationToken.getToken()).stream().collect( + Collectors.toSet())); + return authenticatedUser; + + } + + 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(); + } + + 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(); + } + + private HttpServletRequest getRequest() { + return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) + .getRequest(); + } +} diff --git a/src/test/java/de/caritas/cob/messageservice/MessageServiceApplicationTests.java b/src/test/java/de/caritas/cob/messageservice/AuthenticatedUserConfigTest.java similarity index 63% rename from src/test/java/de/caritas/cob/messageservice/MessageServiceApplicationTests.java rename to src/test/java/de/caritas/cob/messageservice/AuthenticatedUserConfigTest.java index 002a077..874887e 100644 --- a/src/test/java/de/caritas/cob/messageservice/MessageServiceApplicationTests.java +++ b/src/test/java/de/caritas/cob/messageservice/AuthenticatedUserConfigTest.java @@ -1,19 +1,21 @@ package de.caritas.cob.messageservice; import static org.junit.Assert.assertNull; + +import de.caritas.cob.messageservice.config.AuthenticatedUserConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -public class MessageServiceApplicationTests { +public class AuthenticatedUserConfigTest { @MockBean - MessageServiceApplication messageServiceApplication; + AuthenticatedUserConfig authenticatedUserConfig; @Test public void getAuthenticatedUser_Should_ReturnNullWhenNoUserSessionActive() { - assertNull(messageServiceApplication.getAuthenticatedUser()); + assertNull(authenticatedUserConfig.getAuthenticatedUser()); } } diff --git a/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java b/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java index 6a41cfb..d82cb79 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/authorization/RoleAuthorizationAuthorityMapperTest.java @@ -1,57 +1,70 @@ package de.caritas.cob.messageservice.api.authorization; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.mockito.Mockito.mock; +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; -import java.security.Principal; -import java.util.HashSet; -import java.util.Set; +import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; -import org.junit.runner.RunWith; -import org.keycloak.adapters.RefreshableKeycloakSecurityContext; -import org.keycloak.adapters.spi.KeycloakAccount; -import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount; -import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -@RunWith(MockitoJUnitRunner.class) public class RoleAuthorizationAuthorityMapperTest { - private final KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider(); - private final Set roles = Stream.of(Role.values()) - .map(Role::getRoleName) - .collect(Collectors.toSet()); + private final RoleAuthorizationAuthorityMapper roleAuthorizationAuthorityMapper = + new RoleAuthorizationAuthorityMapper(); @Test - public void roleAuthorizationAuthorityMapper_Should_GrantCorrectAuthorities() { + public void mapAuthorities_Should_returnGrantedConsultantAuthority_When_authorityConsultant() { + List grantedAuthorities = Stream.of("consultant") + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); - Principal principal = mock(Principal.class); - RefreshableKeycloakSecurityContext securityContext = - mock(RefreshableKeycloakSecurityContext.class); - KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, securityContext); + Collection mappedAuthorities = this.roleAuthorizationAuthorityMapper + .mapAuthorities(grantedAuthorities); - KeycloakAuthenticationToken token = new KeycloakAuthenticationToken(account, false); + assertThat(mappedAuthorities).hasSize(1); + List authorities = mappedAuthorities.stream() + .map(grantedAuthority -> grantedAuthority.getAuthority()).toList(); + assertThat(authorities).containsAll(Authority.CONSULTANT.getAuthorities()); + } + + @Test + public void mapAuthorities_Should_returnGrantedTechnicalAuthority_When_authoritiesContainsTechnical() { + List grantedAuthorities = Stream.of("a", "v", "technical", "c") + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); - RoleAuthorizationAuthorityMapper roleAuthorizationAuthorityMapper = - new RoleAuthorizationAuthorityMapper(); - provider.setGrantedAuthoritiesMapper(roleAuthorizationAuthorityMapper); + Collection mappedAuthorities = this.roleAuthorizationAuthorityMapper + .mapAuthorities(grantedAuthorities); + + assertThat(mappedAuthorities).hasSize(1); + List authorities = mappedAuthorities.stream() + .map(grantedAuthority -> grantedAuthority.getAuthority()).toList(); + assertThat(authorities).containsAll(Authority.TECHNICAL.getAuthorities()); + + } - Authentication result = provider.authenticate(token); + @Test + public void mapAuthorities_Should_returnEmptyCollection_When_authorityIsEmpty() { + Collection mappedAuthorities = this.roleAuthorizationAuthorityMapper + .mapAuthorities(emptyList()); + + assertThat(mappedAuthorities).isEmpty(); + } + + @Test + public void mapAuthorities_Should_returnEmptyCollection_When_authoritiesAreNotProvided() { + List grantedAuthorities = Stream.of("a", "v", "b", "c") + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); - Set expectedGrantendAuthorities = new HashSet<>(); - roles.forEach(roleName -> { - expectedGrantendAuthorities.addAll(Authority - .getAuthoritiesByUserRole(Role.getRoleByName(roleName).get()).stream() - .map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); - }); + Collection mappedAuthorities = this.roleAuthorizationAuthorityMapper + .mapAuthorities(grantedAuthorities); - assertThat(expectedGrantendAuthorities, containsInAnyOrder(result.getAuthorities().toArray())); + assertThat(mappedAuthorities).isEmpty(); } } diff --git a/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java index 3bd7488..4ce444f 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/AccessTokenTenantResolverTest.java @@ -4,36 +4,54 @@ import static org.mockito.Mockito.when; import com.google.common.collect.Maps; +import jakarta.servlet.http.HttpServletRequest; +import java.time.Instant; +import java.time.temporal.TemporalUnit; import java.util.HashMap; +import java.util.Map; import java.util.Optional; -import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; @ExtendWith(MockitoExtension.class) class AccessTokenTenantResolverTest { + + @InjectMocks + AccessTokenTenantResolver accessTokenTenantResolver; + + @Mock + SecurityContext mockSecurityContext; + + @Mock + Authentication mockAuthentication; + @Mock HttpServletRequest authenticatedRequest; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - KeycloakAuthenticationToken token; + @AfterEach + public void tearDown() { + SecurityContextHolder.clearContext(); + } - @InjectMocks - AccessTokenTenantResolver accessTokenTenantResolver; + private void givenUserIsAuthenticated() { + SecurityContextHolder.setContext(mockSecurityContext); + when(mockSecurityContext.getAuthentication()).thenReturn(mockAuthentication); + Jwt jwt = buildJwt(); + when(mockAuthentication.getPrincipal()).thenReturn(jwt); + } @Test void resolve_Should_ResolveTenantId_When_TenantIdInAccessTokenClaim() { // given - when(authenticatedRequest.getUserPrincipal()).thenReturn(token); - - HashMap claimMap = givenClaimMapContainingTenantId(1); - when(token.getAccount().getKeycloakSecurityContext().getToken().getOtherClaims()) - .thenReturn(claimMap); + givenUserIsAuthenticated(); // when Optional resolvedTenantId = accessTokenTenantResolver.resolve(authenticatedRequest); @@ -42,6 +60,14 @@ void resolve_Should_ResolveTenantId_When_TenantIdInAccessTokenClaim() { assertThat(resolvedTenantId).isEqualTo(Optional.of(1L)); } + private Jwt buildJwt() { + Map headers = new HashMap<>(); + headers.put("alg", "HS256"); // Signature algorithm + headers.put("typ", "JWT"); // Token type + return new Jwt( + "token", Instant.now(), Instant.now().plusMillis(100), headers, givenClaimMapContainingTenantId(1)); + } + private HashMap givenClaimMapContainingTenantId(Integer tenantId) { HashMap claimMap = Maps.newHashMap(); claimMap.put("tenantId", tenantId); diff --git a/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java index d5b2761..7cc794f 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/TechnicalUserTenantResolverTest.java @@ -4,26 +4,36 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import jakarta.servlet.http.HttpServletRequest; -import org.assertj.core.util.Sets; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken.Access; import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; @ExtendWith(MockitoExtension.class) class TechnicalUserTenantResolverTest { + public static final long TECHNICAL_CONTEXT = 0L; @Mock HttpServletRequest authenticatedRequest; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - KeycloakAuthenticationToken token; + JwtAuthenticationToken token; @Mock(answer = Answers.RETURNS_DEEP_STUBS) AccessToken accessToken; @@ -31,16 +41,25 @@ class TechnicalUserTenantResolverTest { @Mock Access access; + @Mock + SecurityContext mockSecurityContext; + + @Mock + Authentication mockAuthentication; + @InjectMocks TechnicalUserTenantResolver technicalUserTenantResolver; + @AfterEach + public void tearDown() { + SecurityContextHolder.clearContext(); + } + @Test void resolve_should_ResolveTechnicalTenantId_ForTechnicalUserRole() { // given - when(authenticatedRequest.getUserPrincipal()).thenReturn(token); - when(token.getAccount() - .getKeycloakSecurityContext().getToken()).thenReturn(accessToken); - when(accessToken.getRealmAccess().getRoles()).thenReturn(Sets.newLinkedHashSet("technical")); + givenUserIsAuthenticated(); + when(mockAuthentication.getPrincipal()).thenReturn(buildJwtWithRealmRole("technical")); var resolved = technicalUserTenantResolver.resolve(authenticatedRequest); // then assertThat(resolved).contains(TECHNICAL_CONTEXT); @@ -49,12 +68,31 @@ void resolve_should_ResolveTechnicalTenantId_ForTechnicalUserRole() { @Test void resolve_should_NotResolveTenantId_When_NonTechnicalUserRole() { // given - when(authenticatedRequest.getUserPrincipal()).thenReturn(token); - when(token.getAccount() - .getKeycloakSecurityContext().getToken()).thenReturn(accessToken); - when(accessToken.getRealmAccess().getRoles()).thenReturn(Sets.newLinkedHashSet("another-role")); + givenUserIsAuthenticated(); + when(mockAuthentication.getPrincipal()).thenReturn(buildJwtWithRealmRole("another-role")); var resolved = technicalUserTenantResolver.resolve(authenticatedRequest); // then assertThat(resolved).isEmpty(); } + + private void givenUserIsAuthenticated() { + SecurityContextHolder.setContext(mockSecurityContext); + when(mockSecurityContext.getAuthentication()).thenReturn(mockAuthentication); + } + + private Jwt buildJwtWithRealmRole(String realmRole) { + Map headers = new HashMap<>(); + headers.put("alg", "HS256"); // Signature algorithm + headers.put("typ", "JWT"); // Token type + return new Jwt( + "token", Instant.now(), Instant.now(), headers, givenClaimMapContainingRole(realmRole)); + } + + private HashMap givenClaimMapContainingRole(String realmRole) { + HashMap claimMap = Maps.newHashMap(); + var realmAccess = Maps.newHashMap(); + realmAccess.put("roles", Lists.newArrayList(realmRole)); + claimMap.put("realm_access", realmAccess); + return claimMap; + } } \ No newline at end of file diff --git a/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java b/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java index eaa1a30..1052f72 100644 --- a/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java +++ b/src/test/java/de/caritas/cob/messageservice/api/tenant/TenantResolverServiceTest.java @@ -8,12 +8,12 @@ import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; @ExtendWith(MockitoExtension.class) class TenantResolverServiceTest { @@ -33,7 +33,7 @@ class TenantResolverServiceTest { HttpServletRequest nonAuthenticatedRequest; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - KeycloakAuthenticationToken token; + JwtAuthenticationToken token; @InjectMocks TenantResolverService tenantResolverService;