From 4aeced19338b992d4f99cdda6c17d8ff5eacf502 Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 23 Jan 2025 16:56:35 +0100 Subject: [PATCH] chore(dataplane): integrate dataplane plugin for Device fixes AM-4707 related-to AM-4569 --- .../common/service/DeviceGatewayService.java | 21 +-- .../impl/CredentialGatewayServiceImpl.java | 8 +- .../impl/DeviceGatewayServiceImpl.java | 79 +++++++++++ .../common/spring/CommonConfiguration.java | 11 +- .../common/utils/RiskAssessmentService.java | 8 +- .../service/CredentialGatewayServiceTest.java | 13 +- .../service/DeviceGatewayServiceTest.java | 96 +++++-------- .../utils/RiskAssessmentServiceTest.java | 10 +- .../am/gateway/handler/root/RootProvider.java | 6 +- .../endpoint/mfa/MFAChallengeEndpoint.java | 10 +- .../DeviceIdentifierHandler.java | 13 +- .../mfa/MFAChallengeEndpointTest.java | 4 +- .../DeviceIdentifierHandlerTest.java | 24 ++-- .../handler/oauth2/OAuth2Provider.java | 4 +- .../handler/risk/RiskAssessmentHandler.java | 8 +- .../risk/RiskAssessmentHandlerTest.java | 8 +- .../environments/domains/DeviceResource.java | 12 +- .../environments/domains/DevicesResource.java | 11 +- .../management/api/JerseySpringTest.java | 10 +- .../api/resources/DevicesResourceTest.java | 3 +- .../dataplane/DeviceManagementService.java | 37 +++++ .../impl/DeviceManagementServiceImpl.java | 72 +++------- .../DeviceManagementServiceTest.java | 132 ++++++++++++++++++ 23 files changed, 395 insertions(+), 205 deletions(-) rename gravitee-am-service/src/main/java/io/gravitee/am/service/DeviceService.java => gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayService.java (63%) create mode 100644 gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/DeviceGatewayServiceImpl.java rename gravitee-am-service/src/test/java/io/gravitee/am/service/DeviceServiceTest.java => gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayServiceTest.java (67%) create mode 100644 gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/DeviceManagementService.java rename gravitee-am-service/src/main/java/io/gravitee/am/service/impl/DeviceServiceImpl.java => gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/impl/DeviceManagementServiceImpl.java (52%) create mode 100644 gravitee-am-management-api/gravitee-am-management-api-service/src/test/java/io/gravitee/am/management/service/dataplane/DeviceManagementServiceTest.java diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/DeviceService.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayService.java similarity index 63% rename from gravitee-am-service/src/main/java/io/gravitee/am/service/DeviceService.java rename to gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayService.java index 15a42fb217e..bd9798304fe 100644 --- a/gravitee-am-service/src/main/java/io/gravitee/am/service/DeviceService.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayService.java @@ -13,27 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.am.service; -import io.gravitee.am.identityprovider.api.User; +package io.gravitee.am.gateway.handler.common.service; + import io.gravitee.am.model.Device; +import io.gravitee.am.model.Domain; import io.gravitee.am.model.UserId; -import io.reactivex.rxjava3.core.Completable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Single; -/** - * @author Rémi SULTAN (remi.sultan at graviteesource.com) - * @author GraviteeSource Team - */ -public interface DeviceService { - - Flowable findByDomainAndUser(String domain, UserId user); - - Single deviceExists(String domain, String client, UserId user, String rememberDevice, String deviceId); +public interface DeviceGatewayService { - Single create(String domain, String client, UserId user, String rememberDevice, String type, Long timeExpirationMs, String deviceId); + Flowable findByDomainAndUser(Domain domain, UserId user); - Completable delete(String domain, UserId user, String id, User authenticatedUser); + Single deviceExists(Domain domain, String client, UserId user, String rememberDevice, String deviceId); + Single create(Domain domain, String client, UserId user, String rememberDevice, String type, Long timeExpirationMs, String deviceId); } diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/CredentialGatewayServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/CredentialGatewayServiceImpl.java index 8af923f1447..db6d2d402a0 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/CredentialGatewayServiceImpl.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/CredentialGatewayServiceImpl.java @@ -31,9 +31,8 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Maybe; import io.reactivex.rxjava3.core.Single; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import java.util.Date; import java.util.List; @@ -47,11 +46,10 @@ * @author GraviteeSource Team */ @Slf4j +@AllArgsConstructor public class CredentialGatewayServiceImpl implements CredentialGatewayService { - @Lazy - @Autowired - private DataPlaneRegistry dataPlaneRegistry; + private final DataPlaneRegistry dataPlaneRegistry; //FIXME do we have to keep RefTyp & RefId into the repository signatures ? //FIXME do we have to create a business Rule for the delete/update method to avoid logic duplication between mAPI and GW? diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/DeviceGatewayServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/DeviceGatewayServiceImpl.java new file mode 100644 index 00000000000..18091e12285 --- /dev/null +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/service/impl/DeviceGatewayServiceImpl.java @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.gravitee.am.gateway.handler.common.service.impl; + + +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; +import io.gravitee.am.model.Device; +import io.gravitee.am.model.Domain; +import io.gravitee.am.model.UserId; +import io.gravitee.am.plugins.dataplane.core.DataPlaneRegistry; +import io.gravitee.am.service.exception.TechnicalManagementException; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.Single; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; +import java.util.Optional; + +import static io.gravitee.am.model.ReferenceType.DOMAIN; + +/** + * @author Eric LELEU (eric.leleu at graviteesource.com) + * @author GraviteeSource Team + */ +@Slf4j +@AllArgsConstructor +public class DeviceGatewayServiceImpl implements DeviceGatewayService { + //Ten hours + private static final long DEFAULT_DEVICE_EXPIRATION_TIME_SECONDS = 10L * 60L * 60L; + + private DataPlaneRegistry dataPlaneRegistry; + + @Override + public Flowable findByDomainAndUser(Domain domain, UserId userId) { + return dataPlaneRegistry.getDeviceRepository(domain).findByDomainAndClientAndUser(domain.getId(), userId).onErrorResumeNext(ex -> { + log.error("An error occurs while trying to find Devices by {} {}", domain, userId, ex); + return Flowable.error(new TechnicalManagementException(String.format("An error occurs while trying to find Devices by %s %s", domain, userId), ex)); + }); + } + + @Override + public Single deviceExists(Domain domain, String client, UserId user, String rememberDevice, String deviceId) { + return dataPlaneRegistry.getDeviceRepository(domain).findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(domain.getId(), client, user, rememberDevice, deviceId).isEmpty(); + } + + @Override + public Single create(Domain domain, String client, UserId user, String rememberDevice, String deviceType, Long timeExpirationSeconds, String deviceId) { + long expiresAt = System.currentTimeMillis() + Optional.ofNullable(timeExpirationSeconds) + .filter(time -> time > 0L) + .orElse(DEFAULT_DEVICE_EXPIRATION_TIME_SECONDS) * 1000L; + return dataPlaneRegistry.getDeviceRepository(domain).create(new Device() + .setReferenceType(DOMAIN) + .setReferenceId(domain.getId()) + .setClient(client) + .setUserId(user) + .setDeviceIdentifierId(rememberDevice) + .setType(deviceType) + .setDeviceId(deviceId) + .setCreatedAt(new Date()) + .setExpiresAt(new Date(expiresAt)) + ); + } +} diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/spring/CommonConfiguration.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/spring/CommonConfiguration.java index e7a72e2bd9b..7014e63df4d 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/spring/CommonConfiguration.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/spring/CommonConfiguration.java @@ -56,8 +56,10 @@ import io.gravitee.am.gateway.handler.common.ruleengine.RuleEngine; import io.gravitee.am.gateway.handler.common.ruleengine.SpELRuleEngine; import io.gravitee.am.gateway.handler.common.service.CredentialGatewayService; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.gateway.handler.common.service.impl.CredentialGatewayServiceImpl; +import io.gravitee.am.gateway.handler.common.service.impl.DeviceGatewayServiceImpl; import io.gravitee.am.gateway.handler.common.service.impl.UserActivityGatewayServiceImpl; import io.gravitee.am.gateway.handler.common.spring.web.WebConfiguration; import io.gravitee.am.gateway.handler.common.user.GatewayUserService; @@ -340,12 +342,17 @@ public UserEnhancer facadeManagerUserEnhancer(GroupManager groupManager, RoleMan } @Bean - public CredentialGatewayService credentialGatewayService() { - return new CredentialGatewayServiceImpl(); + public CredentialGatewayService credentialGatewayService(DataPlaneRegistry dataPlaneRegistry) { + return new CredentialGatewayServiceImpl(dataPlaneRegistry); } @Bean public UserActivityGatewayService userActivityGatewayService(UserActivityConfiguration configuration, DataPlaneRegistry dataPlaneRegistry) { return new UserActivityGatewayServiceImpl(configuration, dataPlaneRegistry); } + + @Bean + public DeviceGatewayService deviceGatewayService(DataPlaneRegistry dataPlaneRegistry) { + return new DeviceGatewayServiceImpl(dataPlaneRegistry); + } } diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentService.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentService.java index 3ec953f9a1f..4f9219e9524 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentService.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/main/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentService.java @@ -19,12 +19,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.gravitee.am.common.jwt.Claims; import io.gravitee.am.gateway.handler.common.auth.AuthenticationDetails; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.model.Device; import io.gravitee.am.model.Domain; import io.gravitee.am.model.User; import io.gravitee.am.model.UserActivity; -import io.gravitee.am.service.DeviceService; import io.gravitee.risk.assessment.api.assessment.AssessmentMessage; import io.gravitee.risk.assessment.api.assessment.AssessmentMessageResult; import io.gravitee.risk.assessment.api.assessment.AssessmentResult; @@ -62,14 +62,14 @@ public class RiskAssessmentService { private static final Logger logger = LoggerFactory.getLogger(RiskAssessmentService.class); private static final String RISK_ASSESSMENT_SERVICE = "service:risk-assessment"; - private final DeviceService deviceService; + private final DeviceGatewayService deviceService; private final UserActivityGatewayService userActivityService; private final ObjectMapper objectMapper; private final EventBus eventBus; private final RiskAssessmentSettings riskAssessmentSettings; public RiskAssessmentService( - DeviceService deviceService, + DeviceGatewayService deviceService, UserActivityGatewayService userActivityService, ObjectMapper objectMapper, RiskAssessmentSettings riskAssessmentSettings, @@ -105,7 +105,7 @@ private Function> buildDeviceAssess var deviceAssessment = ofNullable(riskAssessmentSettings.getDeviceAssessment()).orElse(new AssessmentSettings()); if (deviceAssessment.isEnabled()) { logger.debug("Decorating assessment with devices"); - return deviceService.findByDomainAndUser(domain.getId(), user.getFullId()) + return deviceService.findByDomainAndUser(domain, user.getFullId()) .map(Device::getDeviceId) .toList().flatMap(deviceIds -> { assessmentMessage.getData().setDevices(new Devices() diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/CredentialGatewayServiceTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/CredentialGatewayServiceTest.java index 527e07feb9b..ed908b19b4f 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/CredentialGatewayServiceTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/CredentialGatewayServiceTest.java @@ -42,7 +42,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; @@ -65,18 +64,17 @@ @RunWith(MockitoJUnitRunner.class) public class CredentialGatewayServiceTest { - @InjectMocks - private CredentialGatewayService credentialService = new CredentialGatewayServiceImpl(); - - @Mock - private CredentialRepository credentialRepository; - @Mock private DataPlaneRegistry dataPlaneRegistry; @Mock private UserRepository userRepository; + @Mock + private CredentialRepository credentialRepository; + + private CredentialGatewayService credentialService; + private final static String DOMAIN = "domain1"; private Domain domain = new Domain(); @@ -86,6 +84,7 @@ public void init() { this.domain.setId(DOMAIN); when(dataPlaneRegistry.getUserRepository(any())).thenReturn(userRepository); when(dataPlaneRegistry.getCredentialRepository(any())).thenReturn(credentialRepository); + credentialService = new CredentialGatewayServiceImpl(dataPlaneRegistry); } @Test diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/DeviceServiceTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayServiceTest.java similarity index 67% rename from gravitee-am-service/src/test/java/io/gravitee/am/service/DeviceServiceTest.java rename to gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayServiceTest.java index 0c4fd6eb292..0feaa58a569 100644 --- a/gravitee-am-service/src/test/java/io/gravitee/am/service/DeviceServiceTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/service/DeviceGatewayServiceTest.java @@ -13,27 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.am.service; -import io.gravitee.am.identityprovider.api.DefaultUser; +package io.gravitee.am.gateway.handler.common.service; + + +/** + * @author Eric LELEU (eric.leleu at graviteesource.com) + * @author GraviteeSource Team + */ + +import io.gravitee.am.dataplane.api.repository.DeviceRepository; +import io.gravitee.am.gateway.handler.common.service.impl.DeviceGatewayServiceImpl; import io.gravitee.am.model.Device; +import io.gravitee.am.model.Domain; import io.gravitee.am.model.ReferenceType; import io.gravitee.am.model.UserId; -import io.gravitee.am.repository.management.api.DeviceRepository; -import io.gravitee.am.service.exception.DeviceNotFoundException; -import io.gravitee.am.service.impl.DeviceServiceImpl; -import io.reactivex.rxjava3.core.Completable; +import io.gravitee.am.plugins.dataplane.core.DataPlaneRegistry; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Maybe; import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.subscribers.TestSubscriber; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.Date; import java.util.List; @@ -43,29 +49,25 @@ import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -/** - * @author Rémi SULTAN (remi.sultan at graviteesource.com) - * @author GraviteeSource Team - */ -@RunWith(MockitoJUnitRunner.class) -public class DeviceServiceTest { - - @InjectMocks - private DeviceService deviceService = new DeviceServiceImpl(); +@ExtendWith(MockitoExtension.class) +public class DeviceGatewayServiceTest { @Mock private DeviceRepository deviceRepository; @Mock - private AuditService auditService; + private DataPlaneRegistry dataPlaneRegistry; + + @InjectMocks + private DeviceGatewayService deviceService = new DeviceGatewayServiceImpl(dataPlaneRegistry); - private final static String DOMAIN = "domain1"; - private final static String DOMAIN2 = "domain2"; + private final static Domain DOMAIN = new Domain("domain1"); + private final static Domain DOMAIN2 = new Domain("domain2"); private final static String CLIENT = "client1"; private final static UserId USER = UserId.internal("user1"); private final static String DEVICE_IDENTIFIER = "rememberDevice1"; @@ -78,13 +80,12 @@ public class DeviceServiceTest { private Device device1; private Device device2; - @Before + @BeforeEach public void setUp() { - doNothing().when(auditService).report(any()); createdAt = new Date(); expiresAt = new Date(System.currentTimeMillis() + 7200); device1 = new Device().setId(UUID.randomUUID().toString()).setReferenceType(ReferenceType.DOMAIN) - .setReferenceId(DOMAIN) + .setReferenceId(DOMAIN.getId()) .setClient(CLIENT) .setUserId(USER) .setDeviceIdentifierId(DEVICE_IDENTIFIER) @@ -94,7 +95,7 @@ public void setUp() { .setExpiresAt(expiresAt); device2 = new Device().setId(UUID.randomUUID().toString()).setReferenceType(ReferenceType.DOMAIN) - .setReferenceId(DOMAIN) + .setReferenceId(DOMAIN.getId()) .setClient(CLIENT) .setUserId(USER) .setDeviceIdentifierId(REMEMBER_DEVICE2) @@ -102,30 +103,32 @@ public void setUp() { .setDeviceId(DEVICE2) .setCreatedAt(createdAt) .setExpiresAt(expiresAt); + + when(dataPlaneRegistry.getDeviceRepository(any())).thenReturn(deviceRepository); } @Test public void mustFindByDomainAndApplicationAndUser() { - doReturn(Flowable.fromIterable(List.of(device1, device2))).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN, USER); + doReturn(Flowable.fromIterable(List.of(device1, device2))).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN.getId(), USER); final TestSubscriber testFull = deviceService.findByDomainAndUser(DOMAIN, USER).test(); testFull.awaitDone(10, TimeUnit.SECONDS); testFull.assertNoErrors(); testFull.assertValueCount(2); - verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN, USER); + verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN.getId(), USER); } @Test public void mustFindNothing() { - doReturn(Flowable.fromIterable(List.of())).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN2, USER); + doReturn(Flowable.fromIterable(List.of())).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN2.getId(), USER); final TestSubscriber testEmpty = deviceService.findByDomainAndUser(DOMAIN2, USER).test(); testEmpty.awaitDone(10, TimeUnit.SECONDS); testEmpty.assertNoErrors(); testEmpty.assertValueCount(0); - verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN2, USER); + verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN2.getId(), USER); } @Test @@ -140,8 +143,8 @@ public void mustCreate_Device() { @Test public void mustReturn_SingleBoolean() { - doReturn(Maybe.empty()).when(deviceRepository).findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(DOMAIN, CLIENT, USER, DEVICE_IDENTIFIER, DEVICE1); - doReturn(Maybe.just(device2)).when(deviceRepository).findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(DOMAIN2, CLIENT, USER, DEVICE_IDENTIFIER, DEVICE1); + doReturn(Maybe.empty()).when(deviceRepository).findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(DOMAIN.getId(), CLIENT, USER, DEVICE_IDENTIFIER, DEVICE1); + doReturn(Maybe.just(device2)).when(deviceRepository).findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(DOMAIN2.getId(), CLIENT, USER, DEVICE_IDENTIFIER, DEVICE1); final TestObserver testObserverEmpty = deviceService.deviceExists(DOMAIN, CLIENT, USER, DEVICE_IDENTIFIER, DEVICE1).test(); testObserverEmpty.awaitDone(10, TimeUnit.SECONDS); @@ -153,31 +156,4 @@ public void mustReturn_SingleBoolean() { testObserver.assertNoErrors(); testObserver.assertValue(FALSE::equals); } - - @Test - public void mustNotDelete_deviceDoesNotExist() { - doReturn(Maybe.empty()).when(deviceRepository).findById(device1.getId()); - - deviceService.delete(DOMAIN, USER, device1.getId(), new DefaultUser()) - .test() - .assertFailure(DeviceNotFoundException.class); - } - - @Test - public void mustNotDelete_deviceDoesNotBelongToContext() { - doReturn(Maybe.just(device1)).when(deviceRepository).findById(device1.getId()); - - deviceService.delete(DOMAIN2, USER, device1.getId(), new DefaultUser()) - .test() - .assertFailure(DeviceNotFoundException.class); - } - - @Test - public void mustDeleteDevice() { - doReturn(Maybe.just(device1)).when(deviceRepository).findById(device1.getId()); - doReturn(Completable.complete()).when(deviceRepository).delete(device1.getId()); - - deviceService.delete(DOMAIN, USER, device1.getId(), new DefaultUser()) - .test().assertNoErrors(); - } } diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentServiceTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentServiceTest.java index 0865921778c..ef091813908 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentServiceTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/utils/RiskAssessmentServiceTest.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.gravitee.am.gateway.handler.common.auth.AuthenticationDetails; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.identityprovider.api.Authentication; import io.gravitee.am.identityprovider.api.AuthenticationContext; @@ -26,7 +27,6 @@ import io.gravitee.am.model.Domain; import io.gravitee.am.model.User; import io.gravitee.am.model.UserActivity; -import io.gravitee.am.service.DeviceService; import io.gravitee.risk.assessment.api.assessment.AssessmentMessageResult; import io.gravitee.risk.assessment.api.assessment.AssessmentResult; import io.gravitee.risk.assessment.api.assessment.settings.AssessmentSettings; @@ -73,7 +73,7 @@ public class RiskAssessmentServiceTest { @Mock private Vertx vertx; @Mock - private DeviceService deviceService; + private DeviceGatewayService deviceService; @Mock private UserActivityGatewayService userActivityService; @Mock @@ -149,7 +149,7 @@ public void must_test_computeRiskAssessment() throws JsonProcessingException { //device doReturn(Flowable.just(new Device().setDeviceId("1"), new Device().setDeviceId("2"))) - .when(deviceService).findByDomainAndUser(anyString(), any()); + .when(deviceService).findByDomainAndUser(any(), any()); //geo doReturn(Flowable.just( new UserActivity().setLatitude(50.34D).setLongitude(3.025D).setCreatedAt(new Date()), @@ -184,7 +184,7 @@ public void must_test_return_nothing_due_to_event_bus_error() throws JsonProcess //device doReturn(Flowable.just(new Device().setDeviceId("1"), new Device().setDeviceId("2"))) - .when(deviceService).findByDomainAndUser(anyString(), any()); + .when(deviceService).findByDomainAndUser(any(), any()); //geo doReturn(Flowable.just( new UserActivity().setLatitude(50.34D).setLongitude(3.025D).setCreatedAt(new Date()), @@ -219,7 +219,7 @@ public void must_test_return_nothing_due_to_message_parse_error() throws JsonPro //device doReturn(Flowable.just(new Device().setDeviceId("1"), new Device().setDeviceId("2"))) - .when(deviceService).findByDomainAndUser(anyString(), any()); + .when(deviceService).findByDomainAndUser(any(), any()); //geo doReturn(Flowable.just( new UserActivity().setLatitude(50.34D).setLongitude(3.025D).setCreatedAt(new Date()), diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/RootProvider.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/RootProvider.java index 2382b343800..dd3742dc0de 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/RootProvider.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/RootProvider.java @@ -30,6 +30,7 @@ import io.gravitee.am.gateway.handler.common.password.PasswordPolicyManager; import io.gravitee.am.gateway.handler.common.ruleengine.RuleEngine; import io.gravitee.am.gateway.handler.common.service.CredentialGatewayService; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.gateway.handler.common.vertx.web.auth.provider.UserAuthProvider; import io.gravitee.am.gateway.handler.common.vertx.web.endpoint.ErrorEndpoint; @@ -130,7 +131,6 @@ import io.gravitee.am.monitoring.provider.GatewayMetricProvider; import io.gravitee.am.service.AuditService; import io.gravitee.am.service.AuthenticationFlowContextService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.FactorService; import io.gravitee.am.service.LoginAttemptService; import io.gravitee.am.service.PasswordService; @@ -276,7 +276,7 @@ public class RootProvider extends AbstractProtocolProvider { private DeviceIdentifierManager deviceIdentifierManager; @Autowired - private DeviceService deviceService; + private DeviceGatewayService deviceService; @Autowired private WebClient webClient; @@ -362,7 +362,7 @@ protected void doStart() throws Exception { Handler geoIpHandler = new GeoIpHandler(userActivityService, vertx.eventBus()); Handler loginAttemptHandler = new LoginAttemptHandler(domain, identityProviderManager, loginAttemptService, userActivityService); Handler rememberDeviceSettingsHandler = new RememberDeviceSettingsHandler(); - Handler deviceIdentifierHandler = new DeviceIdentifierHandler(deviceService); + Handler deviceIdentifierHandler = new DeviceIdentifierHandler(domain, deviceService); Handler userActivityHandler = new UserActivityHandler(userActivityService, domain); Handler localeHandler = new LocaleHandler(messageResolver); Handler loginPostWebAuthnHandler = new LoginPostWebAuthnHandler(webAuthnCookieService); diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpoint.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpoint.java index 55fceaad5d7..e4542a9612c 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpoint.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpoint.java @@ -24,6 +24,7 @@ import io.gravitee.am.gateway.handler.common.email.EmailService; import io.gravitee.am.gateway.handler.common.factor.FactorManager; import io.gravitee.am.gateway.handler.common.service.CredentialGatewayService; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.utils.HashUtil; import io.gravitee.am.gateway.handler.common.vertx.core.http.VertxHttpServerRequest; import io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderRequest; @@ -48,7 +49,6 @@ import io.gravitee.am.model.oidc.Client; import io.gravitee.am.model.safe.EnrolledFactorProperties; import io.gravitee.am.service.AuditService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.RateLimiterService; import io.gravitee.am.service.VerifyAttemptService; import io.gravitee.am.service.exception.FactorNotFoundException; @@ -136,7 +136,7 @@ public class MFAChallengeEndpoint extends MFAEndpoint { private final FactorManager factorManager; private final UserService userService; private final ApplicationContext applicationContext; - private final DeviceService deviceService; + private final DeviceGatewayService deviceService; private final Domain domain; private final CredentialGatewayService credentialService; private final RateLimiterService rateLimiterService; @@ -147,7 +147,7 @@ public class MFAChallengeEndpoint extends MFAEndpoint { public MFAChallengeEndpoint(FactorManager factorManager, UserService userService, TemplateEngine engine, - DeviceService deviceService, + DeviceGatewayService deviceService, ApplicationContext applicationContext, Domain domain, CredentialGatewayService credentialService, @@ -677,14 +677,14 @@ private void saveDeviceAndRedirect(RoutingContext routingContext, Client client, routingContext.session().put(DEVICE_ALREADY_EXISTS_KEY, false); doRedirect(routingContext.response(), redirectUrl); } else { - this.deviceService.deviceExists(client.getDomain(), client.getClientId(), userId, rememberDeviceId, deviceId).flatMapMaybe(isEmpty -> { + this.deviceService.deviceExists(domain, client.getClientId(), userId, rememberDeviceId, deviceId).flatMapMaybe(isEmpty -> { if (Boolean.FALSE.equals(isEmpty)) { routingContext.session().put(DEVICE_ALREADY_EXISTS_KEY, true); return Maybe.empty(); } var deviceType = routingContext.session().get(DEVICE_TYPE); return this.deviceService.create( - client.getDomain(), + domain, client.getClientId(), userId, rememberDeviceId, diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandler.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandler.java index 7bcfdfa7f85..d89f0e0c092 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandler.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandler.java @@ -16,14 +16,16 @@ package io.gravitee.am.gateway.handler.root.resources.handler.rememberdevice; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; +import io.gravitee.am.model.Domain; import io.gravitee.am.model.MFASettings; import io.gravitee.am.model.RememberDeviceSettings; import io.gravitee.am.model.User; import io.gravitee.am.model.oidc.Client; -import io.gravitee.am.service.DeviceService; import io.reactivex.rxjava3.core.Maybe; import io.vertx.core.Handler; import io.vertx.rxjava3.ext.web.RoutingContext; +import lombok.AllArgsConstructor; import static com.google.common.base.Strings.isNullOrEmpty; import static io.gravitee.am.common.utils.ConstantKeys.CLIENT_CONTEXT_KEY; @@ -38,13 +40,11 @@ * @author Rémi SULTAN (remi.sultan at graviteesource.com) * @author GraviteeSource Team */ +@AllArgsConstructor public class DeviceIdentifierHandler implements Handler { - private final DeviceService deviceService; - - public DeviceIdentifierHandler(DeviceService deviceService) { - this.deviceService = deviceService; - } + private final Domain domain; + private final DeviceGatewayService deviceService; @Override public void handle(RoutingContext routingContext) { @@ -65,7 +65,6 @@ private RememberDeviceSettings getRememberDeviceSettings(Client client) { } private void checkIfDeviceExists(RoutingContext routingContext, Client client, User user, RememberDeviceSettings rememberDeviceSettings) { - var domain = client.getDomain(); var deviceId = routingContext.request().getParam(DEVICE_ID); var deviceIdentifierId = rememberDeviceSettings.getDeviceIdentifierId(); if (isNullOrEmpty(deviceId)) { diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpointTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpointTest.java index 24aaae86f5f..a45fb6b7f0d 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpointTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/endpoint/mfa/MFAChallengeEndpointTest.java @@ -22,6 +22,7 @@ import io.gravitee.am.gateway.handler.common.email.EmailService; import io.gravitee.am.gateway.handler.common.factor.FactorManager; import io.gravitee.am.gateway.handler.common.service.CredentialGatewayService; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.vertx.RxWebTestBase; import io.gravitee.am.gateway.handler.root.service.user.UserService; import io.gravitee.am.model.ApplicationFactorSettings; @@ -37,7 +38,6 @@ import io.gravitee.am.model.oidc.Client; import io.gravitee.am.service.AuditService; import io.gravitee.am.service.AuthenticationFlowContextService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.RateLimiterService; import io.gravitee.am.service.VerifyAttemptService; import io.gravitee.am.service.exception.MFAValidationAttemptException; @@ -91,7 +91,7 @@ public class MFAChallengeEndpointTest extends RxWebTestBase { @Mock private ApplicationContext applicationContext; @Mock - private DeviceService deviceService; + private DeviceGatewayService deviceService; @Mock private Domain domain; @Mock diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandlerTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandlerTest.java index 712c663e07f..02093b782fd 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandlerTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/test/java/io/gravitee/am/gateway/handler/root/resources/handler/rememberdevice/DeviceIdentifierHandlerTest.java @@ -16,13 +16,13 @@ package io.gravitee.am.gateway.handler.root.resources.handler.rememberdevice; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.root.resources.handler.dummies.SpyRoutingContext; import io.gravitee.am.model.Domain; import io.gravitee.am.model.MFASettings; import io.gravitee.am.model.RememberDeviceSettings; import io.gravitee.am.model.User; import io.gravitee.am.model.oidc.Client; -import io.gravitee.am.service.DeviceService; import io.reactivex.rxjava3.core.Single; import io.vertx.core.http.HttpMethod; import org.junit.Assert; @@ -53,7 +53,7 @@ @RunWith(MockitoJUnitRunner.class) public class DeviceIdentifierHandlerTest { - private DeviceService deviceService; + private DeviceGatewayService deviceService; private SpyRoutingContext spyRoutingContext; private Client client; @@ -69,8 +69,8 @@ public void setUp() { client.setDomain(domain.getId()); client.setId(UUID.randomUUID().toString()); client.setClientId(UUID.randomUUID().toString()); - deviceService = spy(DeviceService.class); - handler = new DeviceIdentifierHandler(deviceService); + deviceService = spy(DeviceGatewayService.class); + handler = new DeviceIdentifierHandler(domain, deviceService); userId = UUID.randomUUID().toString(); deviceIdentifierId = UUID.randomUUID().toString(); @@ -85,7 +85,7 @@ public void mustDoNext_nullClient() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -100,7 +100,7 @@ public void mustDoNext_nullUser() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -116,7 +116,7 @@ public void mustDoNext_nullMfa() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -132,7 +132,7 @@ public void mustDoNext_nullRememberDeviceSettings() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -149,7 +149,7 @@ public void mustDoNext_RememberDeviceSettingsIsNotActive() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -170,7 +170,7 @@ public void mustDoNext_deviceIdIsEmpty() { Assert.assertNull(spyRoutingContext.get(DEVICE_ALREADY_EXISTS_KEY)); verify(spyRoutingContext, times(1)).next(); - verify(deviceService, times(0)).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + verify(deviceService, times(0)).deviceExists(any(), anyString(), any(), anyString(), anyString()); } @Test @@ -188,7 +188,7 @@ public void mustDoNext_DeviceAlreadyExists() { spyRoutingContext.put(USER_CONTEXT_KEY, user); spyRoutingContext.putParam(DEVICE_ID, "deviceId"); - doReturn(Single.just(false)).when(deviceService).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + doReturn(Single.just(false)).when(deviceService).deviceExists(any(), anyString(), any(), anyString(), anyString()); handler.handle(spyRoutingContext); Assert.assertTrue(spyRoutingContext.session().get(DEVICE_ALREADY_EXISTS_KEY)); @@ -211,7 +211,7 @@ public void mustDoNext_DeviceNotExists() { spyRoutingContext.putParam(DEVICE_ID, "deviceId2"); spyRoutingContext.putParam(DEVICE_TYPE, "deviceType"); - doReturn(Single.just(true)).when(deviceService).deviceExists(anyString(), anyString(), any(), anyString(), anyString()); + doReturn(Single.just(true)).when(deviceService).deviceExists(any(), anyString(), any(), anyString(), anyString()); handler.handle(spyRoutingContext); Assert.assertFalse(spyRoutingContext.session().get(DEVICE_ALREADY_EXISTS_KEY)); diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/OAuth2Provider.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/OAuth2Provider.java index 016aa5154ee..f68342b5bd2 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/OAuth2Provider.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/OAuth2Provider.java @@ -21,6 +21,7 @@ import io.gravitee.am.gateway.handler.api.AbstractProtocolProvider; import io.gravitee.am.gateway.handler.common.client.ClientSyncService; import io.gravitee.am.gateway.handler.common.jwt.JWTService; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.gateway.handler.common.vertx.web.endpoint.ErrorEndpoint; import io.gravitee.am.gateway.handler.common.vertx.web.handler.AuthenticationFlowContextHandler; @@ -75,7 +76,6 @@ import io.gravitee.am.model.Domain; import io.gravitee.am.service.AuditService; import io.gravitee.am.service.AuthenticationFlowContextService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.i18n.GraviteeMessageResolver; import io.gravitee.am.service.impl.ApplicationClientSecretService; import io.gravitee.common.http.MediaType; @@ -192,7 +192,7 @@ public class OAuth2Provider extends AbstractProtocolProvider { private ScopeManager scopeManager; @Autowired - private DeviceService deviceService; + private DeviceGatewayService deviceService; @Autowired private UserActivityGatewayService userActivityService; diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/resources/handler/risk/RiskAssessmentHandler.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/resources/handler/risk/RiskAssessmentHandler.java index a5df76ff1b8..ea55d759869 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/resources/handler/risk/RiskAssessmentHandler.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oauth2/resources/handler/risk/RiskAssessmentHandler.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.gravitee.am.common.utils.ConstantKeys; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User; import io.gravitee.am.model.Device; @@ -29,7 +30,6 @@ import io.gravitee.am.model.UserActivity.Type; import io.gravitee.am.model.UserId; import io.gravitee.am.model.oidc.Client; -import io.gravitee.am.service.DeviceService; import io.gravitee.risk.assessment.api.assessment.AssessmentMessage; import io.gravitee.risk.assessment.api.assessment.AssessmentMessageResult; import io.gravitee.risk.assessment.api.assessment.AssessmentResult; @@ -66,14 +66,14 @@ public class RiskAssessmentHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(RiskAssessmentHandler.class); private static final String RISK_ASSESSMENT_SERVICE = "service:risk-assessment"; - private final DeviceService deviceService; + private final DeviceGatewayService deviceService; private final ObjectMapper objectMapper; private final EventBus eventBus; private final UserActivityGatewayService userActivityService; private final Domain domain; public RiskAssessmentHandler( - DeviceService deviceService, + DeviceGatewayService deviceService, UserActivityGatewayService userActivityService, EventBus eventBus, ObjectMapper objectMapper, @@ -126,7 +126,7 @@ private Function> buildDeviceMessag if (deviceAssessment.isEnabled() && rememberDevice.isActive()) { logger.debug("Decorating assessment with devices"); - return deviceService.findByDomainAndUser(client.getDomain(), userId) + return deviceService.findByDomainAndUser(domain, userId) .map(Device::getDeviceId) .toList().flatMap(deviceIds -> { assessmentMessage.getData().setDevices(new Devices() diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/risk/RiskAssessmentHandlerTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/risk/RiskAssessmentHandlerTest.java index 1c0c1e94f9d..f0844dde9a1 100644 --- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/risk/RiskAssessmentHandlerTest.java +++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/risk/RiskAssessmentHandlerTest.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.gravitee.am.common.utils.ConstantKeys; +import io.gravitee.am.gateway.handler.common.service.DeviceGatewayService; import io.gravitee.am.gateway.handler.common.service.UserActivityGatewayService; import io.gravitee.am.gateway.handler.dummies.SpyRoutingContext; import io.gravitee.am.gateway.handler.oauth2.resources.handler.risk.RiskAssessmentHandler; @@ -29,7 +30,6 @@ import io.gravitee.am.model.User; import io.gravitee.am.model.UserActivity; import io.gravitee.am.model.oidc.Client; -import io.gravitee.am.service.DeviceService; import io.gravitee.risk.assessment.api.assessment.Assessment; import io.gravitee.risk.assessment.api.assessment.AssessmentMessageResult; import io.gravitee.risk.assessment.api.assessment.AssessmentResult; @@ -73,7 +73,7 @@ public class RiskAssessmentHandlerTest { @Mock - private DeviceService deviceService; + private DeviceGatewayService deviceService; @Mock private UserActivityGatewayService userActivityService; @@ -170,7 +170,7 @@ public void must_next_only_client_and_user_with_risk_assessment_enabled_with_rem when(eventBus.request(anyString(), anyString())).thenReturn(Single.just(mockMessage)); doReturn(Flowable.just(new Device().setDeviceId("1"), new Device().setDeviceId("2"))) - .when(deviceService).findByDomainAndUser(anyString(), any()); + .when(deviceService).findByDomainAndUser(any(), any()); handler.handle(routingContext); @@ -196,7 +196,7 @@ public void must_do_nothing_when_error_with_deviceService() throws JsonProcessin routingContext.session().put(DEVICE_ID, "deviceId"); doReturn(Flowable.error(new IllegalArgumentException())) - .when(deviceService).findByDomainAndUser(anyString(), any()); + .when(deviceService).findByDomainAndUser(any(), any()); handler.handle(routingContext); diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DeviceResource.java b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DeviceResource.java index b0e67b549dd..95ad2e06739 100644 --- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DeviceResource.java +++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DeviceResource.java @@ -17,10 +17,10 @@ import io.gravitee.am.management.handlers.management.api.resources.AbstractResource; import io.gravitee.am.management.service.DomainService; +import io.gravitee.am.management.service.dataplane.DeviceManagementService; import io.gravitee.am.model.Acl; import io.gravitee.am.model.UserId; import io.gravitee.am.model.permissions.Permission; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.exception.DomainNotFoundException; import io.reactivex.rxjava3.core.Maybe; import io.swagger.v3.oas.annotations.Operation; @@ -43,7 +43,7 @@ public class DeviceResource extends AbstractResource { private DomainService domainService; @Autowired - private DeviceService deviceService; + private DeviceManagementService deviceService; @DELETE @Operation(summary = "Delete a device", @@ -56,15 +56,15 @@ public class DeviceResource extends AbstractResource { public void delete( @PathParam("organizationId") String organizationId, @PathParam("environmentId") String environmentId, - @PathParam("domain") String domain, + @PathParam("domain") String domainId, @PathParam("user") String user, @PathParam("device") String device, @Suspended final AsyncResponse response) { final io.gravitee.am.identityprovider.api.User authenticatedUser = getAuthenticatedUser(); - checkAnyPermission(organizationId, environmentId, domain, Permission.DOMAIN_USER_DEVICE, Acl.DELETE) - .andThen(domainService.findById(domain).switchIfEmpty(Maybe.error(new DomainNotFoundException(domain)))) - .flatMapCompletable(__ -> deviceService.delete(domain, UserId.internal(user), device, authenticatedUser)) + checkAnyPermission(organizationId, environmentId, domainId, Permission.DOMAIN_USER_DEVICE, Acl.DELETE) + .andThen(domainService.findById(domainId).switchIfEmpty(Maybe.error(new DomainNotFoundException(domainId)))) + .flatMapCompletable(domain -> deviceService.delete(domain, UserId.internal(user), device, authenticatedUser)) .subscribe(() -> response.resume(Response.noContent().build()), response::resume); } diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DevicesResource.java b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DevicesResource.java index 020028d094f..4f49230010d 100644 --- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DevicesResource.java +++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/resources/organizations/environments/domains/DevicesResource.java @@ -18,10 +18,10 @@ import io.gravitee.am.management.handlers.management.api.resources.AbstractResource; import io.gravitee.am.management.service.DomainService; import io.gravitee.am.management.service.ManagementUserService; +import io.gravitee.am.management.service.dataplane.DeviceManagementService; import io.gravitee.am.model.Acl; import io.gravitee.am.model.User; import io.gravitee.am.model.permissions.Permission; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.exception.DomainNotFoundException; import io.gravitee.am.service.exception.UserNotFoundException; import io.gravitee.common.http.MediaType; @@ -57,7 +57,7 @@ public class DevicesResource extends AbstractResource { private DomainService domainService; @Autowired - private DeviceService deviceService; + private DeviceManagementService deviceService; @Autowired private ManagementUserService userService; @@ -83,9 +83,10 @@ public void list( checkAnyPermission(organizationId, environmentId, domainId, Permission.DOMAIN_USER_DEVICE, Acl.LIST) .andThen(domainService.findById(domainId) .switchIfEmpty(Maybe.error(new DomainNotFoundException(domainId))) - .flatMap(domain -> this.userService.findById(domain, userId)) - .switchIfEmpty(Maybe.error(new UserNotFoundException(userId))) - .flatMapSingle(user -> this.deviceService.findByDomainAndUser(domainId, user.getFullId()).toList())) + .flatMap(domain -> + this.userService.findById(domain, userId) + .switchIfEmpty(Maybe.error(new UserNotFoundException(userId))) + .flatMapSingle(user -> this.deviceService.findByDomainAndUser(domain, user.getFullId()).toList()))) .subscribe(response::resume, response::resume); } diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/JerseySpringTest.java b/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/JerseySpringTest.java index e0902d16832..3691f72115e 100644 --- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/JerseySpringTest.java +++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/JerseySpringTest.java @@ -33,6 +33,7 @@ import io.gravitee.am.management.service.CertificateServiceProxy; import io.gravitee.am.management.service.DefaultIdentityProviderService; import io.gravitee.am.management.service.DeviceIdentifierPluginService; +import io.gravitee.am.management.service.DomainGroupService; import io.gravitee.am.management.service.DomainService; import io.gravitee.am.management.service.EmailManager; import io.gravitee.am.management.service.ExtensionGrantPluginService; @@ -48,6 +49,7 @@ import io.gravitee.am.management.service.ResourcePluginService; import io.gravitee.am.management.service.TagService; import io.gravitee.am.management.service.dataplane.CredentialManagementService; +import io.gravitee.am.management.service.dataplane.DeviceManagementService; import io.gravitee.am.management.service.dataplane.UserActivityManagementService; import io.gravitee.am.management.service.permissions.PermissionAcls; import io.gravitee.am.plugins.handlers.api.core.AmPluginManager; @@ -58,7 +60,6 @@ import io.gravitee.am.service.CertificatePluginService; import io.gravitee.am.service.CertificateService; import io.gravitee.am.service.DeviceIdentifierService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.EmailTemplateService; import io.gravitee.am.service.EntrypointService; import io.gravitee.am.service.EnvironmentService; @@ -66,7 +67,6 @@ import io.gravitee.am.service.FactorService; import io.gravitee.am.service.FlowService; import io.gravitee.am.service.FormService; -import io.gravitee.am.management.service.DomainGroupService; import io.gravitee.am.service.IdentityProviderService; import io.gravitee.am.service.MembershipService; import io.gravitee.am.service.OrganizationGroupService; @@ -260,7 +260,7 @@ public abstract class JerseySpringTest { protected DeviceIdentifierService deviceIdentifierService; @Autowired - protected DeviceService deviceService; + protected DeviceManagementService deviceService; @Autowired protected AuthenticationDeviceNotifierPluginService authDeviceNotifierPluginService; @@ -577,8 +577,8 @@ public DeviceIdentifierService deviceIdentifierService() { } @Bean - public DeviceService deviceService() { - return mock(DeviceService.class); + public DeviceManagementService deviceService() { + return mock(DeviceManagementService.class); } @Bean diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/resources/DevicesResourceTest.java b/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/resources/DevicesResourceTest.java index 9a3e8a258e6..46eaa449456 100644 --- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/resources/DevicesResourceTest.java +++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/test/java/io/gravitee/am/management/handlers/management/api/resources/DevicesResourceTest.java @@ -29,6 +29,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; /** @@ -54,7 +55,7 @@ public void shouldGetDevices() { doReturn(Flowable.just( List.of(device, device2, device3) - )).when(deviceService).findByDomainAndUser(Mockito.eq(domainId), Mockito.any()); + )).when(deviceService).findByDomainAndUser(any(), Mockito.any()); doReturn(Maybe.just(user)).when(userService).findById(mockDomain, userId); final Response response = target("domains") diff --git a/gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/DeviceManagementService.java b/gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/DeviceManagementService.java new file mode 100644 index 00000000000..51887c4ae3b --- /dev/null +++ b/gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/DeviceManagementService.java @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.gravitee.am.management.service.dataplane; + + +import io.gravitee.am.identityprovider.api.User; +import io.gravitee.am.model.Device; +import io.gravitee.am.model.Domain; +import io.gravitee.am.model.UserId; +import io.reactivex.rxjava3.core.Completable; +import io.reactivex.rxjava3.core.Flowable; + +/** + * @author Eric LELEU (eric.leleu at graviteesource.com) + * @author GraviteeSource Team + */ +public interface DeviceManagementService { + + Flowable findByDomainAndUser(Domain domain, UserId user); + + Completable delete(Domain domain, UserId user, String id, User authenticatedUser); + +} diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/DeviceServiceImpl.java b/gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/impl/DeviceManagementServiceImpl.java similarity index 52% rename from gravitee-am-service/src/main/java/io/gravitee/am/service/impl/DeviceServiceImpl.java rename to gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/impl/DeviceManagementServiceImpl.java index 628eb8b2779..cfbf9a2ddac 100644 --- a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/DeviceServiceImpl.java +++ b/gravitee-am-management-api/gravitee-am-management-api-service/src/main/java/io/gravitee/am/management/service/dataplane/impl/DeviceManagementServiceImpl.java @@ -14,16 +14,17 @@ * limitations under the License. */ -package io.gravitee.am.service.impl; +package io.gravitee.am.management.service.dataplane.impl; + import io.gravitee.am.common.audit.EventType; import io.gravitee.am.identityprovider.api.User; +import io.gravitee.am.management.service.dataplane.DeviceManagementService; import io.gravitee.am.model.Device; -import io.gravitee.am.model.Reference; +import io.gravitee.am.model.Domain; import io.gravitee.am.model.UserId; -import io.gravitee.am.repository.management.api.DeviceRepository; +import io.gravitee.am.plugins.dataplane.core.DataPlaneRegistry; import io.gravitee.am.service.AuditService; -import io.gravitee.am.service.DeviceService; import io.gravitee.am.service.exception.DeviceNotFoundException; import io.gravitee.am.service.exception.TechnicalManagementException; import io.gravitee.am.service.reporter.builder.AuditBuilder; @@ -31,74 +32,41 @@ import io.reactivex.rxjava3.core.Completable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Maybe; -import io.reactivex.rxjava3.core.Single; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import java.util.Date; -import java.util.Optional; - import static io.gravitee.am.model.ReferenceType.DOMAIN; /** - * @author Rémi SULTAN (remi.sultan at graviteesource.com) + * @author Eric LELEU (eric.leleu at graviteesource.com) * @author GraviteeSource Team */ @Component -public class DeviceServiceImpl implements DeviceService { - - private static final Logger LOGGER = LoggerFactory.getLogger(DeviceServiceImpl.class); - //Ten hours - private static final long DEFAULT_DEVICE_EXPIRATION_TIME_SECONDS = 10L * 60L * 60L; +@Slf4j +public class DeviceManagementServiceImpl implements DeviceManagementService { - @Lazy @Autowired - private DeviceRepository deviceRepository; + private DataPlaneRegistry dataPlaneRegistry; @Autowired private AuditService auditService; - + @Override - public Flowable findByDomainAndUser(String domain, UserId userId) { - return deviceRepository.findByDomainAndClientAndUser(domain, userId).onErrorResumeNext(ex -> { - LOGGER.error("An error occurs while trying to find Devices by {} {}", domain, userId, ex); + public Flowable findByDomainAndUser(Domain domain, UserId userId) { + return dataPlaneRegistry.getDeviceRepository(domain).findByDomainAndClientAndUser(domain.getId(), userId).onErrorResumeNext(ex -> { + log.error("An error occurs while trying to find Devices by {} {}", domain, userId, ex); return Flowable.error(new TechnicalManagementException(String.format("An error occurs while trying to find Devices by %s %s", domain, userId), ex)); }); } @Override - public Single deviceExists(String domain, String client, UserId user, String rememberDevice, String deviceId) { - return deviceRepository.findByDomainAndClientAndUserAndDeviceIdentifierAndDeviceId(domain, client, user, rememberDevice, deviceId).isEmpty(); - } - - @Override - public Single create(String domain, String client, UserId user, String rememberDevice, String deviceType, Long timeExpirationSeconds, String deviceId) { - long expiresAt = System.currentTimeMillis() + Optional.ofNullable(timeExpirationSeconds) - .filter(time -> time > 0L) - .orElse(DEFAULT_DEVICE_EXPIRATION_TIME_SECONDS) * 1000L; - return deviceRepository.create(new Device() - .setReferenceType(DOMAIN) - .setReferenceId(domain) - .setClient(client) - .setUserId(user) - .setDeviceIdentifierId(rememberDevice) - .setType(deviceType) - .setDeviceId(deviceId) - .setCreatedAt(new Date()) - .setExpiresAt(new Date(expiresAt)) - ); - } - - @Override - public Completable delete(String domain, UserId user, String deviceId, User principal) { - return deviceRepository.findById(deviceId) + public Completable delete(Domain domain, UserId user, String deviceId, User principal) { + return dataPlaneRegistry.getDeviceRepository(domain).findById(deviceId) .switchIfEmpty(Maybe.error(new DeviceNotFoundException(deviceId))) .flatMap(device -> { if (DOMAIN.equals(device.getReferenceType()) && device.getReferenceId().equals(domain) && device.getUserId().id().equals(user.id())) { - return deviceRepository.delete(deviceId).andThen(Maybe.just(device)); + return dataPlaneRegistry.getDeviceRepository(domain).delete(deviceId).andThen(Maybe.just(device)); } else { return Maybe.error(new DeviceNotFoundException(deviceId)); } @@ -106,12 +74,12 @@ public Completable delete(String domain, UserId user, String deviceId, User prin if (ex instanceof DeviceNotFoundException) { return Maybe.error(ex); } - LOGGER.error("An error occurs while trying to delete factor: {}", deviceId, ex); + log.error("An error occurs while trying to delete factor: {}", deviceId, ex); return Maybe.error(new TechnicalManagementException( String.format("An error occurs while trying to delete factor: %s", deviceId), ex)); }) - .doOnSuccess(device -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).principal(principal).type(EventType.DEVICE_DELETED).reference(Reference.domain(domain)).deletedDevice(device))) - .doOnError(throwable -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).principal(principal).type(EventType.DEVICE_DELETED).reference(Reference.domain(domain)).throwable(throwable))) + .doOnSuccess(device -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).principal(principal).type(EventType.DEVICE_DELETED).reference(domain.asReference()).deletedDevice(device))) + .doOnError(throwable -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).principal(principal).type(EventType.DEVICE_DELETED).reference(domain.asReference()).throwable(throwable))) .ignoreElement(); } } diff --git a/gravitee-am-management-api/gravitee-am-management-api-service/src/test/java/io/gravitee/am/management/service/dataplane/DeviceManagementServiceTest.java b/gravitee-am-management-api/gravitee-am-management-api-service/src/test/java/io/gravitee/am/management/service/dataplane/DeviceManagementServiceTest.java new file mode 100644 index 00000000000..1c9ef781220 --- /dev/null +++ b/gravitee-am-management-api/gravitee-am-management-api-service/src/test/java/io/gravitee/am/management/service/dataplane/DeviceManagementServiceTest.java @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.gravitee.am.management.service.dataplane; + + +import io.gravitee.am.dataplane.api.repository.DeviceRepository; +import io.gravitee.am.management.service.dataplane.impl.DeviceManagementServiceImpl; +import io.gravitee.am.model.Device; +import io.gravitee.am.model.Domain; +import io.gravitee.am.model.ReferenceType; +import io.gravitee.am.model.UserId; +import io.gravitee.am.plugins.dataplane.core.DataPlaneRegistry; +import io.gravitee.am.service.AuditService; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author Eric LELEU (eric.leleu at graviteesource.com) + * @author GraviteeSource Team + */ +@ExtendWith(MockitoExtension.class) +public class DeviceManagementServiceTest { + + @Mock + private DeviceRepository deviceRepository; + + @Mock + private DataPlaneRegistry dataPlaneRegistry; + + @Mock + private AuditService auditService; + + @InjectMocks + private DeviceManagementService deviceService = new DeviceManagementServiceImpl(); + + private final static Domain DOMAIN = new Domain("domain1"); + private final static Domain DOMAIN2 = new Domain("domain2"); + private final static String CLIENT = "client1"; + private final static UserId USER = UserId.internal("user1"); + private final static String DEVICE_IDENTIFIER = "rememberDevice1"; + private final static String REMEMBER_DEVICE2 = "rememberDevice2"; + private final static String TYPE = "type"; + private final static String DEVICE1 = "device1"; + private final static String DEVICE2 = "device2"; + private Date expiresAt; + private Date createdAt; + private Device device1; + private Device device2; + + @BeforeEach + public void setUp() { + createdAt = new Date(); + expiresAt = new Date(System.currentTimeMillis() + 7200); + device1 = new Device().setId(UUID.randomUUID().toString()).setReferenceType(ReferenceType.DOMAIN) + .setReferenceId(DOMAIN.getId()) + .setClient(CLIENT) + .setUserId(USER) + .setDeviceIdentifierId(DEVICE_IDENTIFIER) + .setType(TYPE) + .setDeviceId(DEVICE1) + .setCreatedAt(createdAt) + .setExpiresAt(expiresAt); + + device2 = new Device().setId(UUID.randomUUID().toString()).setReferenceType(ReferenceType.DOMAIN) + .setReferenceId(DOMAIN.getId()) + .setClient(CLIENT) + .setUserId(USER) + .setDeviceIdentifierId(REMEMBER_DEVICE2) + .setType(TYPE) + .setDeviceId(DEVICE2) + .setCreatedAt(createdAt) + .setExpiresAt(expiresAt); + + when(dataPlaneRegistry.getDeviceRepository(any())).thenReturn(deviceRepository); + } + + @Test + public void mustFindByDomainAndApplicationAndUser() { + doReturn(Flowable.fromIterable(List.of(device1, device2))).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN.getId(), USER); + + final TestSubscriber testFull = deviceService.findByDomainAndUser(DOMAIN, USER).test(); + testFull.awaitDone(10, TimeUnit.SECONDS); + testFull.assertNoErrors(); + testFull.assertValueCount(2); + + verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN.getId(), USER); + } + + @Test + public void mustFindNothing() { + doReturn(Flowable.fromIterable(List.of())).when(deviceRepository).findByDomainAndClientAndUser(DOMAIN2.getId(), USER); + + final TestSubscriber testEmpty = deviceService.findByDomainAndUser(DOMAIN2, USER).test(); + testEmpty.awaitDone(10, TimeUnit.SECONDS); + testEmpty.assertNoErrors(); + testEmpty.assertValueCount(0); + + verify(deviceRepository, times(1)).findByDomainAndClientAndUser(DOMAIN2.getId(), USER); + } + +}