From 968cad0e3ce387d873389a016de54f70760fc266 Mon Sep 17 00:00:00 2001 From: theghost5800 Date: Thu, 29 May 2025 12:40:21 +0300 Subject: [PATCH] Use user guid for token cache JIRA:LMCROSSITXSADEPLOY-3207 --- .../multiapps/controller/core/Constants.java | 4 + .../multiapps/controller/core/Messages.java | 2 +- .../cf/CloudControllerClientProvider.java | 51 ++++---- .../core/cf/OAuthClientExtended.java | 14 +-- .../core/security/token/TokenService.java | 78 ++++++++---- .../core/security/token/TokenServiceTest.java | 31 +++-- .../persistence/dto/AccessTokenDto.java | 16 ++- .../persistence/model/AccessToken.java | 7 +- .../model/PersistenceMetadata.java | 1 + .../persistence/query/AccessTokenQuery.java | 2 + .../query/impl/AccessTokenQueryImpl.java | 19 ++- .../services/AccessTokenService.java | 5 +- .../db-changelog-1.192.0-persistence.xml | 19 +++ .../persistence/db/changelog/db-changelog.xml | 44 +++---- .../controller/process/Messages.java | 1 + .../steps/CollectSystemParametersStep.java | 26 ++-- .../process/steps/CreateOrUpdateAppStep.java | 21 ++-- .../steps/DeleteApplicationRoutesStep.java | 28 ++--- .../process/steps/DetectDeployedMtaStep.java | 24 ++-- ...eApplicationServiceBindingActionsStep.java | 53 +++++---- .../steps/PollExecuteAppStatusExecution.java | 14 +-- .../steps/PollExecuteTaskStatusExecution.java | 8 +- .../steps/PollStageAppStatusExecution.java | 10 +- .../steps/PollStartAppStatusExecution.java | 19 ++- .../process/steps/ProcessContext.java | 9 +- .../controller/process/steps/StepsUtil.java | 25 ++-- .../process/steps/UpdateSubscribersStep.java | 36 +++--- .../process/util/ClientReleaser.java | 5 +- .../util/OperationInFinalStateHandler.java | 34 +++--- .../process/variables/Variables.java | 112 +++++++++++------- .../controller/process/deploy-app.bpmn | 3 + .../process/process-batches-sequentially.bpmn | 1 + .../BuildCloudUndeployModelStepTest.java | 24 ++-- .../PollExecuteAppStatusExecutionTest.java | 77 ++++++------ ...viceInProgressOperationsExecutionTest.java | 27 ++--- .../steps/PollServiceOperationsStepTest.java | 4 +- .../PollStageAppStatusExecutionTest.java | 17 +-- .../PollStartAppStatusExecutionTest.java | 28 +++-- .../steps/RestartSubscribersStepTest.java | 31 +++-- .../process/steps/SyncFlowableStepTest.java | 13 +- .../steps/UpdateSubscribersStepTest.java | 59 ++++----- .../process/util/ApplicationStagerTest.java | 41 ++++--- ...cationWaitAfterStopVariableGetterTest.java | 16 +-- .../process/util/ServiceRemoverTest.java | 46 +++---- .../web/api/impl/MtasApiServiceImpl.java | 13 +- .../api/impl/OperationsApiServiceImpl.java | 18 +-- .../ConfigurationEntriesResource.java | 22 ++-- .../web/security/AuthorizationChecker.java | 14 +-- .../web/util/BasicTokenGenerator.java | 23 ++-- .../web/util/OauthTokenGenerator.java | 17 ++- .../controller/web/util/TokenGenerator.java | 12 +- .../controller/web/util/TokenReuser.java | 39 ++---- .../web/api/impl/MtasApiServiceImplTest.java | 15 ++- .../impl/OperationsApiServiceImplTest.java | 72 ++++++----- .../security/AuthorizationCheckerTest.java | 103 ++++++++-------- .../web/util/BasicTokenGeneratorTest.java | 26 ++-- .../controller/web/util/TokenReuserTest.java | 46 +------ 57 files changed, 812 insertions(+), 713 deletions(-) create mode 100644 multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.192.0-persistence.xml diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Constants.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Constants.java index d4ce6a27cd..e3588eb994 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Constants.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Constants.java @@ -30,6 +30,10 @@ public class Constants { public static final String B3_TRACE_ID_HEADER = "X-B3-TraceId"; public static final String B3_SPAN_ID_HEADER = "X-B3-SpanId"; + public static final int TOKEN_SERVICE_DELETION_CORE_POOL_SIZE = 1; + public static final int TOKEN_SERVICE_DELETION_MAXIMUM_POOL_SIZE = 3; + public static final int TOKEN_SERVICE_DELETION_KEEP_ALIVE_THREAD_IN_SECONDS = 30; + protected Constants() { } } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java index 74eb64d9d1..26c576bf35 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java @@ -6,7 +6,7 @@ public final class Messages { // Exception messages - public static final String NO_VALID_TOKEN_FOUND = "No valid access token was found for user \"{0}\""; + public static final String NO_VALID_TOKEN_FOUND = "No valid access token was found for user guid \"{0}\""; public static final String CANT_CREATE_CLIENT = "Could not create client"; public static final String CANT_CREATE_CLIENT_FOR_SPACE_ID = "Could not create client in space with guid \"{0}\""; public static final String UNAUTHORISED_OPERATION_ORG_SPACE = "Not authorized to perform operation \"{0}\" in organization \"{1}\" and space \"{2}\""; diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerClientProvider.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerClientProvider.java index 1ed5016841..add0e4b52c 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerClientProvider.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerClientProvider.java @@ -2,18 +2,16 @@ import java.time.Duration; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudOperationException; import jakarta.inject.Inject; import jakarta.inject.Named; - import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.controller.core.Messages; import org.cloudfoundry.multiapps.controller.core.model.CachedMap; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.springframework.beans.factory.DisposableBean; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudOperationException; - @Named public class CloudControllerClientProvider implements DisposableBean { @@ -25,59 +23,64 @@ public class CloudControllerClientProvider implements DisposableBean { private final CachedMap clients = new CachedMap<>(Duration.ofMinutes(30)); /** - * Returns a client for the specified user name and space id by either getting it from the clients cache or creating a new one. + * Returns a client for the specified user guid and space id by either getting it from the clients cache or creating a new one. * - * @param userName the user name associated with the client + * @param userName the username associated with the client + * @param userGuid the userGuid associated with the client * @param spaceGuid the space guid associated with the client * @param correlationId of the process which is used to tag HTTP requests * @return a CF client for the specified access token, organization, and space */ - public CloudControllerClient getControllerClient(String userName, String spaceGuid, String correlationId) { + public CloudControllerClient getControllerClient(String userName, String userGuid, String spaceGuid, String correlationId) { try { - return getClientFromCache(userName, spaceGuid, correlationId); + return getClientFromCache(userName, userGuid, spaceGuid, correlationId); } catch (CloudOperationException e) { throw new SLException(e, Messages.CANT_CREATE_CLIENT_FOR_SPACE_ID, spaceGuid); } } /** - * Returns a client for the specified user name and space id by either getting it from the clients cache or creating a new one. + * Returns a client for the specified username and space id by either getting it from the clients cache or creating a new one. * - * @param userName the user name associated with the client + * @param userName the username associated with the client + * @param userGuid the userGuid associated with the client * @param spaceGuid the space guid associated with the client * @return a CF client for the specified access token, organization, and space */ - public CloudControllerClient getControllerClientWithNoCorrelation(String userName, String spaceGuid) { + public CloudControllerClient getControllerClientWithNoCorrelation(String userName, String userGuid, String spaceGuid) { try { - return getClientFromCacheWithNoCorrelation(userName, spaceGuid); + return getClientFromCacheWithNoCorrelation(userName, userGuid, spaceGuid); } catch (CloudOperationException e) { throw new SLException(e, Messages.CANT_CREATE_CLIENT_FOR_SPACE_ID, spaceGuid); } } /** - * Releases the client for the specified user name and space id by removing it from the clients cache. + * Releases the client for the specified username and space id by removing it from the clients cache. * - * @param userName the user name associated with the client + * @param userGuid the userGuid associated with the client * @param spaceGuid the space id associated with the client */ - public void releaseClient(String userName, String spaceGuid) { - clients.remove(getKey(spaceGuid, userName)); + public void releaseClient(String userGuid, String spaceGuid) { + clients.remove(getKey(spaceGuid, userGuid, null)); } - private CloudControllerClient getClientFromCacheWithNoCorrelation(String userName, String spaceId) { - String key = getKey(spaceId, userName); - return clients.computeIfAbsent(key, - () -> clientFactory.createClient(tokenService.getToken(userName), spaceId, null)); + private CloudControllerClient getClientFromCacheWithNoCorrelation(String userName, String userGuid, String spaceId) { + String key = getKey(spaceId, userGuid, userName); + return clients.computeIfAbsent(key, () -> clientFactory.createClient(tokenService.getToken(userName, userGuid), spaceId, null)); } - private CloudControllerClient getClientFromCache(String userName, String spaceId, String correlationId) { - String key = getKey(spaceId, userName); + private CloudControllerClient getClientFromCache(String userName, String userGuid, String spaceId, String correlationId) { + String key = getKey(spaceId, userGuid, userName); return clients.computeIfAbsent(key, - () -> clientFactory.createClient(tokenService.getToken(userName), spaceId, correlationId)); + () -> clientFactory.createClient(tokenService.getToken(userName, userGuid), spaceId, correlationId)); } - private String getKey(String spaceGuid, String username) { + private String getKey(String spaceGuid, String userGuid, String username) { + if (userGuid != null) { + return spaceGuid + "|" + userGuid; + } + // TODO: Remove this branch when userGuid is guaranteed to be non-null(In the next release after introduction of userGuid) return spaceGuid + "|" + username; } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java index 2d04cfa0c0..3a48eecb9d 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java @@ -5,6 +5,8 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; import org.cloudfoundry.multiapps.controller.core.Messages; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; @@ -12,9 +14,6 @@ import org.slf4j.LoggerFactory; import org.springframework.web.reactive.function.client.WebClient; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; -import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; - public class OAuthClientExtended extends OAuthClient { private static final Logger LOGGER = LoggerFactory.getLogger(OAuthClientExtended.class); @@ -35,10 +34,11 @@ public OAuth2AccessTokenWithAdditionalInfo getToken() { .isBefore(Instant.now() .plus(120, ChronoUnit.SECONDS))) { TokenProperties tokenProperties = TokenProperties.fromToken(token); - token = tokenService.getToken(tokenProperties.getUserName()); - LOGGER.info(MessageFormat.format(Messages.RETRIEVED_TOKEN_FOR_USER_WITH_GUID_0_WITH_EXPIRATION_TIME_1, tokenProperties.getUserId(), - token.getOAuth2AccessToken() - .getExpiresAt())); + token = tokenService.getToken(tokenProperties.getUserName(), tokenProperties.getUserId()); + LOGGER.info( + MessageFormat.format(Messages.RETRIEVED_TOKEN_FOR_USER_WITH_GUID_0_WITH_EXPIRATION_TIME_1, tokenProperties.getUserId(), + token.getOAuth2AccessToken() + .getExpiresAt())); } return token; } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenService.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenService.java index 8fa00683f3..1e2ad82b96 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenService.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenService.java @@ -12,6 +12,11 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; +import org.cloudfoundry.multiapps.controller.core.Constants; import org.cloudfoundry.multiapps.controller.core.Messages; import org.cloudfoundry.multiapps.controller.core.model.CachedMap; import org.cloudfoundry.multiapps.controller.core.security.token.parsers.TokenParserChain; @@ -20,11 +25,6 @@ import org.cloudfoundry.multiapps.controller.persistence.services.AccessTokenService; import org.springframework.beans.factory.DisposableBean; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; - -import jakarta.inject.Inject; -import jakarta.inject.Named; - /** * Provides functionality for persisting, updating and removing tokens from a token store */ @@ -35,11 +35,10 @@ public class TokenService implements DisposableBean { private final TokenParserChain tokenParserChain; private final Duration tokenExpirationTime = Duration.ofMinutes(10); private final CachedMap cachedTokens = new CachedMap<>(tokenExpirationTime); - private final ExecutorService threadPoolForTokensDeletion = new ThreadPoolExecutor(1, - 3, - 30, - TimeUnit.SECONDS, - new LinkedBlockingQueue<>()); + private final ExecutorService threadPoolForTokensDeletion = new ThreadPoolExecutor(Constants.TOKEN_SERVICE_DELETION_CORE_POOL_SIZE, + Constants.TOKEN_SERVICE_DELETION_MAXIMUM_POOL_SIZE, + Constants.TOKEN_SERVICE_DELETION_KEEP_ALIVE_THREAD_IN_SECONDS, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); @Inject public TokenService(AccessTokenService accessTokenService, TokenParserChain tokenParserChain) { @@ -51,21 +50,19 @@ public TokenService(AccessTokenService accessTokenService, TokenParserChain toke * Chooses a token among all tokens for this user in the access token table. * * @param username the username + * @param userGuid the userGuid * @return the latest token, or throw an exception if token is not found */ - public OAuth2AccessTokenWithAdditionalInfo getToken(String username) { - OAuth2AccessTokenWithAdditionalInfo cachedAccessToken = cachedTokens.get(username); - if (shouldUseCachedToken(cachedAccessToken)) { - return cachedAccessToken; - } - List accessTokens = getSortedAccessTokensByUsername(username); - if (accessTokens.isEmpty()) { - throw new IllegalStateException(MessageFormat.format(Messages.NO_VALID_TOKEN_FOUND, username)); + public OAuth2AccessTokenWithAdditionalInfo getToken(String username, String userGuid) { + if (userGuid != null) { + OAuth2AccessTokenWithAdditionalInfo cachedAccessToken = cachedTokens.get(userGuid); + if (shouldUseCachedToken(cachedAccessToken)) { + return cachedAccessToken; + } + return getLatestAccessTokenByUserGuid(userGuid); } - OAuth2AccessTokenWithAdditionalInfo tokenByUser = getLatestToken(accessTokens); - cachedTokens.put(username, tokenByUser); - deleteTokens(accessTokens.subList(1, accessTokens.size())); - return tokenByUser; + // TODO: If no tokens are found for the userGuid, try to find tokens by username. This is temporary and should be removed in the next release. + return getLatestAccessTokenByUsername(username); } private boolean shouldUseCachedToken(OAuth2AccessTokenWithAdditionalInfo cachedAccessToken) { @@ -75,9 +72,42 @@ private boolean shouldUseCachedToken(OAuth2AccessTokenWithAdditionalInfo cachedA .plus(120, ChronoUnit.SECONDS)); } - private List getSortedAccessTokensByUsername(String userName) { + private OAuth2AccessTokenWithAdditionalInfo getLatestAccessTokenByUserGuid(String userGuid) { + List tokensByGuid = getSortedAccessTokensByUserGuid(userGuid); + if (tokensByGuid.isEmpty()) { + throw new IllegalStateException(MessageFormat.format(Messages.NO_VALID_TOKEN_FOUND, userGuid)); + } + OAuth2AccessTokenWithAdditionalInfo latestToken = getLatestToken(tokensByGuid); + addTokenToCache(latestToken, tokensByGuid); + return latestToken; + } + + private List getSortedAccessTokensByUserGuid(String userGuid) { + return accessTokenService.createQuery() + .userGuid(userGuid) + .orderByExpiresAt(OrderDirection.DESCENDING) + .list(); + } + + private void addTokenToCache(OAuth2AccessTokenWithAdditionalInfo token, List accessTokens) { + cachedTokens.put((String) token.getAdditionalInfo() + .get(TokenProperties.USER_ID_KEY), token); + if (accessTokens.size() > 1) { + deleteTokens(accessTokens.subList(1, accessTokens.size())); + } + } + + private OAuth2AccessTokenWithAdditionalInfo getLatestAccessTokenByUsername(String username) { + List tokensByUsername = getSortedAccessTokensByUsername(username); + if (tokensByUsername.isEmpty()) { + throw new IllegalStateException(MessageFormat.format(Messages.NO_VALID_TOKEN_FOUND, username)); + } + return getLatestToken(tokensByUsername); + } + + private List getSortedAccessTokensByUsername(String username) { return accessTokenService.createQuery() - .username(userName) + .username(username) .orderByExpiresAt(OrderDirection.DESCENDING) .list(); } diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenServiceTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenServiceTest.java index db1ff4c4e8..9823f71758 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenServiceTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenServiceTest.java @@ -1,16 +1,15 @@ package org.cloudfoundry.multiapps.controller.core.security.token; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; - import java.time.Instant; import java.time.LocalDateTime; import java.time.Month; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.List; +import java.util.Map; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; import org.cloudfoundry.multiapps.controller.core.security.token.parsers.TokenParserChain; import org.cloudfoundry.multiapps.controller.persistence.OrderDirection; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; @@ -24,7 +23,9 @@ import org.mockito.MockitoAnnotations; import org.springframework.security.oauth2.core.OAuth2AccessToken; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; class TokenServiceTest { @@ -46,8 +47,8 @@ void setUp() throws Exception { void testGetTokenWhenThereAreNoTokensForUser() { AccessTokenQuery accessTokenQuery = Mockito.mock(AccessTokenQuery.class); mockAccessTokenService(accessTokenQuery); - Exception exception = assertThrows(IllegalStateException.class, () -> tokenService.getToken("deploy-service-user")); - assertEquals("No valid access token was found for user \"deploy-service-user\"", exception.getMessage()); + Exception exception = assertThrows(IllegalStateException.class, () -> tokenService.getToken("deploy-service-user", "123")); + assertEquals("No valid access token was found for user guid \"123\"", exception.getMessage()); } @Test @@ -60,9 +61,11 @@ void testGetTokenWhenThereIsOnlyOneTokenInDb() { .thenReturn(List.of(accessToken)); mockAccessTokenService(accessTokenQuery); OAuth2AccessTokenWithAdditionalInfo mockedToken = Mockito.mock(OAuth2AccessTokenWithAdditionalInfo.class); + Mockito.when(mockedToken.getAdditionalInfo()) + .thenReturn(Map.of(TokenProperties.USER_NAME_KEY, "deploy-service-user", TokenProperties.USER_ID_KEY, "123")); Mockito.when(tokenParserChain.parse(any())) .thenReturn(mockedToken); - OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user"); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user", "123"); assertEquals(mockedToken, token); } @@ -71,9 +74,11 @@ void testGetTokenWhenThereIsNewerTokenInDb() { AccessTokenQuery accessTokenQuery = mockAccessTokenQuery(); mockAccessTokenService(accessTokenQuery); OAuth2AccessTokenWithAdditionalInfo mockedToken = Mockito.mock(OAuth2AccessTokenWithAdditionalInfo.class); + Mockito.when(mockedToken.getAdditionalInfo()) + .thenReturn(Map.of(TokenProperties.USER_NAME_KEY, "deploy-service-user", TokenProperties.USER_ID_KEY, "123")); Mockito.when(tokenParserChain.parse(any())) .thenReturn(mockedToken); - OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user"); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user", "123"); assertEquals(mockedToken, token); } @@ -88,10 +93,12 @@ void testGetTokenWhenCachedIsAvailable() { .plus(90, ChronoUnit.SECONDS)); Mockito.when(mockedToken.getOAuth2AccessToken()) .thenReturn(oAuth2AccessToken); + Mockito.when(mockedToken.getAdditionalInfo()) + .thenReturn(Map.of(TokenProperties.USER_NAME_KEY, "deploy-service-user", TokenProperties.USER_ID_KEY, "123")); Mockito.when(tokenParserChain.parse(any())) .thenReturn(mockedToken); - tokenService.getToken("deploy-service-user"); - OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user"); + tokenService.getToken("deploy-service-user", "123"); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken("deploy-service-user", "123"); assertEquals(mockedToken, token); } @@ -117,6 +124,8 @@ private AccessTokenQuery mockAccessTokenQuery() { private void mockAccessTokenService(AccessTokenQuery accessTokenQuery) { Mockito.when(accessTokenService.createQuery()) .thenReturn(accessTokenQuery); + Mockito.when(accessTokenQuery.userGuid(any())) + .thenReturn(accessTokenQuery); Mockito.when(accessTokenQuery.username(any())) .thenReturn(accessTokenQuery); Mockito.when(accessTokenQuery.orderByExpiresAt(OrderDirection.DESCENDING)) diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/dto/AccessTokenDto.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/dto/AccessTokenDto.java index e744a04ea2..ebf710db44 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/dto/AccessTokenDto.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/dto/AccessTokenDto.java @@ -9,7 +9,6 @@ import jakarta.persistence.Id; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; - import org.cloudfoundry.multiapps.controller.persistence.model.PersistenceMetadata; @Entity @@ -25,6 +24,7 @@ private AttributeNames() { public static final String ID = "id"; public static final String VALUE = "value"; public static final String USERNAME = "username"; + public static final String USER_GUID = "userGuid"; public static final String EXPIRES_AT = "expiresAt"; } @@ -40,6 +40,9 @@ private AttributeNames() { @Column(name = PersistenceMetadata.TableColumnNames.ACCESS_TOKEN_USERNAME, nullable = false) private String username; + @Column(name = PersistenceMetadata.TableColumnNames.ACCESS_TOKEN_USER_GUID) + private String userGuid; + @Column(name = PersistenceMetadata.TableColumnNames.ACCESS_TOKEN_EXPIRES_AT, nullable = false) private LocalDateTime expiresAt; @@ -47,10 +50,11 @@ public AccessTokenDto() { // Required by JPA } - public AccessTokenDto(long id, byte[] value, String username, LocalDateTime expiresAt) { + public AccessTokenDto(long id, byte[] value, String username, String userGuid, LocalDateTime expiresAt) { this.id = id; this.value = value; this.username = username; + this.userGuid = userGuid; this.expiresAt = expiresAt; } @@ -80,6 +84,14 @@ public void setUsername(String username) { this.username = username; } + public String getUserGuid() { + return userGuid; + } + + public void setUserGuid(String userGuid) { + this.userGuid = userGuid; + } + public LocalDateTime getExpiresAt() { return expiresAt; } diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/AccessToken.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/AccessToken.java index 9ae31706d8..9196885d57 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/AccessToken.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/AccessToken.java @@ -2,10 +2,10 @@ import java.time.LocalDateTime; -import org.immutables.value.Value; - import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.cloudfoundry.multiapps.common.Nullable; +import org.immutables.value.Value; @Value.Immutable @JsonSerialize(as = ImmutableAccessToken.class) @@ -21,5 +21,8 @@ default long getId() { String getUsername(); + @Nullable + String getUserGuid(); + LocalDateTime getExpiresAt(); } diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/PersistenceMetadata.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/PersistenceMetadata.java index 5138f1a7ff..0a4232c509 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/PersistenceMetadata.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/model/PersistenceMetadata.java @@ -83,6 +83,7 @@ private TableColumnNames() { public static final String ACCESS_TOKEN_VALUE = "value"; public static final String ACCESS_TOKEN_USERNAME = "username"; public static final String ACCESS_TOKEN_EXPIRES_AT = "expires_at"; + public static final String ACCESS_TOKEN_USER_GUID = "user_guid"; public static final String LOCK_OWNER_ID = "id"; public static final String LOCK_OWNER_LOCK_OWNER = "lock_owner"; diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/AccessTokenQuery.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/AccessTokenQuery.java index 964c0dafb0..0381de01ff 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/AccessTokenQuery.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/AccessTokenQuery.java @@ -16,6 +16,8 @@ public interface AccessTokenQuery extends Query { AccessTokenQuery username(String username); + AccessTokenQuery userGuid(String userGuid); + AccessTokenQuery expiresBefore(LocalDateTime expiresAt); AccessTokenQuery orderByExpiresAt(OrderDirection orderDirection); diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/impl/AccessTokenQueryImpl.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/impl/AccessTokenQueryImpl.java index b26681501f..642775ed9d 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/impl/AccessTokenQueryImpl.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/query/impl/AccessTokenQueryImpl.java @@ -8,7 +8,6 @@ import jakarta.persistence.NoResultException; import jakarta.persistence.NonUniqueResultException; import jakarta.persistence.criteria.Expression; - import org.cloudfoundry.multiapps.controller.persistence.OrderDirection; import org.cloudfoundry.multiapps.controller.persistence.dto.AccessTokenDto; import org.cloudfoundry.multiapps.controller.persistence.dto.AccessTokenDto.AttributeNames; @@ -68,6 +67,16 @@ public AccessTokenQuery username(String username) { return this; } + @Override + public AccessTokenQuery userGuid(String userGuid) { + queryCriteria.addRestriction(ImmutableQueryAttributeRestriction.builder() + .attribute(AttributeNames.USER_GUID) + .condition(getCriteriaBuilder()::equal) + .value(userGuid) + .build()); + return this; + } + @Override public AccessTokenQuery expiresBefore(LocalDateTime expiresAt) { queryCriteria.addRestriction(ImmutableQueryAttributeRestriction. builder() @@ -86,15 +95,15 @@ public AccessTokenQuery orderByExpiresAt(OrderDirection orderDirection) { @Override public AccessToken singleResult() throws NoResultException, NonUniqueResultException { - AccessTokenDto accessTokenDto = executeInTransaction(manager -> createQuery(manager, queryCriteria, - AccessTokenDto.class).getSingleResult()); + AccessTokenDto accessTokenDto = executeInTransaction( + manager -> createQuery(manager, queryCriteria, AccessTokenDto.class).getSingleResult()); return accessTokenMapper.fromDto(accessTokenDto); } @Override public List list() { - List accessTokenDtos = executeInTransaction(manager -> createQuery(manager, queryCriteria, - AccessTokenDto.class).getResultList()); + List accessTokenDtos = executeInTransaction( + manager -> createQuery(manager, queryCriteria, AccessTokenDto.class).getResultList()); return accessTokenDtos.stream() .map(accessTokenMapper::fromDto) .collect(Collectors.toList()); diff --git a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AccessTokenService.java b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AccessTokenService.java index 64e452a2e6..80f3eab69c 100644 --- a/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AccessTokenService.java +++ b/multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AccessTokenService.java @@ -3,7 +3,6 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.persistence.EntityManagerFactory; - import org.cloudfoundry.multiapps.common.ConflictException; import org.cloudfoundry.multiapps.common.NotFoundException; import org.cloudfoundry.multiapps.controller.persistence.Messages; @@ -52,13 +51,15 @@ public AccessToken fromDto(AccessTokenDto accessTokenDto) { .id(accessTokenDto.getPrimaryKey()) .value(accessTokenDto.getValue()) .username(accessTokenDto.getUsername()) + .userGuid(accessTokenDto.getUserGuid()) .expiresAt(accessTokenDto.getExpiresAt()) .build(); } @Override public AccessTokenDto toDto(AccessToken accessToken) { - return new AccessTokenDto(accessToken.getId(), accessToken.getValue(), accessToken.getUsername(), accessToken.getExpiresAt()); + return new AccessTokenDto(accessToken.getId(), accessToken.getValue(), accessToken.getUsername(), accessToken.getUserGuid(), + accessToken.getExpiresAt()); } } } diff --git a/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.192.0-persistence.xml b/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.192.0-persistence.xml new file mode 100644 index 0000000000..7d439ea6bf --- /dev/null +++ b/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.192.0-persistence.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog.xml b/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog.xml index ed7f8b369c..08541fc2a2 100644 --- a/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog.xml +++ b/multiapps-controller-persistence/src/main/resources/org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog.xml @@ -1,38 +1,40 @@ - - + + - - + + + file="org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.110.0-persistence.xml"/> - - + file="org/cloudfoundry/multiapps/controller/persistence/db/changelog/db-changelog-1.116.0-persistence.xml"/> + + - - + + - + - + - + - + - + - + - - - + + + + + diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java index 446f78c2c9..e6d31d6ce6 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java @@ -7,6 +7,7 @@ public class Messages { // Exception messages public static final String CANT_DETERMINE_CURRENT_USER = "Cannot determine the current user"; + public static final String CANT_DETERMINE_CURRENT_USER_GUID = "Cannot determine the current user guid"; public static final String CONFLICTING_PROCESS_FOUND = "Conflicting process \"{0}\" found for MTA \"{1}\""; public static final String REQUIRED_PROCESS_VARIABLE_IS_MISSING = "Required process variable \"{0}\" is missing."; public static final String ERROR_RETRIEVING_MTA_MODULE_CONTENT = "Error retrieving content of MTA module \"{0}\""; diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CollectSystemParametersStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CollectSystemParametersStep.java index 7c73c6b9a4..407ecbd606 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CollectSystemParametersStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CollectSystemParametersStep.java @@ -4,9 +4,12 @@ import java.text.MessageFormat; import java.util.function.Supplier; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import com.sap.cloudfoundry.client.facade.CloudOperationException; +import com.sap.cloudfoundry.client.facade.util.AuthorizationEndpointGetter; import jakarta.inject.Inject; import jakarta.inject.Named; - import org.cloudfoundry.multiapps.common.ContentException; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.helpers.CredentialsGenerator; @@ -27,11 +30,6 @@ import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudCredentials; -import com.sap.cloudfoundry.client.facade.CloudOperationException; -import com.sap.cloudfoundry.client.facade.util.AuthorizationEndpointGetter; - @Named("collectSystemParametersStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class CollectSystemParametersStep extends SyncFlowableStep { @@ -124,11 +122,10 @@ private SystemParameters createSystemParameters(ProcessContext context, String d .timestamp(timestamp) .mtaId(descriptor.getId()) .mtaVersion(descriptor.getVersion()) - .hostValidator(new HostValidator(namespace, - applyNamespaceGlobalLevel, - applyNamespaceProcessVariable, - applyNamespaceAsSuffixGlobalLevel, - applyNamespaceAsSuffixProcessVariable)) + .hostValidator( + new HostValidator(namespace, applyNamespaceGlobalLevel, applyNamespaceProcessVariable, + applyNamespaceAsSuffixGlobalLevel, + applyNamespaceAsSuffixProcessVariable)) .build(); } @@ -150,8 +147,8 @@ private void determineIsVersionAccepted(ProcessContext context, DeploymentDescri if (deploymentType == DeploymentType.REDEPLOYMENT) { throw new ContentException(Messages.SAME_VERSION_ALREADY_DEPLOYED); } - throw new IllegalStateException(MessageFormat.format(Messages.VERSION_RULE_DOES_NOT_ALLOW_DEPLOYMENT_TYPE, versionRule, - deploymentType)); + throw new IllegalStateException( + MessageFormat.format(Messages.VERSION_RULE_DOES_NOT_ALLOW_DEPLOYMENT_TYPE, versionRule, deploymentType)); } private DeploymentType getDeploymentType(DeployedMta deployedMta, Version newMtaVersion) { @@ -175,7 +172,8 @@ protected boolean shouldStartApplications(ProcessContext context) { protected AuthorizationEndpointGetter getAuthorizationEndpointGetter(ProcessContext context) { String user = context.getVariable(Variables.USER); - var token = tokenService.getToken(user); + String userGuid = context.getVariable(Variables.USER_GUID); + var token = tokenService.getToken(user, userGuid); var creds = new CloudCredentials(token, true); return new AuthorizationEndpointGetter(webClientFactory.getWebClient(creds)); } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CreateOrUpdateAppStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CreateOrUpdateAppStep.java index 3e5f890588..6aef1f6756 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CreateOrUpdateAppStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/CreateOrUpdateAppStep.java @@ -1,7 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.cloudfoundry.multiapps.controller.process.steps.StepsUtil.disableAutoscaling; - import java.text.MessageFormat; import java.util.HashMap; import java.util.LinkedHashMap; @@ -14,6 +12,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.dto.ApplicationToCreateDto; +import com.sap.cloudfoundry.client.facade.dto.ImmutableApplicationToCreateDto; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; @@ -37,14 +42,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudCredentials; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.dto.ApplicationToCreateDto; -import com.sap.cloudfoundry.client.facade.dto.ImmutableApplicationToCreateDto; - -import jakarta.inject.Inject; -import jakarta.inject.Named; +import static org.cloudfoundry.multiapps.controller.process.steps.StepsUtil.disableAutoscaling; @Named("createOrUpdateAppStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) @@ -84,8 +82,9 @@ protected String getStepErrorMessage(ProcessContext context) { protected AppBoundServiceInstanceNamesGetter getAppBoundServiceInstanceNamesGetter(ProcessContext context) { String user = context.getVariable(Variables.USER); + String userGuid = context.getVariable(Variables.USER_GUID); String correlationId = context.getVariable(Variables.CORRELATION_ID); - var token = tokenService.getToken(user); + var token = tokenService.getToken(user, userGuid); var credentials = new CloudCredentials(token, true); return new AppBoundServiceInstanceNamesGetter(configuration, webClientFactory, credentials, correlationId); } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DeleteApplicationRoutesStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DeleteApplicationRoutesStep.java index 828975bbb5..3a9910c232 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DeleteApplicationRoutesStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DeleteApplicationRoutesStep.java @@ -7,6 +7,12 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudRoute; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudRouteExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudRouteExtended; @@ -20,14 +26,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudCredentials; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudRoute; - -import jakarta.inject.Inject; -import jakarta.inject.Named; - @Named("deleteApplicationRoutesStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class DeleteApplicationRoutesStep extends UndeployAppStep implements BeforeStepHookPhaseProvider { @@ -65,8 +63,9 @@ protected ServiceInstanceRoutesGetter getServiceRoutesGetter(CloudCredentials cr private List getApplicationRoutes(CloudControllerClient client, CloudApplication app, ProcessContext context) { String user = context.getVariable(Variables.USER); + String userGuid = context.getVariable(Variables.USER_GUID); String correlationId = context.getVariable(Variables.CORRELATION_ID); - var token = tokenService.getToken(user); + var token = tokenService.getToken(user, userGuid); var credentials = new CloudCredentials(token, true); var serviceInstanceRoutesGetter = getServiceRoutesGetter(credentials, correlationId); @@ -78,8 +77,9 @@ private List getApplicationRoutes(CloudControllerClient clie var serviceRouteBindings = serviceInstanceRoutesGetter.getServiceRouteBindings(routeGuids); var routeIdsToServiceInstanceIds = serviceRouteBindings.stream() .collect(Collectors.groupingBy(ServiceRouteBinding::getRouteId, - Collectors.mapping(ServiceRouteBinding::getServiceInstanceId, - Collectors.toList()))); + Collectors.mapping( + ServiceRouteBinding::getServiceInstanceId, + Collectors.toList()))); return routes.stream() .map(route -> addServicesToRoute(route, routeIdsToServiceInstanceIds)) .collect(Collectors.toList()); @@ -87,8 +87,7 @@ private List getApplicationRoutes(CloudControllerClient clie private CloudRouteExtended addServicesToRoute(CloudRoute route, Map> routesToServices) { var boundServiceGuids = routesToServices.getOrDefault(route.getGuid() - .toString(), - Collections.emptyList()); + .toString(), Collections.emptyList()); return ImmutableCloudRouteExtended.builder() .from(route) .boundServiceInstanceGuids(boundServiceGuids) @@ -103,8 +102,7 @@ private void deleteApplicationRoute(CloudControllerClient client, CloudRouteExte } getStepLogger().info(Messages.DELETING_ROUTE, route.getUrl()); client.deleteRoute(route.getHost(), route.getDomain() - .getName(), - route.getPath()); + .getName(), route.getPath()); getStepLogger().debug(Messages.ROUTE_DELETED, route.getUrl()); } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java index 7fad9124b4..3291e69571 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java @@ -4,6 +4,10 @@ import java.util.List; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; @@ -22,12 +26,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudCredentials; - -import jakarta.inject.Inject; -import jakarta.inject.Named; - @Named("detectDeployedMtaStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class DetectDeployedMtaStep extends SyncFlowableStep { @@ -80,9 +78,9 @@ private DeployedMta detectDeployedMta(String mtaId, String mtaNamespace, CloudCo private void detectBackupMta(String mtaId, String mtaNamespace, CloudControllerClient client, ProcessContext context) { getStepLogger().debug(Messages.DETECTING_BACKUP_MTA_BY_ID_AND_NAMESPACE, mtaId, mtaNamespace); Optional optionalBackupMta = deployedMtaDetector.detectDeployedMtaByNameAndNamespace(mtaId, - NameUtil.computeUserNamespaceWithSystemNamespace(Constants.MTA_BACKUP_NAMESPACE, - mtaNamespace), - client); + NameUtil.computeUserNamespaceWithSystemNamespace( + Constants.MTA_BACKUP_NAMESPACE, + mtaNamespace), client); if (optionalBackupMta.isEmpty()) { context.setVariable(Variables.BACKUP_MTA, null); @@ -99,7 +97,8 @@ private List detectDeployedServiceKeys(String mtaId, Stri List deployedMtaServices = deployedMta == null ? null : deployedMta.getServices(); String spaceGuid = context.getVariable(Variables.SPACE_GUID); String user = context.getVariable(Variables.USER); - var token = tokenService.getToken(user); + String userGuid = context.getVariable(Variables.USER_GUID); + var token = tokenService.getToken(user, userGuid); var creds = new CloudCredentials(token, true); CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); @@ -116,8 +115,9 @@ private void logNoMtaDeployedDetected(String mtaId, String mtaNamespace) { private void logDetectedDeployedMta(String mtaNamespace, MtaMetadata metadata) { if (StringUtils.isNotEmpty(mtaNamespace)) { - getStepLogger().info(MessageFormat.format(Messages.DETECTED_DEPLOYED_MTA_WITH_NAMESPACE, metadata.getId(), - metadata.getVersion(), metadata.getNamespace())); + getStepLogger().info( + MessageFormat.format(Messages.DETECTED_DEPLOYED_MTA_WITH_NAMESPACE, metadata.getId(), metadata.getVersion(), + metadata.getNamespace())); return; } getStepLogger().info(MessageFormat.format(Messages.DETECTED_DEPLOYED_MTA, metadata.getId(), metadata.getVersion())); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetermineApplicationServiceBindingActionsStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetermineApplicationServiceBindingActionsStep.java index fa0f67b880..beedfbd4b5 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetermineApplicationServiceBindingActionsStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetermineApplicationServiceBindingActionsStep.java @@ -1,5 +1,11 @@ package org.cloudfoundry.multiapps.controller.process.steps; +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + import com.sap.cloudfoundry.client.facade.CloudControllerClient; import com.sap.cloudfoundry.client.facade.CloudCredentials; import com.sap.cloudfoundry.client.facade.domain.CloudApplication; @@ -18,12 +24,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import java.text.MessageFormat; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - @Named("determineApplicationServiceBindingActionsStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class DetermineApplicationServiceBindingActionsStep extends SyncFlowableStep { @@ -41,14 +41,16 @@ protected StepPhase executeStep(ProcessContext context) { CloudServiceBinding serviceBindingToDelete = context.getVariable(Variables.SERVICE_BINDING_TO_DELETE); CloudApplicationExtended appToProcess = context.getVariable(Variables.APP_TO_PROCESS); if (serviceBindingToDelete != null) { - String appName = appToProcess != null ? appToProcess.getName() : client.getApplicationName(serviceBindingToDelete.getApplicationGuid()); + String appName = + appToProcess != null ? appToProcess.getName() : client.getApplicationName(serviceBindingToDelete.getApplicationGuid()); String serviceInstanceName = getServiceInstanceToUnbind(context, client, serviceBindingToDelete); getStepLogger().debug(Messages.WILL_UNBIND_SERVICE_INSTANCE_0_FROM_APP_1, serviceInstanceName, appName); return setBindingForDeletion(context, appName, serviceInstanceName); } String serviceInstanceToUnbindBind = context.getVariable(Variables.SERVICE_TO_UNBIND_BIND); - getStepLogger().debug(Messages.DETERMINE_BIND_UNBIND_OPERATIONS_APPLICATION_0_SERVICE_INSTANCE_1, appToProcess.getName(), serviceInstanceToUnbindBind); + getStepLogger().debug(Messages.DETERMINE_BIND_UNBIND_OPERATIONS_APPLICATION_0_SERVICE_INSTANCE_1, appToProcess.getName(), + serviceInstanceToUnbindBind); if (!isServicePartFromMta(appToProcess, serviceInstanceToUnbindBind) && !shouldKeepExistingServiceBindings(appToProcess)) { return setBindingForDeletion(context, appToProcess.getName(), serviceInstanceToUnbindBind); } @@ -59,28 +61,34 @@ protected StepPhase executeStep(ProcessContext context) { String bindingName = serviceBindingParametersGetter.getDescriptorProvidedBindingName(appToProcess, serviceInstanceToUnbindBind); context.setVariable(Variables.BINDING_NAME, bindingName); - Map bindingParameters = serviceBindingParametersGetter.getServiceBindingParametersFromMta(appToProcess, serviceInstanceToUnbindBind); + Map bindingParameters = serviceBindingParametersGetter.getServiceBindingParametersFromMta(appToProcess, + serviceInstanceToUnbindBind); if (!doesServiceBindingExist(serviceInstanceToUnbindBind, existingApp.getGuid(), context)) { context.setVariable(Variables.SHOULD_UNBIND_SERVICE_FROM_APP, false); context.setVariable(Variables.SHOULD_BIND_SERVICE_TO_APP, true); context.setVariable(Variables.SERVICE_BINDING_PARAMETERS, bindingParameters); - getStepLogger().debug(Messages.CALCULATED_BINDING_OPERATIONS_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), serviceInstanceToUnbindBind, + getStepLogger().debug(Messages.CALCULATED_BINDING_OPERATIONS_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), + serviceInstanceToUnbindBind, false, true); return StepPhase.DONE; } - getStepLogger().debug(Messages.CHECK_SHOULD_REBIND_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), serviceInstanceToUnbindBind); + getStepLogger().debug(Messages.CHECK_SHOULD_REBIND_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), + serviceInstanceToUnbindBind); if (shouldKeepExistingServiceBindings(appToProcess)) { - getStepLogger().info(Messages.WILL_NOT_REBIND_APP_TO_SERVICE_KEEP_EXISTING_STRATEGY, serviceInstanceToUnbindBind, appToProcess.getName()); + getStepLogger().info(Messages.WILL_NOT_REBIND_APP_TO_SERVICE_KEEP_EXISTING_STRATEGY, serviceInstanceToUnbindBind, + appToProcess.getName()); return keepExistingServiceBindings(context, appToProcess, serviceInstanceToUnbindBind); } - if (shouldRecreateServiceBinding(context) || areBindingParametersDifferent(serviceBindingParametersGetter, existingApp, serviceInstanceToUnbindBind, + if (shouldRecreateServiceBinding(context) || areBindingParametersDifferent(serviceBindingParametersGetter, existingApp, + serviceInstanceToUnbindBind, bindingParameters)) { context.setVariable(Variables.SHOULD_UNBIND_SERVICE_FROM_APP, true); context.setVariable(Variables.SHOULD_BIND_SERVICE_TO_APP, true); context.setVariable(Variables.SERVICE_BINDING_PARAMETERS, bindingParameters); - getStepLogger().debug(Messages.CALCULATED_BINDING_OPERATIONS_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), serviceInstanceToUnbindBind, + getStepLogger().debug(Messages.CALCULATED_BINDING_OPERATIONS_APPLICATION_SERVICE_INSTANCE, appToProcess.getName(), + serviceInstanceToUnbindBind, true, true); return StepPhase.DONE; } @@ -88,7 +96,8 @@ protected StepPhase executeStep(ProcessContext context) { return keepExistingServiceBindings(context, appToProcess, serviceInstanceToUnbindBind); } - private String getServiceInstanceToUnbind(ProcessContext context, CloudControllerClient controllerClient, CloudServiceBinding cloudServiceBinding) { + private String getServiceInstanceToUnbind(ProcessContext context, CloudControllerClient controllerClient, + CloudServiceBinding cloudServiceBinding) { String serviceInstanceToUnbindBind = context.getVariable(Variables.SERVICE_TO_UNBIND_BIND); if (serviceInstanceToUnbindBind != null) { return serviceInstanceToUnbindBind; @@ -135,8 +144,9 @@ protected AppBoundServiceInstanceNamesGetter getAppServicesGetter(CloudCredentia private boolean doesServiceBindingExist(String serviceName, UUID appGuid, ProcessContext context) { String user = context.getVariable(Variables.USER); + String userGuid = context.getVariable(Variables.USER_GUID); String correlationId = context.getVariable(Variables.CORRELATION_ID); - var token = tokenService.getToken(user); + var token = tokenService.getToken(user, userGuid); var creds = new CloudCredentials(token, true); var serviceNamesGetter = getAppServicesGetter(creds, correlationId); @@ -144,8 +154,10 @@ private boolean doesServiceBindingExist(String serviceName, UUID appGuid, Proces return appServiceNames.contains(serviceName); } - private boolean areBindingParametersDifferent(ServiceBindingParametersGetter serviceBindingParametersGetter, CloudApplication app, String serviceName, Map newBindingParameters) { - Map currentBindingParameters = serviceBindingParametersGetter.getServiceBindingParametersFromExistingInstance(app, serviceName); + private boolean areBindingParametersDifferent(ServiceBindingParametersGetter serviceBindingParametersGetter, CloudApplication app, + String serviceName, Map newBindingParameters) { + Map currentBindingParameters = serviceBindingParametersGetter.getServiceBindingParametersFromExistingInstance(app, + serviceName); return !Objects.equals(currentBindingParameters, newBindingParameters); } @@ -157,8 +169,9 @@ private boolean shouldRecreateServiceBinding(ProcessContext context) { protected String getStepErrorMessage(ProcessContext context) { CloudServiceBinding serviceBindingToDelete = context.getVariable(Variables.SERVICE_BINDING_TO_DELETE); if (serviceBindingToDelete != null) { - return MessageFormat.format(Messages.ERROR_WHILE_DETERMINING_BIND_UNBIND_OPERATIONS_OF_APPLICATION_GUID_TO_SERVICE_INSTANCE_GUID, - serviceBindingToDelete.getApplicationGuid(), serviceBindingToDelete.getServiceInstanceGuid()); + return MessageFormat.format( + Messages.ERROR_WHILE_DETERMINING_BIND_UNBIND_OPERATIONS_OF_APPLICATION_GUID_TO_SERVICE_INSTANCE_GUID, + serviceBindingToDelete.getApplicationGuid(), serviceBindingToDelete.getServiceInstanceGuid()); } return MessageFormat.format(Messages.ERROR_WHILE_DETERMINING_BIND_UNBIND_OPERATIONS_OF_APPLICATION_TO_SERVICE, context.getVariable(Variables.APP_TO_PROCESS) diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecution.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecution.java index 3f670dbe1f..f207aa8048 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecution.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecution.java @@ -1,7 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static java.text.MessageFormat.format; - import java.text.MessageFormat; import java.time.Instant; import java.time.LocalDateTime; @@ -10,6 +8,10 @@ import java.util.Objects; import java.util.UUID; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; +import com.sap.cloudfoundry.client.facade.domain.ApplicationLog.MessageType; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.apps.ApplicationStateAction; @@ -22,10 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; -import com.sap.cloudfoundry.client.facade.domain.ApplicationLog.MessageType; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import static java.text.MessageFormat.format; public class PollExecuteAppStatusExecution implements AsyncExecution { @@ -81,8 +80,9 @@ public AsyncExecutionState execute(ProcessContext context) { LocalDateTime logsOffset = context.getVariable(Variables.LOGS_OFFSET_FOR_APP_EXECUTION); var user = context.getVariable(Variables.USER); + var userGuid = context.getVariable(Variables.USER_GUID); var correlationId = context.getVariable(Variables.CORRELATION_ID); - var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user), correlationId); + var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user, userGuid), correlationId); UUID appGuid = client.getApplicationGuid(app.getName()); List recentLogs = logCacheClient.getRecentLogs(appGuid, logsOffset); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteTaskStatusExecution.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteTaskStatusExecution.java index ecb3eb1e28..25011bb464 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteTaskStatusExecution.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteTaskStatusExecution.java @@ -3,6 +3,8 @@ import java.text.MessageFormat; import java.util.UUID; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.CloudTask; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; @@ -12,9 +14,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.CloudTask; - public class PollExecuteTaskStatusExecution implements AsyncExecution { private static final Logger LOGGER = LoggerFactory.getLogger(PollExecuteTaskStatusExecution.class); @@ -42,8 +41,9 @@ public AsyncExecutionState execute(ProcessContext context) { .getProcessLoggerProvider(); var user = context.getVariable(Variables.USER); + var userGuid = context.getVariable(Variables.USER_GUID); var correlationId = context.getVariable(Variables.CORRELATION_ID); - var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user), correlationId); + var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user, userGuid), correlationId); UUID appGuid = client.getApplicationGuid(app.getName()); StepsUtil.saveAppLogs(context, logCacheClient, appGuid, app.getName(), LOGGER, processLoggerProvider); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStageAppStatusExecution.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStageAppStatusExecution.java index 5635858614..e41ccf522c 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStageAppStatusExecution.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStageAppStatusExecution.java @@ -3,6 +3,9 @@ import java.text.MessageFormat; import java.util.UUID; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.PackageState; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.cloudfoundry.multiapps.controller.persistence.services.ProcessLoggerProvider; @@ -14,10 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.PackageState; - public class PollStageAppStatusExecution implements AsyncExecution { private static final Logger LOGGER = LoggerFactory.getLogger(PollStageAppStatusExecution.class); @@ -46,8 +45,9 @@ public AsyncExecutionState execute(ProcessContext context) { ProcessLoggerProvider processLoggerProvider = stepLogger.getProcessLoggerProvider(); var user = context.getVariable(Variables.USER); + var userGuid = context.getVariable(Variables.USER_GUID); var correlationId = context.getVariable(Variables.CORRELATION_ID); - var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user), correlationId); + var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user, userGuid), correlationId); UUID appGuid = client.getApplicationGuid(application.getName()); StepsUtil.saveAppLogs(context, logCacheClient, appGuid, application.getName(), LOGGER, processLoggerProvider); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStartAppStatusExecution.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStartAppStatusExecution.java index 85c4dba3b5..893f0cdcf6 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStartAppStatusExecution.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/PollStartAppStatusExecution.java @@ -1,11 +1,14 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static java.text.MessageFormat.format; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudRoute; +import com.sap.cloudfoundry.client.facade.domain.InstanceInfo; +import com.sap.cloudfoundry.client.facade.domain.InstanceState; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.cloudfoundry.multiapps.controller.core.util.UriUtil; @@ -15,11 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudRoute; -import com.sap.cloudfoundry.client.facade.domain.InstanceInfo; -import com.sap.cloudfoundry.client.facade.domain.InstanceState; +import static java.text.MessageFormat.format; public class PollStartAppStatusExecution implements AsyncExecution { @@ -48,8 +47,9 @@ public AsyncExecutionState execute(ProcessContext context) { .getProcessLoggerProvider(); var user = context.getVariable(Variables.USER); + var userGuid = context.getVariable(Variables.USER_GUID); var correlationId = context.getVariable(Variables.CORRELATION_ID); - var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user), correlationId); + var logCacheClient = clientFactory.createLogCacheClient(tokenService.getToken(user, userGuid), correlationId); StepsUtil.saveAppLogs(context, logCacheClient, app.getGuid(), app.getName(), LOGGER, processLoggerProvider); return checkStartupStatus(context, app, status); @@ -139,8 +139,7 @@ private String composeStatesMessage(List instances) { } else { stateCounts = instances.stream() .collect(Collectors.groupingBy(instance -> instance.getState() - .toString(), - Collectors.counting())); + .toString(), Collectors.counting())); } return stateCounts.entrySet() .stream() diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/ProcessContext.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/ProcessContext.java index 6faa550497..fe34c50b03 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/ProcessContext.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/ProcessContext.java @@ -1,5 +1,6 @@ package org.cloudfoundry.multiapps.controller.process.steps; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; import org.cloudfoundry.multiapps.controller.process.Messages; @@ -10,8 +11,6 @@ import org.cloudfoundry.multiapps.controller.process.variables.Variables; import org.flowable.engine.delegate.DelegateExecution; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; - public class ProcessContext { private final DelegateExecution execution; @@ -34,16 +33,18 @@ public StepLogger getStepLogger() { public CloudControllerClient getControllerClient() { String userName = StepsUtil.determineCurrentUser(execution); + String userGuid = StepsUtil.determineCurrentUserGuid(execution); String spaceGuid = getVariable(Variables.SPACE_GUID); String correlationId = getVariable(Variables.CORRELATION_ID); - CloudControllerClient delegate = clientProvider.getControllerClient(userName, spaceGuid, correlationId); + CloudControllerClient delegate = clientProvider.getControllerClient(userName, userGuid, spaceGuid, correlationId); return new LoggingCloudControllerClient(delegate, stepLogger); } public CloudControllerClient getControllerClient(String spaceGuid) { String userName = StepsUtil.determineCurrentUser(execution); + String userGuid = StepsUtil.determineCurrentUserGuid(execution); String correlationId = getVariable(Variables.CORRELATION_ID); - CloudControllerClient delegate = clientProvider.getControllerClient(userName, spaceGuid, correlationId); + CloudControllerClient delegate = clientProvider.getControllerClient(userName, userGuid, spaceGuid, correlationId); return new LoggingCloudControllerClient(delegate, stepLogger); } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/StepsUtil.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/StepsUtil.java index 74592853f3..3a41037365 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/StepsUtil.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/StepsUtil.java @@ -12,6 +12,13 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.fasterxml.jackson.core.type.TypeReference; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.adapters.LogCacheClient; +import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudServiceBroker; +import com.sap.cloudfoundry.client.facade.domain.CloudTask; import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.client.v3.Metadata; import org.cloudfoundry.multiapps.common.SLException; @@ -38,14 +45,6 @@ import org.flowable.variable.api.history.HistoricVariableInstance; import org.slf4j.Logger; -import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.adapters.LogCacheClient; -import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudServiceBroker; -import com.sap.cloudfoundry.client.facade.domain.CloudTask; - public class StepsUtil { public static final String DEPLOY_ID_PREFIX = "deploy-"; @@ -61,6 +60,16 @@ public static String determineCurrentUser(VariableScope scope) { return user; } + public static String determineCurrentUserGuid(VariableScope scope) { + String userGuid = VariableHandling.get(scope, Variables.USER_GUID); + if (userGuid == null) { + // TODO: Throw exception when we are sure that userGuid is not null after one release takt + return null; + // throw new SLException(Messages.CANT_DETERMINE_CURRENT_USER_GUID); + } + return userGuid; + } + public static CloudHandlerFactory getHandlerFactory(VariableScope scope) { int majorSchemaVersion = VariableHandling.get(scope, Variables.MTA_MAJOR_SCHEMA_VERSION); return CloudHandlerFactory.forSchemaVersion(majorSchemaVersion); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStep.java index 817cdf649a..40f5af7a29 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStep.java @@ -11,6 +11,13 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudOperationException; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudSpace; +import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.apache.commons.collections4.ListUtils; import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.common.util.JsonUtil; @@ -49,15 +56,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudOperationException; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudSpace; -import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; - -import jakarta.inject.Inject; -import jakarta.inject.Named; - @Named("updateSubscribersStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class UpdateSubscribersStep extends SyncFlowableStep { @@ -66,7 +64,7 @@ public class UpdateSubscribersStep extends SyncFlowableStep { * This schema version will be used only for the handling of the subscription entities and it should always be the same as the latest * version that is supported by the deploy service, as it is assumed that the latest version of the MTA specification will always * support a superset of the features supported by the previous versions. - * + * * The major schema version of the MTA that is currently being deployed should NOT be used instead of this one, as problems could occur * if the subscriber has a different major schema version. If, for example, the current MTA has a major schema version 1, and the * subscriber has a major schema version 2, then this would result in the creation of a handler factory for version 1. That would cause @@ -136,7 +134,8 @@ protected String getStepErrorMessage(ProcessContext context) { private CloudSpaceClient createSpaceClient(ProcessContext context) { var user = context.getVariable(Variables.USER); - var token = tokenService.getToken(user); + var userGuid = context.getVariable(Variables.USER_GUID); + var token = tokenService.getToken(user, userGuid); return clientFactory.createSpaceClient(token); } @@ -183,9 +182,12 @@ private CloudApplication attemptToUpdateSubscriber(ProcessContext context, Cloud SecureSerialization.toJson(dummyDescriptor)); ConfigurationReferencesResolver resolver = handlerFactory.getConfigurationReferencesResolver(configurationEntryService, - new DummyConfigurationFilterParser(subscription.getFilter()), - new CloudTarget(context.getVariable(Variables.ORGANIZATION_NAME), - context.getVariable(Variables.SPACE_NAME)), + new DummyConfigurationFilterParser( + subscription.getFilter()), + new CloudTarget(context.getVariable( + Variables.ORGANIZATION_NAME), + context.getVariable( + Variables.SPACE_NAME)), configuration); resolver.resolve(dummyDescriptor); getStepLogger().debug(Messages.RESOLVED_DEPLOYMENT_DESCRIPTOR, SecureSerialization.toJson(dummyDescriptor)); @@ -198,9 +200,11 @@ private CloudApplication attemptToUpdateSubscriber(ProcessContext context, Cloud ApplicationCloudModelBuilder applicationCloudModelBuilder = handlerFactory.getApplicationCloudModelBuilder(dummyDescriptor, shouldUsePrettyPrinting(), null, "", - context.getVariable(Variables.MTA_NAMESPACE), + context.getVariable( + Variables.MTA_NAMESPACE), getStepLogger(), - StepsUtil.getAppSuffixDeterminer(context), + StepsUtil.getAppSuffixDeterminer( + context), client, false); Module module = dummyDescriptor.getModules() diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ClientReleaser.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ClientReleaser.java index 5eddf63942..d894e7d987 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ClientReleaser.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ClientReleaser.java @@ -2,7 +2,6 @@ import jakarta.inject.Inject; import jakarta.inject.Named; - import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; import org.cloudfoundry.multiapps.controller.process.variables.Variables; import org.flowable.engine.HistoryService; @@ -18,9 +17,9 @@ public ClientReleaser(CloudControllerClientProvider clientProvider) { } public void releaseClientFor(HistoryService historyService, String processInstanceId) { - String user = HistoryUtil.getVariableValue(historyService, processInstanceId, Variables.USER.getName()); + String userGuid = HistoryUtil.getVariableValue(historyService, processInstanceId, Variables.USER_GUID.getName()); String spaceGuid = HistoryUtil.getVariableValue(historyService, processInstanceId, Variables.SPACE_GUID.getName()); - clientProvider.releaseClient(user, spaceGuid); + clientProvider.releaseClient(userGuid, spaceGuid); } } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/OperationInFinalStateHandler.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/OperationInFinalStateHandler.java index 5cbd6a7feb..9e2c52f303 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/OperationInFinalStateHandler.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/OperationInFinalStateHandler.java @@ -1,7 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.util; -import static java.text.MessageFormat.format; - import java.text.MessageFormat; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -9,6 +7,9 @@ import java.util.Map; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.cloudfoundry.client.v3.Metadata; import org.cloudfoundry.multiapps.controller.api.model.ImmutableOperation; import org.cloudfoundry.multiapps.controller.api.model.Operation; @@ -38,10 +39,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; - -import jakarta.inject.Inject; -import jakarta.inject.Named; +import static java.text.MessageFormat.format; @Named public class OperationInFinalStateHandler { @@ -92,10 +90,10 @@ protected void deleteDeploymentFiles(String correlationId, DelegateExecution exe } private void deleteCloudControllerClientForProcess(DelegateExecution execution) { - String user = StepsUtil.determineCurrentUser(execution); + String userGuid = StepsUtil.determineCurrentUserGuid(execution); String spaceGuid = VariableHandling.get(execution, Variables.SPACE_GUID); - clientProvider.releaseClient(user, spaceGuid); + clientProvider.releaseClient(userGuid, spaceGuid); } protected void setOperationState(String processInstanceId, Operation.State state) { @@ -120,8 +118,7 @@ protected void setOperationState(String processInstanceId, Operation.State state private boolean isOperationAlreadyFinal(Operation operation) { return operation.getState() - .isFinal() - && !operation.hasAcquiredLock() && operation.getEndedAt() != null; + .isFinal() && !operation.hasAcquiredLock() && operation.getEndedAt() != null; } private HistoricOperationEvent.EventType toEventType(State state) { @@ -142,8 +139,8 @@ private void deletePreviousBackupDescriptors(DelegateExecution execution, Proces Optional mtaVersion = getMtaVersionOfDeployedApplication(deployedMta); if (mtaVersion.isPresent()) { - LOGGER.info(MessageFormat.format(Messages.DELETING_BACKUP_DESCRIPTOR_WITH_MTA_ID_0_SPACE_1_NAMESPACE_2_AND_VERSION_3, - mtaId, spaceId, mtaNamespace, mtaVersion.get())); + LOGGER.info(MessageFormat.format(Messages.DELETING_BACKUP_DESCRIPTOR_WITH_MTA_ID_0_SPACE_1_NAMESPACE_2_AND_VERSION_3, mtaId, + spaceId, mtaNamespace, mtaVersion.get())); descriptorBackupService.createQuery() .mtaId(mtaId) .spaceId(spaceId) @@ -170,8 +167,9 @@ private void deletePreviousBackupDescriptors(DelegateExecution execution, Proces return; } - LOGGER.info(MessageFormat.format(Messages.DELETING_BACKUP_DESCRIPTORS_WITH_MTA_ID_0_SPACE_1_NAMESPACE_2_AND_SKIP_VERSIONS_3, mtaId, - spaceId, mtaNamespace, mtaVersionsToSkipDeletion)); + LOGGER.info( + MessageFormat.format(Messages.DELETING_BACKUP_DESCRIPTORS_WITH_MTA_ID_0_SPACE_1_NAMESPACE_2_AND_SKIP_VERSIONS_3, mtaId, spaceId, + mtaNamespace, mtaVersionsToSkipDeletion)); descriptorBackupService.createQuery() .mtaId(mtaId) .spaceId(spaceId) @@ -225,12 +223,14 @@ private void trackOperationDuration(String correlationId, DelegateExecution exec Variables.SPACE_GUID)) .operationState(state) .processType(processType) - .processDuration(overallProcessTime.getProcessDuration()) + .processDuration( + overallProcessTime.getProcessDuration()) .build(); dynatracePublisher.publishProcessDuration(dynatraceProcessDuration, LOGGER); - LOGGER.info(format(Messages.TIME_STATISTICS_FOR_OPERATION_0_DURATION_1_DELAY_2, correlationId, - overallProcessTime.getProcessDuration(), overallProcessTime.getDelayBetweenSteps())); + LOGGER.info( + format(Messages.TIME_STATISTICS_FOR_OPERATION_0_DURATION_1_DELAY_2, correlationId, overallProcessTime.getProcessDuration(), + overallProcessTime.getDelayBetweenSteps())); } private void logProcessTime(String correlationId, String processId, ProcessTime processTime) { diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/variables/Variables.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/variables/Variables.java index 3075f66cbb..dfa65dd558 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/variables/Variables.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/variables/Variables.java @@ -10,6 +10,15 @@ import java.util.Set; import java.util.UUID; +import com.fasterxml.jackson.core.type.TypeReference; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudPackage; +import com.sap.cloudfoundry.client.facade.domain.CloudRoute; +import com.sap.cloudfoundry.client.facade.domain.CloudServiceBinding; +import com.sap.cloudfoundry.client.facade.domain.CloudServiceBroker; +import com.sap.cloudfoundry.client.facade.domain.CloudServiceKey; +import com.sap.cloudfoundry.client.facade.domain.CloudTask; +import com.sap.cloudfoundry.client.facade.domain.ServiceOperation; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudServiceInstanceExtended; import org.cloudfoundry.multiapps.controller.core.cf.DeploymentMode; @@ -37,16 +46,6 @@ import org.cloudfoundry.multiapps.mta.model.Module; import org.cloudfoundry.multiapps.mta.model.VersionRule; -import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudPackage; -import com.sap.cloudfoundry.client.facade.domain.CloudRoute; -import com.sap.cloudfoundry.client.facade.domain.CloudServiceBinding; -import com.sap.cloudfoundry.client.facade.domain.CloudServiceBroker; -import com.sap.cloudfoundry.client.facade.domain.CloudServiceKey; -import com.sap.cloudfoundry.client.facade.domain.CloudTask; -import com.sap.cloudfoundry.client.facade.domain.ServiceOperation; - public interface Variables { Variable CORRELATION_ID = ImmutableSimpleVariable. builder() @@ -62,13 +61,15 @@ public interface Variables { .name("space") .build(); Variable SPACE_GUID = ImmutableSimpleVariable. builder() - .name(org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SPACE_ID) + .name( + org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SPACE_ID) .build(); Variable SUBPROCESS_ID = ImmutableSimpleVariable. builder() .name("subProcessId") .build(); Variable SERVICE_ID = ImmutableSimpleVariable. builder() - .name(org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SERVICE_ID) + .name( + org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SERVICE_ID) .build(); Variable TASK_ID = ImmutableSimpleVariable. builder() .name("__TASK_ID") @@ -132,6 +133,9 @@ public interface Variables { Variable USER = ImmutableSimpleVariable. builder() .name("user") .build(); + Variable USER_GUID = ImmutableSimpleVariable. builder() + .name("userGuid") + .build(); Variable SERVICE_OFFERING = ImmutableSimpleVariable. builder() .name("serviceOffering") .build(); @@ -301,19 +305,24 @@ public interface Variables { .build(); Variable DEPLOYMENT_DESCRIPTOR = ImmutableJsonStringVariable. builder() .name("mtaDeploymentDescriptor") - .type(Variable.typeReference(DeploymentDescriptor.class)) + .type(Variable.typeReference( + DeploymentDescriptor.class)) .build(); Variable DEPLOYMENT_DESCRIPTOR_WITH_SYSTEM_PARAMETERS = ImmutableJsonStringVariable. builder() - .name("mtaDeploymentDescriptorWithSystemParameters") - .type(Variable.typeReference(DeploymentDescriptor.class)) + .name( + "mtaDeploymentDescriptorWithSystemParameters") + .type(Variable.typeReference( + DeploymentDescriptor.class)) .build(); Variable COMPLETE_DEPLOYMENT_DESCRIPTOR = ImmutableJsonStringVariable. builder() .name("completeMtaDeploymentDescriptor") - .type(Variable.typeReference(DeploymentDescriptor.class)) + .type(Variable.typeReference( + DeploymentDescriptor.class)) .build(); Variable APP_TO_PROCESS = ImmutableJsonStringVariable. builder() .name("appToProcess") - .type(Variable.typeReference(CloudApplicationExtended.class)) + .type(Variable.typeReference( + CloudApplicationExtended.class)) .build(); Variable BINDING_NAME = ImmutableSimpleVariable. builder() .name("bindingName") @@ -327,7 +336,8 @@ public interface Variables { .build(); Variable SERVICE_TO_PROCESS = ImmutableJsonStringVariable. builder() .name("serviceToProcess") - .type(Variable.typeReference(CloudServiceInstanceExtended.class)) + .type(Variable.typeReference( + CloudServiceInstanceExtended.class)) .build(); Variable CLOUD_PACKAGE = ImmutableJsonStringVariable. builder() .name("uploadedCloudPackage") @@ -365,7 +375,8 @@ public interface Variables { .build(); Variable CREATED_OR_UPDATED_SERVICE_BROKER = ImmutableJsonBinaryVariable. builder() .name("createdOrUpdatedServiceBroker") - .type(Variable.typeReference(CloudServiceBroker.class)) + .type(Variable.typeReference( + CloudServiceBroker.class)) .build(); Variable> CUSTOM_DOMAINS = ImmutableJsonBinaryVariable.> builder() .name("customDomains") @@ -414,7 +425,8 @@ public interface Variables { .build(); Variable>> SERVICE_KEYS_FOR_CONTENT_DEPLOY = ImmutableJsonBinaryVariable.>> builder() - .name("serviceKeysForContentDeploy") + .name( + "serviceKeysForContentDeploy") .type(new TypeReference<>() { }) .build(); @@ -449,12 +461,14 @@ public interface Variables { }) .build(); Variable> TRIGGERED_SERVICE_OPERATIONS = ImmutableJsonBinaryVariable.> builder() - .name("triggeredServiceOperations") + .name( + "triggeredServiceOperations") .type(new TypeReference<>() { }) .build(); Variable> UPDATED_SERVICE_BROKER_SUBSCRIBERS = ImmutableJsonBinaryVariable.> builder() - .name("updatedServiceBrokerSubscribers") + .name( + "updatedServiceBrokerSubscribers") .type(new TypeReference<>() { }) .build(); @@ -528,12 +542,14 @@ public interface Variables { .build(); Variable> SERVICES_TO_BIND = ImmutableJsonStringListVariable. builder() .name("servicesToBind") - .type(Variable.typeReference(CloudServiceInstanceExtended.class)) + .type(Variable.typeReference( + CloudServiceInstanceExtended.class)) .defaultValue(Collections.emptyList()) .build(); Variable> SERVICES_TO_CREATE = ImmutableJsonStringListVariable. builder() .name("servicesToCreate") - .type(Variable.typeReference(CloudServiceInstanceExtended.class)) + .type(Variable.typeReference( + CloudServiceInstanceExtended.class)) .defaultValue(Collections.emptyList()) .build(); Variable> HOOKS_FOR_EXECUTION = ImmutableJsonStringListVariable. builder() @@ -567,8 +583,11 @@ public interface Variables { .defaultValue(Collections.emptyList()) .build(); Variable> MTA_EXTENSION_DESCRIPTOR_CHAIN = ImmutableJsonBinaryListVariableAllowingNulls. builder() - .name("mtaExtensionDescriptorChain") - .type(Variable.typeReference(ExtensionDescriptor.class)) + .name( + "mtaExtensionDescriptorChain") + .type( + Variable.typeReference( + ExtensionDescriptor.class)) .build(); Variable> MODULES_FOR_DEPLOYMENT = ImmutableCommaSeparatedValuesVariable.builder() .name("modulesForDeployment") @@ -623,7 +642,8 @@ public interface Variables { .build(); Variable WAS_SERVICE_BINDING_KEY_OPERATION_ALREADY_DONE = ImmutableSimpleVariable. builder() - .name("wasServiceBindingKeyOperationAlreadyDone") + .name( + "wasServiceBindingKeyOperationAlreadyDone") .defaultValue(false) .build(); @@ -720,11 +740,13 @@ public Serializer> getSerializer() { .name("serviceKeyDeletionJobId") .build(); Variable USE_LAST_OPERATION_FOR_SERVICE_BINDING_CREATION = ImmutableSimpleVariable. builder() - .name("useLastOperationForServiceBindingCreation") + .name( + "useLastOperationForServiceBindingCreation") .defaultValue(false) .build(); Variable USE_LAST_OPERATION_FOR_SERVICE_BINDING_DELETION = ImmutableSimpleVariable. builder() - .name("useLastOperationForServiceBindingDeletion") + .name( + "useLastOperationForServiceBindingDeletion") .defaultValue(false) .build(); Variable USE_LAST_OPERATION_FOR_SERVICE_KEY_CREATION = ImmutableSimpleVariable. builder() @@ -737,13 +759,16 @@ public Serializer> getSerializer() { .build(); Variable SERVICE_BINDING_TO_DELETE = ImmutableJsonStringVariable. builder() .name("serviceBindingToDelete") - .type(Variable.typeReference(CloudServiceBinding.class)) + .type(Variable.typeReference( + CloudServiceBinding.class)) .build(); Variable> CLOUD_SERVICE_BINDINGS_TO_DELETE = ImmutableJsonStringListVariable. builder() - .name("cloudServiceBindingsToDelete") + .name( + "cloudServiceBindingsToDelete") .type(new TypeReference<>() { }) - .defaultValue(Collections.emptyList()) + .defaultValue( + Collections.emptyList()) .build(); Variable> CLOUD_SERVICE_KEYS_TO_CREATE = ImmutableJsonStringListVariable. builder() .name("cloudServiceKeysToCreate") @@ -761,7 +786,8 @@ public Serializer> getSerializer() { .name("cloudServiceKeysToUpdate") .type(new TypeReference<>() { }) - .defaultValue(Collections.emptyList()) + .defaultValue( + Collections.emptyList()) .build(); Variable> SERVICE_DELETION_ACTIONS = ImmutableEnumListVariable. builder() .name("serviceDeletionActions") @@ -787,7 +813,8 @@ public Serializer> getSerializer() { .name("logsOffsetForAppExecution") .type(Variable.typeReference(LocalDateTime.class)) .defaultValue(LocalDateTime.ofInstant(Instant.EPOCH, - ZoneId.of("UTC"))) + ZoneId.of( + "UTC"))) .build(); // we need to use a Json string serialization because the nanosecond precision is being lost when using SimpleVariable Variable LOGS_OFFSET = ImmutableJsonStringVariable. builder() @@ -807,10 +834,12 @@ public Serializer> getSerializer() { .build(); Variable> DYNAMIC_RESOLVABLE_PARAMETERS = ImmutableJsonStringVariable.> builder() - .name("dynamicResolvableParameters") + .name( + "dynamicResolvableParameters") .type(new TypeReference<>() { }) - .defaultValue(Collections.emptySet()) + .defaultValue( + Collections.emptySet()) .build(); Variable DYNAMIC_RESOLVABLE_PARAMETER = ImmutableJsonStringVariable. builder() @@ -829,9 +858,11 @@ public Serializer> getSerializer() { .build(); Variable INCREMENTAL_APP_INSTANCE_UPDATE_CONFIGURATION = ImmutableJsonStringVariable. builder() - .name("incrementalAppInstanceUpdateConfiguration") - .type(new TypeReference<>() { - }) + .name( + "incrementalAppInstanceUpdateConfiguration") + .type( + new TypeReference<>() { + }) .build(); Variable SKIP_APP_DIGEST_CALCULATION = ImmutableSimpleVariable. builder() @@ -851,7 +882,8 @@ public Serializer> getSerializer() { .build(); Variable> ARCHIVE_ENTRIES_POSITIONS = ImmutableJsonStringListVariable. builder() - .name("archiveEntriesPositions") + .name( + "archiveEntriesPositions") .type(new TypeReference<>() { }) .build(); diff --git a/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/deploy-app.bpmn b/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/deploy-app.bpmn index 255a5e7abd..7d33810803 100644 --- a/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/deploy-app.bpmn +++ b/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/deploy-app.bpmn @@ -84,6 +84,7 @@ + @@ -100,6 +101,7 @@ + @@ -124,6 +126,7 @@ + diff --git a/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/process-batches-sequentially.bpmn b/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/process-batches-sequentially.bpmn index 608c109710..240c359f21 100644 --- a/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/process-batches-sequentially.bpmn +++ b/multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/process-batches-sequentially.bpmn @@ -16,6 +16,7 @@ + diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStepTest.java index 993f6342b8..af2de7dc3c 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStepTest.java @@ -1,10 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -13,6 +8,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.fasterxml.jackson.core.type.TypeReference; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudEntity; import org.cloudfoundry.multiapps.common.test.TestUtil; import org.cloudfoundry.multiapps.common.test.Tester; import org.cloudfoundry.multiapps.common.test.Tester.Expectation; @@ -38,10 +37,10 @@ import org.mockito.Mock; import org.mockito.Mockito; -import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudEntity; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; class BuildCloudUndeployModelStepTest extends SyncFlowableStepTest { @@ -51,7 +50,7 @@ class BuildCloudUndeployModelStepTest extends SyncFlowableStepTest testExecute() { return Stream.of( -// @formatter:off + // @formatter:off // (0) No previously deployed MTA: Arguments.of(new StepInput("modules-to-deploy-01.json", "apps-to-deploy-01.json", "empty-list.json", Collections.emptyList(), "deployed-apps-01.json", new TreeSet<>(List.of("a", "b", "c")), null, "empty-list.json", "empty-list.json", new TreeSet<>(List.of("a", "b", "c"))), new StepOutput(Collections.emptyList(), Collections.emptyList(), new Expectation(Expectation.Type.JSON, "empty-list.json"))), @@ -125,7 +124,7 @@ private void prepareClient() { Mockito.when(client.getApplication(application.getName(), false)) .thenReturn(application); } - Mockito.when(clientProvider.getControllerClient(anyString(), anyString(), anyString())) + Mockito.when(clientProvider.getControllerClient(anyString(), anyString(), anyString(), anyString())) .thenReturn(client); } @@ -195,7 +194,8 @@ private void prepareContext(StepInput input) { private void prepareSubscriptionService() { when(configurationSubscriptionService.createQuery()).thenReturn(configurationSubscriptionQuery); if (deployedMta != null) { - ConfigurationSubscriptionQuery mock = new MockBuilder<>(configurationSubscriptionQuery).on(query -> query.mtaId(deployedMta.getMetadata() + ConfigurationSubscriptionQuery mock = new MockBuilder<>(configurationSubscriptionQuery).on( + query -> query.mtaId(deployedMta.getMetadata() .getId())) .on(query -> query.spaceId(SPACE_ID)) .build(); diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecutionTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecutionTest.java index e6a7eab319..3b5e27566d 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecutionTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollExecuteAppStatusExecutionTest.java @@ -1,21 +1,12 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; -import java.time.ZoneOffset; import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -23,7 +14,11 @@ import java.util.UUID; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; import com.sap.cloudfoundry.client.facade.adapters.LogCacheClient; +import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; +import com.sap.cloudfoundry.client.facade.domain.ApplicationLog.MessageType; +import com.sap.cloudfoundry.client.facade.domain.ImmutableApplicationLog; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; @@ -47,14 +42,19 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.ApplicationLog; -import com.sap.cloudfoundry.client.facade.domain.ApplicationLog.MessageType; -import com.sap.cloudfoundry.client.facade.domain.ImmutableApplicationLog; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class PollExecuteAppStatusExecutionTest { private static final String USER_NAME = "testUsername"; + private static final String USER_GUID = "123-456-789"; private static final String APP_SOURCE = "APP"; private static final String APPLICATION_GUID = UUID.randomUUID() .toString(); @@ -94,29 +94,29 @@ void setUp() throws Exception { static Stream testStep() { return Stream.of( - // (1) Application is in running state - Arguments.of(createAppLog("testMessage", MessageType.STDOUT, APP_SOURCE), null, null, false, - AsyncExecutionState.RUNNING), - // (2) Application finished execution and should be stopped - Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), null, null, true, - AsyncExecutionState.FINISHED), - // (3) Application finished execution and should be left to run - Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), null, null, false, - AsyncExecutionState.FINISHED), - // (4) Application with Custom success marker - Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), "executed", null, false, - AsyncExecutionState.RUNNING), - // (5) Application in failed state - Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, null, false, - AsyncExecutionState.ERROR), - // (6) Application in failed state and should be stopped - Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, null, true, AsyncExecutionState.ERROR), - // (7) Application with Custom failure marker - Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, "execution failure", false, - AsyncExecutionState.RUNNING), - // (8) Log message with non APP Source - Arguments.of(createAppLog("info service", MessageType.STDOUT, "service"), null, null, false, - AsyncExecutionState.RUNNING)); + // (1) Application is in running state + Arguments.of(createAppLog("testMessage", MessageType.STDOUT, APP_SOURCE), null, null, false, + AsyncExecutionState.RUNNING), + // (2) Application finished execution and should be stopped + Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), null, null, true, + AsyncExecutionState.FINISHED), + // (3) Application finished execution and should be left to run + Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), null, null, false, + AsyncExecutionState.FINISHED), + // (4) Application with Custom success marker + Arguments.of(createAppLog("SUCCESS", MessageType.STDOUT, APP_SOURCE), "executed", null, false, + AsyncExecutionState.RUNNING), + // (5) Application in failed state + Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, null, false, + AsyncExecutionState.ERROR), + // (6) Application in failed state and should be stopped + Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, null, true, AsyncExecutionState.ERROR), + // (7) Application with Custom failure marker + Arguments.of(createAppLog("FAILURE", MessageType.STDERR, APP_SOURCE), null, "execution failure", false, + AsyncExecutionState.RUNNING), + // (8) Log message with non APP Source + Arguments.of(createAppLog("info service", MessageType.STDOUT, "service"), null, null, false, + AsyncExecutionState.RUNNING)); } private static ApplicationLog createAppLog(String message, MessageType messageType, String sourceName) { @@ -170,6 +170,7 @@ private void prepareContext(CloudApplicationExtended application) { context.setVariable(Variables.APP_TO_PROCESS, application); context.setVariable(Variables.APP_STATE_ACTIONS_TO_EXECUTE, List.of(ApplicationStateAction.EXECUTE)); context.setVariable(Variables.USER, USER_NAME); + context.setVariable(Variables.USER_GUID, USER_GUID); context.setVariable(Variables.START_TIME, PROCESS_START_TIME); context.setVariable(Variables.LOGS_OFFSET, LocalDateTime.ofInstant(Instant.EPOCH, ZoneId.of("UTC"))); context.setVariable(Variables.LOGS_OFFSET_FOR_APP_EXECUTION, LocalDateTime.ofInstant(Instant.EPOCH, ZoneId.of("UTC"))); @@ -184,7 +185,7 @@ private void prepareClients(ApplicationLog applicationLog) { when(logCacheClient.getRecentLogs(any(), any())).thenReturn(List.of(applicationLog)); when(clientFactory.createLogCacheClient(any(), any())).thenReturn(logCacheClient); when(client.getApplicationGuid(eq(APPLICATION_NAME))).thenReturn(UUID.fromString(APPLICATION_GUID)); - when(clientProvider.getControllerClient(any(), any(), any())).thenReturn(client); + when(clientProvider.getControllerClient(any(), any(), any(), any())).thenReturn(client); } @Test diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollServiceInProgressOperationsExecutionTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollServiceInProgressOperationsExecutionTest.java index 0a902da081..58318ed4a7 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollServiceInProgressOperationsExecutionTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/PollServiceInProgressOperationsExecutionTest.java @@ -1,14 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -17,6 +8,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ServiceOperation; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudServiceInstanceExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudServiceInstanceExtended; import org.cloudfoundry.multiapps.controller.process.util.ServiceOperationGetter; @@ -27,9 +21,14 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; -import com.sap.cloudfoundry.client.facade.domain.ServiceOperation; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class PollServiceInProgressOperationsExecutionTest extends AsyncStepOperationTest { @@ -50,7 +49,7 @@ class PollServiceInProgressOperationsExecutionTest extends AsyncStepOperationTes public static Stream testPollStateExecution() { return Stream.of( -// @formatter:off + // @formatter:off // (0) With 2 services in progress: Arguments.of(List.of("service1","service2", "service3"), List.of(ServiceOperation.Type.DELETE, ServiceOperation.Type.CREATE, ServiceOperation.Type.DELETE), @@ -114,7 +113,7 @@ private void initializeParameters(List serviceNames, List instancesStates) { diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/RestartSubscribersStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/RestartSubscribersStepTest.java index 36ef8b748b..bb8307b367 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/RestartSubscribersStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/RestartSubscribersStepTest.java @@ -1,26 +1,25 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; -import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; -import org.cloudfoundry.multiapps.controller.process.variables.Variables; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.http.HttpStatus; - import com.sap.cloudfoundry.client.facade.CloudControllerClient; import com.sap.cloudfoundry.client.facade.CloudOperationException; import com.sap.cloudfoundry.client.facade.domain.CloudApplication; import com.sap.cloudfoundry.client.facade.domain.CloudSpace; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; +import org.cloudfoundry.multiapps.controller.process.variables.Variables; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.http.HttpStatus; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; class RestartSubscribersStepTest extends SyncFlowableStepTest { @@ -40,9 +39,9 @@ void testClientsForCorrectSpacesAreRequested() { // Then: Mockito.verify(clientProvider, Mockito.atLeastOnce()) - .getControllerClient(eq(USER_NAME), eq(FOO_SPACE_GUID.toString()), anyString()); + .getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(FOO_SPACE_GUID.toString()), anyString()); Mockito.verify(clientProvider, Mockito.atLeastOnce()) - .getControllerClient(eq(USER_NAME), eq(BAR_SPACE_GUID.toString()), anyString()); + .getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(BAR_SPACE_GUID.toString()), anyString()); } @Test @@ -52,9 +51,9 @@ void testSubscribersAreRestartedWhenClientExtensionsAreNotSupported() { CloudControllerClient clientForSpaceFoo = Mockito.mock(CloudControllerClient.class); CloudControllerClient clientForSpaceBar = Mockito.mock(CloudControllerClient.class); - Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(FOO_SPACE_GUID.toString()), anyString())) + Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(FOO_SPACE_GUID.toString()), anyString())) .thenReturn(clientForSpaceFoo); - Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(BAR_SPACE_GUID.toString()), anyString())) + Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(BAR_SPACE_GUID.toString()), anyString())) .thenReturn(clientForSpaceBar); // When: @@ -80,9 +79,9 @@ void testSubscribersAreRestartedWhenClientExtensionsAreSupported() { CloudControllerClient clientForSpaceFoo = Mockito.mock(CloudControllerClient.class); CloudControllerClient clientForSpaceBar = Mockito.mock(CloudControllerClient.class); - Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(FOO_SPACE_GUID.toString()), anyString())) + Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(FOO_SPACE_GUID.toString()), anyString())) .thenReturn(clientForSpaceFoo); - Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(BAR_SPACE_GUID.toString()), anyString())) + Mockito.when(clientProvider.getControllerClient(eq(USER_NAME), eq(USER_GUID), eq(BAR_SPACE_GUID.toString()), anyString())) .thenReturn(clientForSpaceBar); // When: diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/SyncFlowableStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/SyncFlowableStepTest.java index 5e9604785d..17ce837940 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/SyncFlowableStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/SyncFlowableStepTest.java @@ -1,9 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - import java.time.Duration; import java.util.Collections; import java.util.HashMap; @@ -12,6 +8,7 @@ import java.util.UUID; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; import org.cloudfoundry.client.v3.Metadata; import org.cloudfoundry.multiapps.common.test.Tester; @@ -53,13 +50,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; public abstract class SyncFlowableStepTest { private static final Logger LOGGER = LoggerFactory.getLogger(SyncFlowableStepTest.class); protected static final String USER_NAME = "dummy"; + protected static final String USER_GUID = "123-456-789"; protected static final String ORG_NAME = "org"; protected static final String SPACE_NAME = "space"; protected static final String SPACE_GUID = "spaceGuid"; @@ -120,8 +120,9 @@ public void initMocks() throws Exception { context.setVariable(Variables.SPACE_NAME, SPACE_NAME); context.setVariable(Variables.SPACE_GUID, SPACE_GUID); context.setVariable(Variables.USER, USER_NAME); + context.setVariable(Variables.USER_GUID, USER_GUID); context.setVariable(Variables.ORGANIZATION_NAME, ORG_NAME); - when(clientProvider.getControllerClient(any(), any(), any())).thenReturn(client); + when(clientProvider.getControllerClient(any(), any(), any(), any())).thenReturn(client); execution.setVariable("correlationId", getCorrelationId()); execution.setVariable("__TASK_ID", getTaskId()); prepareProcessEngineConfiguration(); diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStepTest.java index 983805162c..57e82b15ca 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/UpdateSubscribersStepTest.java @@ -1,16 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; @@ -20,6 +9,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudOperationException; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudSpace; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; import org.cloudfoundry.multiapps.common.test.TestUtil; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; @@ -46,14 +43,16 @@ import org.mockito.Mockito; import org.springframework.http.HttpStatus; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudOperationException; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudSpace; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class UpdateSubscribersStepTest extends SyncFlowableStepTest { @@ -83,7 +82,7 @@ class UpdateSubscribersStepTest extends SyncFlowableStepTest testExecute() { return Stream.of( -// @formatter:off + // @formatter:off // (0) A subscriber should be updated, because there are new published entries (there are no existing entries): Arguments.of("update-subscribers-step-input-00.json", "update-subscribers-step-output-00.json", 2, null), // (1) A subscriber should be updated: @@ -202,7 +201,7 @@ private void prepareClients() { private void prepareClientProvider(CloudSpace space, CloudControllerClient clientMock) { String spaceName = space.getName(); - when(clientProvider.getControllerClient(eq(USER), eq(spaceName), anyString())).thenReturn(clientMock); + when(clientProvider.getControllerClient(eq(USER), eq(USER_GUID), eq(spaceName), anyString())).thenReturn(clientMock); } private Map createClientsForSpacesOfSubscribedApps() { @@ -258,12 +257,18 @@ private void prepareConfigurationServices() { List targets = List.of(new CloudTarget(input.currentSpace.getOrganization() .getName(), input.currentSpace.getName())); - ConfigurationEntryQuery entryQueryMock = new MockBuilder<>(configurationEntryQuery).on(query -> query.providerNid(filter.getProviderNid())) - .on(query -> query.providerId(filter.getProviderId())) - .on(query -> query.version(filter.getProviderVersion())) - .on(query -> query.target(filter.getTargetSpace())) - .on(query -> query.requiredProperties(filter.getRequiredContent())) - .on(query -> query.visibilityTargets(targets)) + ConfigurationEntryQuery entryQueryMock = new MockBuilder<>(configurationEntryQuery).on( + query -> query.providerNid(filter.getProviderNid())) + .on(query -> query.providerId( + filter.getProviderId())) + .on(query -> query.version( + filter.getProviderVersion())) + .on(query -> query.target( + filter.getTargetSpace())) + .on(query -> query.requiredProperties( + filter.getRequiredContent())) + .on(query -> query.visibilityTargets( + targets)) .build(); doReturn(getAllEntries(subscriber)).when(entryQueryMock) .list(); diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationStagerTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationStagerTest.java index 8834337d93..3e9fc0365e 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationStagerTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationStagerTest.java @@ -1,15 +1,23 @@ package org.cloudfoundry.multiapps.controller.process.util; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.any; - import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.UUID; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudOperationException; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudBuild; +import com.sap.cloudfoundry.client.facade.domain.CloudPackage; +import com.sap.cloudfoundry.client.facade.domain.DropletInfo; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudBuild; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudPackage; +import com.sap.cloudfoundry.client.facade.domain.ImmutableDockerData; +import com.sap.cloudfoundry.client.facade.domain.ImmutableDropletInfo; +import com.sap.cloudfoundry.client.facade.domain.PackageState; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; @@ -25,19 +33,10 @@ import org.mockito.MockitoAnnotations; import org.springframework.http.HttpStatus; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudOperationException; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudBuild; -import com.sap.cloudfoundry.client.facade.domain.CloudPackage; -import com.sap.cloudfoundry.client.facade.domain.DropletInfo; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudBuild; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudPackage; -import com.sap.cloudfoundry.client.facade.domain.ImmutableDockerData; -import com.sap.cloudfoundry.client.facade.domain.ImmutableDropletInfo; -import com.sap.cloudfoundry.client.facade.domain.PackageState; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; class ApplicationStagerTest { @@ -62,7 +61,8 @@ public void setUp() throws Exception { .close(); this.context = new ProcessContext(MockDelegateExecution.createSpyInstance(), stepLogger, clientProvider); context.setVariable(Variables.USER, "whatever"); - Mockito.when(clientProvider.getControllerClient(Mockito.any(), Mockito.any(), Mockito.any())) + context.setVariable(Variables.USER_GUID, "123-456-789"); + Mockito.when(clientProvider.getControllerClient(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(client); this.applicationStager = new ApplicationStager(context); setCloudPackage(); @@ -297,8 +297,7 @@ void testStageIfUnprocessableEntityExceptionIsThrownSetPreviousBuildGuid() { .thenReturn(List.of(build)); applicationStager.stageApp(app); assertEquals(build.getMetadata() - .getGuid(), - context.getVariable(Variables.BUILD_GUID)); + .getGuid(), context.getVariable(Variables.BUILD_GUID)); } private void setCloudPackage() { diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationWaitAfterStopVariableGetterTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationWaitAfterStopVariableGetterTest.java index 23e907c7ec..1e627a4a00 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationWaitAfterStopVariableGetterTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ApplicationWaitAfterStopVariableGetterTest.java @@ -1,15 +1,13 @@ package org.cloudfoundry.multiapps.controller.process.util; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.UUID; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudApplicationExtended; import org.cloudfoundry.multiapps.controller.client.lib.domain.ImmutableCloudApplicationExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; @@ -24,11 +22,12 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.Mockito; - -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; import org.mockito.MockitoAnnotations; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + class ApplicationWaitAfterStopVariableGetterTest { private static final String APP_NAME = "app-name"; @@ -49,10 +48,11 @@ void setup() throws Exception { .close(); Mockito.when(client.getApplicationEnvironment(Mockito.any(UUID.class))) .thenReturn(Collections.emptyMap()); - Mockito.when(clientProvider.getControllerClient(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + Mockito.when(clientProvider.getControllerClient(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) .thenReturn(client); context = new ProcessContext(MockDelegateExecution.createSpyInstance(), stepLogger, clientProvider); context.setVariable(Variables.USER, "user"); + context.setVariable(Variables.USER_GUID, "123-456-789"); context.setVariable(Variables.SPACE_GUID, "guid"); context.setVariable(Variables.CORRELATION_ID, "id"); delayVariableGetter = new ApplicationWaitAfterStopVariableGetter(); diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ServiceRemoverTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ServiceRemoverTest.java index 455b16d80d..8526b20b23 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ServiceRemoverTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ServiceRemoverTest.java @@ -1,18 +1,18 @@ package org.cloudfoundry.multiapps.controller.process.util; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.text.MessageFormat; import java.util.UUID; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.CloudControllerException; +import com.sap.cloudfoundry.client.facade.CloudOperationException; +import com.sap.cloudfoundry.client.facade.CloudServiceBrokerException; +import com.sap.cloudfoundry.client.facade.domain.CloudApplication; +import com.sap.cloudfoundry.client.facade.domain.CloudServiceInstance; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudServiceInstance; import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; @@ -29,19 +29,20 @@ import org.mockito.MockitoAnnotations; import org.springframework.http.HttpStatus; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.CloudControllerException; -import com.sap.cloudfoundry.client.facade.CloudOperationException; -import com.sap.cloudfoundry.client.facade.CloudServiceBrokerException; -import com.sap.cloudfoundry.client.facade.domain.CloudApplication; -import com.sap.cloudfoundry.client.facade.domain.CloudServiceInstance; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudApplication; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudServiceInstance; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class ServiceRemoverTest { private static final String TEST_USER = "test-user"; + private static final String TEST_USER_GUID = UUID.randomUUID() + .toString(); private static final String TEST_SPACE = "test-space"; private static final String SERVICE_NAME = "test-service"; private static final String SERVICE_LABEL = "test-label"; @@ -70,9 +71,10 @@ void setUp() throws Exception { } private void prepareExecution() { - when(clientProvider.getControllerClient(anyString(), anyString(), any())).thenReturn(client); + when(clientProvider.getControllerClient(anyString(), anyString(), anyString(), any())).thenReturn(client); context = new ProcessContext(execution, stepLogger, clientProvider); context.setVariable(Variables.USER, TEST_USER); + context.setVariable(Variables.USER_GUID, TEST_USER_GUID); execution.setVariable(org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SPACE_ID, TEST_SPACE); } @@ -105,9 +107,9 @@ void testControllerErrorHandling(HttpStatus httpStatusToThrow, Class serviceRemover.deleteService(context, serviceInstance)); assertEquals(expectedExceptionType, wrappedException.getCause() .getClass()); - assertEquals(MessageFormat.format(Messages.ERROR_DELETING_SERVICE, SERVICE_NAME, SERVICE_LABEL, SERVICE_PLAN, - expectedExceptionMessage), - wrappedException.getMessage()); + assertEquals( + MessageFormat.format(Messages.ERROR_DELETING_SERVICE, SERVICE_NAME, SERVICE_LABEL, SERVICE_PLAN, expectedExceptionMessage), + wrappedException.getMessage()); } @Test diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImpl.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImpl.java index 535377ae9a..87a1335d65 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImpl.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImpl.java @@ -5,9 +5,10 @@ import java.util.Optional; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.CloudRoute; import jakarta.inject.Inject; import jakarta.inject.Named; - import org.cloudfoundry.multiapps.common.ConflictException; import org.cloudfoundry.multiapps.common.NotFoundException; import org.cloudfoundry.multiapps.controller.api.MtasApiService; @@ -31,9 +32,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.CloudRoute; - @Named public class MtasApiServiceImpl implements MtasApiService { @@ -91,9 +89,8 @@ public ResponseEntity> getMtas(String spaceGuid, String namespace, Str CloudControllerClient client = getCloudFoundryClient(spaceGuid); Optional optionalDeployedMta = deployedMtaDetector.detectDeployedMtaByNameAndNamespace(name, namespace, client); - DeployedMta deployedMta = optionalDeployedMta.orElseThrow(() -> new NotFoundException(Messages.SPECIFIC_MTA_NOT_FOUND, - name, - namespace)); + DeployedMta deployedMta = optionalDeployedMta.orElseThrow( + () -> new NotFoundException(Messages.SPECIFIC_MTA_NOT_FOUND, name, namespace)); return ResponseEntity.ok() .body(Arrays.asList(getMta(deployedMta, client))); @@ -133,7 +130,7 @@ protected ResponseEntity> getMtasByName(String spaceGuid, String name) private CloudControllerClient getCloudFoundryClient(String spaceGuid) { UserInfo userInfo = SecurityContextUtil.getUserInfo(); - return clientProvider.getControllerClientWithNoCorrelation(userInfo.getName(), spaceGuid); + return clientProvider.getControllerClientWithNoCorrelation(userInfo.getName(), userInfo.getId(), spaceGuid); } private List getMtas(List deployedMtas, CloudControllerClient client) { diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImpl.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImpl.java index 2dc6d0efed..856452528d 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImpl.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImpl.java @@ -15,11 +15,13 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.domain.CloudOrganization; +import com.sap.cloudfoundry.client.facade.domain.CloudSpace; +import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.persistence.NoResultException; import jakarta.servlet.http.HttpServletRequest; - import org.apache.commons.collections4.ListUtils; import org.cloudfoundry.multiapps.common.ContentException; import org.cloudfoundry.multiapps.common.NotFoundException; @@ -62,10 +64,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.server.ResponseStatusException; -import com.sap.cloudfoundry.client.facade.domain.CloudOrganization; -import com.sap.cloudfoundry.client.facade.domain.CloudSpace; -import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; - @Named public class OperationsApiServiceImpl implements OperationsApiService { @@ -155,7 +153,7 @@ public ResponseEntity startOperation(HttpServletRequest request, Stri String processDefinitionKey = operationsHelper.getProcessDefinitionKey(operation); Set predefinedParameters = operationMetadataMapper.getOperationMetadata(operation.getProcessType()) .getParameters(); - operation = addServiceParameters(operation, spaceGuid, user); + operation = addServiceParameters(operation, spaceGuid, user, SecurityContextUtil.getUserGuid()); operation = addParameterValues(operation, predefinedParameters); ensureRequiredParametersSet(operation, predefinedParameters); ProcessInstance processInstance = flowableFacade.startProcess(processDefinitionKey, operation.getParameters()); @@ -247,7 +245,7 @@ private List getAvailableActions(Operation operation) { throw new IllegalStateException(MessageFormat.format("State \"{0}\" not recognized!", operation.getState())); } - private Operation addServiceParameters(Operation operation, String spaceGuid, String user) { + private Operation addServiceParameters(Operation operation, String spaceGuid, String user, String userGuid) { Map parameters = new HashMap<>(operation.getParameters()); CloudSpaceClient client = getSpaceClient(); @@ -258,6 +256,7 @@ private Operation addServiceParameters(Operation operation, String spaceGuid, St parameters.put(Constants.VARIABLE_NAME_SERVICE_ID, processDefinitionKey); parameters.put(Variables.USER.getName(), user); + parameters.put(Variables.USER_GUID.getName(), userGuid); parameters.put(Variables.SPACE_NAME.getName(), space.getName()); parameters.put(Variables.SPACE_GUID.getName(), spaceGuid); parameters.put(Variables.ORGANIZATION_NAME.getName(), organization.getName()); @@ -285,7 +284,8 @@ private void ensureRequiredParametersSet(Operation operation, Set operationParameters = operation.getParameters(); Set requiredParameters = getRequiredParameters(predefinedParameters); List missingRequiredParameters = requiredParameters.stream() - .filter(parameter -> !operationParameters.containsKey(parameter.getId())) + .filter(parameter -> !operationParameters.containsKey( + parameter.getId())) .collect(Collectors.toList()); if (!missingRequiredParameters.isEmpty()) { throw new ContentException("Required parameters " + getParameterIds(missingRequiredParameters) + " are not set!"); @@ -318,7 +318,7 @@ private String getAuthenticatedUser(HttpServletRequest request) { private CloudSpaceClient getSpaceClient() { UserInfo userInfo = SecurityContextUtil.getUserInfo(); - return clientFactory.createSpaceClient(tokenService.getToken(userInfo.getName())); + return clientFactory.createSpaceClient(tokenService.getToken(userInfo.getName(), userInfo.getId())); } private List getOperationMessages(Operation operation) { diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/resources/ConfigurationEntriesResource.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/resources/ConfigurationEntriesResource.java index 26e555a773..c30965f665 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/resources/ConfigurationEntriesResource.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/resources/ConfigurationEntriesResource.java @@ -1,5 +1,8 @@ package org.cloudfoundry.multiapps.controller.web.resources; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.cloudfoundry.multiapps.controller.core.auditlogging.MtaConfigurationPurgerAuditLog; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientProvider; @@ -18,11 +21,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; - -import jakarta.inject.Inject; -import jakarta.inject.Named; - @RestController @RequestMapping(value = Constants.Resources.CONFIGURATION_ENTRIES) public class ConfigurationEntriesResource { @@ -51,17 +49,15 @@ public class ConfigurationEntriesResource { public ResponseEntity purgeConfigurationRegistry(@RequestParam(REQUEST_PARAM_ORGANIZATION) String organization, @RequestParam(REQUEST_PARAM_SPACE) String space) { UserInfo user = SecurityContextUtil.getUserInfo(); - var spaceClient = clientFactory.createSpaceClient(tokenService.getToken(user.getName())); + var spaceClient = clientFactory.createSpaceClient(tokenService.getToken(user.getName(), user.getId())); var cloudSpace = spaceClient.getSpace(organization, space); - CloudControllerClient client = clientProvider.getControllerClientWithNoCorrelation(user.getName(), cloudSpace.getGuid() - .toString()); - MtaConfigurationPurger configurationPurger = new MtaConfigurationPurger(client, - spaceClient, - configurationEntryService, - configurationSubscriptionService, - mtaMetadataParser, + CloudControllerClient client = clientProvider.getControllerClientWithNoCorrelation(user.getName(), user.getId(), + cloudSpace.getGuid() + .toString()); + MtaConfigurationPurger configurationPurger = new MtaConfigurationPurger(client, spaceClient, configurationEntryService, + configurationSubscriptionService, mtaMetadataParser, mtaConfigurationPurgerAuditLog); configurationPurger.purge(organization, space); return ResponseEntity.status(HttpStatus.NO_CONTENT) diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationChecker.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationChecker.java index 6f4407fef9..75c2456bda 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationChecker.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationChecker.java @@ -5,10 +5,13 @@ import java.util.Set; import java.util.UUID; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import com.sap.cloudfoundry.client.facade.domain.UserRole; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.oauth2.TokenFactory; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.servlet.http.HttpServletRequest; - import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.controller.core.Messages; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; @@ -26,11 +29,6 @@ import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; -import com.sap.cloudfoundry.client.facade.CloudCredentials; -import com.sap.cloudfoundry.client.facade.domain.UserRole; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; -import com.sap.cloudfoundry.client.facade.oauth2.TokenFactory; - @Named public class AuthorizationChecker implements DisposableBean { @@ -94,7 +92,7 @@ boolean checkPermissions(UserInfo userInfo, String orgName, String spaceName, bo if (hasAdminScope(userInfo)) { return true; } - var userToken = tokenService.getToken(userInfo.getName()); + var userToken = tokenService.getToken(userInfo.getName(), userInfo.getId()); var spaceClient = clientFactory.createSpaceClient(userToken); var space = spaceClient.getSpace(orgName, spaceName); @@ -111,7 +109,7 @@ boolean checkPermissions(UserInfo userInfo, String spaceId, boolean readOnly) { if (hasAdminScope(userInfo)) { return true; } - var userToken = tokenService.getToken(userInfo.getName()); + var userToken = tokenService.getToken(userInfo.getName(), userInfo.getId()); CfRolesGetter rolesGetter = getRolesGetter(userToken); UUID userGuid = UUID.fromString(userInfo.getId()); UUID spaceGuid = convertSpaceIdToUUID(spaceId); diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGenerator.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGenerator.java index 0941696d6d..d84338f395 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGenerator.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGenerator.java @@ -4,7 +4,10 @@ import java.util.Base64; import java.util.Optional; -import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; +import com.sap.cloudfoundry.client.facade.CloudCredentials; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; +import com.sap.cloudfoundry.client.facade.util.RestUtil; import org.cloudfoundry.multiapps.controller.core.security.token.parsers.TokenParserChain; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; @@ -14,11 +17,6 @@ import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.authentication.InternalAuthenticationServiceException; -import com.sap.cloudfoundry.client.facade.CloudCredentials; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; -import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; -import com.sap.cloudfoundry.client.facade.util.RestUtil; - public class BasicTokenGenerator extends TokenGenerator { private final RestUtil restUtil = createRestUtil(); @@ -43,14 +41,14 @@ public OAuth2AccessTokenWithAdditionalInfo generate(String tokenString) { applicationConfiguration.shouldSkipSslValidation()); String[] usernameWithPassword = getUsernameWithPassword(tokenString); oauthClient.init(new CloudCredentials(usernameWithPassword[0], usernameWithPassword[1])); - Optional accessToken = tokenReuser.getTokenWithExpirationAfter(usernameWithPassword[0], - Constants.BASIC_TOKEN_RETENTION_TIME_IN_SECONDS); + OAuth2AccessTokenWithAdditionalInfo oAuth2AccessTokenWithAdditionalInfo = oauthClient.getToken(); + Optional accessToken = tokenReuser.getTokenWithExpirationAfterOrReuseCurrent( + extractUserGuid(oAuth2AccessTokenWithAdditionalInfo), Constants.BASIC_TOKEN_RETENTION_TIME_IN_SECONDS, + oAuth2AccessTokenWithAdditionalInfo); if (accessToken.isPresent()) { return tokenParserChain.parse(new String(accessToken.get() - .getValue(), - StandardCharsets.UTF_8)); + .getValue(), StandardCharsets.UTF_8)); } - OAuth2AccessTokenWithAdditionalInfo oAuth2AccessTokenWithAdditionalInfo = oauthClient.getToken(); storeAccessToken(buildAccessToken(oAuth2AccessTokenWithAdditionalInfo), extractUserGuid(oAuth2AccessTokenWithAdditionalInfo)); return oAuth2AccessTokenWithAdditionalInfo; } @@ -69,8 +67,7 @@ String[] getUsernameWithPassword(String tokenString) { private String decodeToken(String tokenString) { try { return new String(Base64.getDecoder() - .decode(tokenString), - StandardCharsets.UTF_8); + .decode(tokenString), StandardCharsets.UTF_8); } catch (IllegalArgumentException e) { throw new InternalAuthenticationServiceException(e.getMessage(), e); } diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/OauthTokenGenerator.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/OauthTokenGenerator.java index b66b021f73..7a69830e4b 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/OauthTokenGenerator.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/OauthTokenGenerator.java @@ -5,6 +5,7 @@ import java.time.Instant; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import org.cloudfoundry.multiapps.controller.core.security.token.parsers.TokenParserChain; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; import org.cloudfoundry.multiapps.controller.persistence.services.AccessTokenService; @@ -13,8 +14,6 @@ import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; - public class OauthTokenGenerator extends TokenGenerator { private final TokenParserChain tokenParserChain; @@ -30,14 +29,13 @@ public OauthTokenGenerator(AccessTokenService accessTokenService, TokenParserCha public OAuth2AccessTokenWithAdditionalInfo generate(String tokenString) { OAuth2AccessTokenWithAdditionalInfo oAuth2AccessTokenWithAdditionalInfo = tokenParserChain.parse(tokenString); validateTokenExpiration(oAuth2AccessTokenWithAdditionalInfo); - String username = extractUsername(oAuth2AccessTokenWithAdditionalInfo); - Optional accessToken = tokenReuser.getTokenWithExpirationAfterOrReuseCurrent(username, + String userGuid = extractUserGuid(oAuth2AccessTokenWithAdditionalInfo); + Optional accessToken = tokenReuser.getTokenWithExpirationAfterOrReuseCurrent(userGuid, Constants.OAUTH_TOKEN_RETENTION_TIME_IN_SECONDS, oAuth2AccessTokenWithAdditionalInfo); if (accessToken.isPresent()) { return tokenParserChain.parse(new String(accessToken.get() - .getValue(), - StandardCharsets.UTF_8)); + .getValue(), StandardCharsets.UTF_8)); } storeAccessToken(buildAccessToken(oAuth2AccessTokenWithAdditionalInfo), extractUserGuid(oAuth2AccessTokenWithAdditionalInfo)); return oAuth2AccessTokenWithAdditionalInfo; @@ -47,10 +45,9 @@ private void validateTokenExpiration(OAuth2AccessTokenWithAdditionalInfo oAuth2A if (oAuth2AccessTokenWithAdditionalInfo.getOAuth2AccessToken() .getExpiresAt() .isBefore(Instant.now())) { - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, - MessageFormat.format(Messages.THE_TOKEN_HAS_EXPIRED_ON_0, - oAuth2AccessTokenWithAdditionalInfo.getOAuth2AccessToken() - .getExpiresAt())); + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, MessageFormat.format(Messages.THE_TOKEN_HAS_EXPIRED_ON_0, + oAuth2AccessTokenWithAdditionalInfo.getOAuth2AccessToken() + .getExpiresAt())); } } } diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenGenerator.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenGenerator.java index 2942d234c0..0004e1bffd 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenGenerator.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenGenerator.java @@ -1,13 +1,12 @@ package org.cloudfoundry.multiapps.controller.web.util; -import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.EXPIRES_AT_KEY; - import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; import org.cloudfoundry.multiapps.controller.persistence.model.ImmutableAccessToken; @@ -16,7 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.EXPIRES_AT_KEY; public abstract class TokenGenerator { @@ -29,8 +28,8 @@ protected TokenGenerator(AccessTokenService accessTokenService) { private static final Logger LOGGER = LoggerFactory.getLogger(TokenGenerator.class); public void storeAccessToken(AccessToken accessToken, String userGuid) { - LOGGER.info(MessageFormat.format(Messages.STORING_TOKEN_FOR_USER_WITH_GUID_0_WHICH_EXPIRES_AT_1, userGuid, - accessToken.getExpiresAt())); + LOGGER.info( + MessageFormat.format(Messages.STORING_TOKEN_FOR_USER_WITH_GUID_0_WHICH_EXPIRES_AT_1, userGuid, accessToken.getExpiresAt())); accessTokenService.add(accessToken); } @@ -43,6 +42,7 @@ protected AccessToken buildAccessToken(OAuth2AccessTokenWithAdditionalInfo oAuth .getBytes(StandardCharsets.UTF_8)) .username(extractUsername(oAuth2AccessTokenWithAdditionalInfo)) .expiresAt(calculateAccessTokenExpirationDate(oAuth2AccessTokenWithAdditionalInfo)) + .userGuid(extractUserGuid(oAuth2AccessTokenWithAdditionalInfo)) .build(); } @@ -53,7 +53,7 @@ protected String extractUsername(OAuth2AccessTokenWithAdditionalInfo token) { protected String extractUserGuid(OAuth2AccessTokenWithAdditionalInfo token) { return (String) token.getAdditionalInfo() - .get(TokenProperties.USER_ID_KEY); + .get(TokenProperties.USER_ID_KEY); } private LocalDateTime calculateAccessTokenExpirationDate(OAuth2AccessTokenWithAdditionalInfo oAuth2AccessTokenWithAdditionalInfo) { diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuser.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuser.java index 71878a9416..e47f76f850 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuser.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuser.java @@ -7,14 +7,12 @@ import java.util.List; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import jakarta.inject.Named; - import org.cloudfoundry.multiapps.controller.persistence.OrderDirection; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; import org.cloudfoundry.multiapps.controller.persistence.services.AccessTokenService; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; - @Named public class TokenReuser { @@ -24,8 +22,9 @@ public TokenReuser(AccessTokenService accessTokenService) { this.accessTokenService = accessTokenService; } - public Optional getTokenWithExpirationAfter(String username, long expiresAfterInSeconds) { - List accessTokens = getTokensOrderedByExpiresAt(username); + public Optional getTokenWithExpirationAfterOrReuseCurrent(String userGuid, long expiresAfterInSeconds, + OAuth2AccessTokenWithAdditionalInfo currentToken) { + List accessTokens = getTokensOrderedByExpiresAtBasedOnUserGuid(userGuid); if (accessTokens.isEmpty()) { return Optional.empty(); } @@ -33,12 +32,17 @@ public Optional getTokenWithExpirationAfter(String username, long e if (shouldUseLatestToken(accessTokens, dateAfter)) { return Optional.of(accessTokens.get(0)); } + LocalDateTime currentTokenExpirationDate = getExpirationDate(currentToken); + if (currentTokenExpirationDate.equals(accessTokens.get(0) + .getExpiresAt())) { + return Optional.of(accessTokens.get(0)); + } return Optional.empty(); } - private List getTokensOrderedByExpiresAt(String username) { + private List getTokensOrderedByExpiresAtBasedOnUserGuid(String userGuid) { return accessTokenService.createQuery() - .username(username) + .userGuid(userGuid) .orderByExpiresAt(OrderDirection.DESCENDING) .list(); } @@ -55,28 +59,9 @@ private boolean shouldUseLatestToken(List accessTokens, LocalDateTi .isAfter(dateAfter); } - public Optional getTokenWithExpirationAfterOrReuseCurrent(String username, long expiresAfterInSeconds, - OAuth2AccessTokenWithAdditionalInfo currentToken) { - List accessTokens = getTokensOrderedByExpiresAt(username); - if (accessTokens.isEmpty()) { - return Optional.empty(); - } - LocalDateTime dateAfter = calculateDateAfter(expiresAfterInSeconds); - if (shouldUseLatestToken(accessTokens, dateAfter)) { - return Optional.of(accessTokens.get(0)); - } - LocalDateTime currentTokenExpirationDate = getExpirationDate(currentToken); - if (currentTokenExpirationDate.equals(accessTokens.get(0) - .getExpiresAt())) { - return Optional.of(accessTokens.get(0)); - } - return Optional.empty(); - } - private LocalDateTime getExpirationDate(OAuth2AccessTokenWithAdditionalInfo currentToken) { return LocalDateTime.ofInstant(currentToken.getOAuth2AccessToken() - .getExpiresAt(), - ZoneId.systemDefault()); + .getExpiresAt(), ZoneId.systemDefault()); } } diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImplTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImplTest.java index 7b10d59167..ba933ce7e6 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImplTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/MtasApiServiceImplTest.java @@ -1,8 +1,5 @@ package org.cloudfoundry.multiapps.controller.web.api.impl; -import static org.cloudfoundry.multiapps.controller.core.util.SecurityUtil.USER_INFO; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.util.Collections; import java.util.List; import java.util.Map; @@ -10,6 +7,9 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.fasterxml.jackson.core.type.TypeReference; +import com.sap.cloudfoundry.client.facade.CloudControllerClient; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; import org.cloudfoundry.multiapps.common.ConflictException; import org.cloudfoundry.multiapps.common.NotFoundException; import org.cloudfoundry.multiapps.common.test.TestUtil; @@ -44,9 +44,8 @@ import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.core.user.OAuth2User; -import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloudfoundry.client.facade.CloudControllerClient; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import static org.cloudfoundry.multiapps.controller.core.util.SecurityUtil.USER_INFO; +import static org.junit.jupiter.api.Assertions.assertEquals; class MtasApiServiceImplTest { @@ -185,7 +184,7 @@ void testGetMtaNotUniqueByName() { } private void mockClient() { - UserInfo userInfo = new UserInfo(null, USER_NAME, null); + UserInfo userInfo = new UserInfo("123-456-789", USER_NAME, null); OAuth2AuthenticationToken auth = Mockito.mock(OAuth2AuthenticationToken.class); Map attributes = Map.of(USER_INFO, userInfo); OAuth2User principal = Mockito.mock(OAuth2User.class); @@ -199,7 +198,7 @@ private void mockClient() { .thenReturn(auth); Mockito.when(client.getApplicationRoutes(Mockito.any(UUID.class))) .thenReturn(Collections.emptyList()); - Mockito.when(clientProvider.getControllerClientWithNoCorrelation(Mockito.anyString(), Mockito.anyString())) + Mockito.when(clientProvider.getControllerClientWithNoCorrelation(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) .thenReturn(client); } diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImplTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImplTest.java index 0add1db458..33402893ff 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImplTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImplTest.java @@ -1,10 +1,5 @@ package org.cloudfoundry.multiapps.controller.web.api.impl; -import static org.cloudfoundry.multiapps.controller.core.util.SecurityUtil.USER_INFO; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.security.Principal; import java.util.Collections; import java.util.LinkedList; @@ -14,15 +9,19 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; import jakarta.persistence.NoResultException; import jakarta.servlet.http.HttpServletRequest; - import org.cloudfoundry.multiapps.common.ContentException; import org.cloudfoundry.multiapps.common.NotFoundException; import org.cloudfoundry.multiapps.controller.api.model.ImmutableOperation; import org.cloudfoundry.multiapps.controller.api.model.Operation; import org.cloudfoundry.multiapps.controller.api.model.ProcessType; -import org.cloudfoundry.multiapps.controller.core.auditlogging.AuditLoggingFacade; +import org.cloudfoundry.multiapps.controller.client.util.TokenProperties; import org.cloudfoundry.multiapps.controller.core.auditlogging.OperationsApiServiceAuditLog; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; @@ -54,10 +53,10 @@ import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.web.server.ResponseStatusException; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; -import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; +import static org.cloudfoundry.multiapps.controller.core.util.SecurityUtil.USER_INFO; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class OperationsApiServiceImplTest { @@ -97,6 +96,7 @@ class OperationsApiServiceImplTest { private static final String SPACE_NAME = "spaceName"; private static final String EXAMPLE_USER = "someUser123"; + private static final String USER_GUID = "123-456-789"; private static final String FINISHED_PROCESS = "1"; private static final String RUNNING_PROCESS = "2"; @@ -128,8 +128,7 @@ public void initialize() throws Exception { void testGetOperations() { ResponseEntity> response = operationsApiService.getOperations(SPACE_GUID, null, List.of(Operation.State.FINISHED.toString(), - Operation.State.ABORTED.toString()), - 1); + Operation.State.ABORTED.toString()), 1); List operations = response.getBody(); assertEquals(2, operations.size()); @@ -141,9 +140,8 @@ void testGetOperations() { @Test void testGetOperationsNotFound() { - ResponseEntity> response = operationsApiService.getOperations(SPACE_GUID, MTA_ID, - Collections.singletonList(Operation.State.ACTION_REQUIRED.toString()), - 1); + ResponseEntity> response = operationsApiService.getOperations(SPACE_GUID, MTA_ID, Collections.singletonList( + Operation.State.ACTION_REQUIRED.toString()), 1); List operations = response.getBody(); assertTrue(operations.isEmpty()); @@ -293,9 +291,8 @@ private void mockFlowableFacade() { } private void mockClientProvider(String user) { - org.cloudfoundry.multiapps.controller.core.util.UserInfo userInfo = new org.cloudfoundry.multiapps.controller.core.util.UserInfo(null, - user, - null); + org.cloudfoundry.multiapps.controller.core.util.UserInfo userInfo = new org.cloudfoundry.multiapps.controller.core.util.UserInfo( + USER_GUID, user, new OAuth2AccessTokenWithAdditionalInfo(null, Map.of(TokenProperties.USER_ID_KEY, USER_GUID))); OAuth2AuthenticationToken auth = Mockito.mock(OAuth2AuthenticationToken.class); Map attributes = Map.of(USER_INFO, userInfo); OAuth2User principal = Mockito.mock(OAuth2User.class); @@ -303,7 +300,8 @@ private void mockClientProvider(String user) { .thenReturn(attributes); Mockito.when(auth.getPrincipal()) .thenReturn(principal); - org.springframework.security.core.context.SecurityContext securityContextMock = Mockito.mock(org.springframework.security.core.context.SecurityContext.class); + org.springframework.security.core.context.SecurityContext securityContextMock = Mockito.mock( + org.springframework.security.core.context.SecurityContext.class); SecurityContextHolder.setContext(securityContextMock); Mockito.when(securityContextMock.getAuthentication()) .thenReturn(auth); @@ -355,33 +353,33 @@ private void setupOperationServiceMock() { .thenReturn(operationQuery); Mockito.doAnswer(invocation -> { - processId = (String) invocation.getArguments()[0]; - return operationQuery; - }) + processId = (String) invocation.getArguments()[0]; + return operationQuery; + }) .when(operationQuery) .processId(Mockito.anyString()); Mockito.doAnswer(invocation -> { - Optional foundOperation = operations.stream() - .filter(operation -> operation.getProcessId() - .equals(processId)) - .findFirst(); - if (!foundOperation.isPresent()) { - throw new NoResultException("not found"); - } - return foundOperation.get(); - }) + Optional foundOperation = operations.stream() + .filter(operation -> operation.getProcessId() + .equals(processId)) + .findFirst(); + if (!foundOperation.isPresent()) { + throw new NoResultException("not found"); + } + return foundOperation.get(); + }) .when(operationQuery) .singleResult(); Mockito.doAnswer(invocation -> { - operationStatesToFilter = (List) invocation.getArguments()[0]; - return operationQuery; - }) + operationStatesToFilter = (List) invocation.getArguments()[0]; + return operationQuery; + }) .when(operationQuery) .withStateAnyOf(Mockito.anyList()); Mockito.doAnswer(invocation -> operations.stream() - .filter(operation -> operationStatesToFilter == null - || operationStatesToFilter.contains(operation.getState())) + .filter(operation -> operationStatesToFilter == null || operationStatesToFilter.contains( + operation.getState())) .collect(Collectors.toList())) .when(operationQuery) .list(); diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationCheckerTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationCheckerTest.java index 338c6a7acb..286fca6606 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationCheckerTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/security/AuthorizationCheckerTest.java @@ -1,19 +1,21 @@ package org.cloudfoundry.multiapps.controller.web.security; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.EnumSet; -import java.util.UUID; import java.util.Set; +import java.util.UUID; import java.util.stream.Stream; +import com.sap.cloudfoundry.client.facade.domain.CloudOrganization; +import com.sap.cloudfoundry.client.facade.domain.CloudSpace; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; +import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; +import com.sap.cloudfoundry.client.facade.domain.UserRole; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.clients.CfRolesGetter; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; @@ -33,14 +35,11 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.server.ResponseStatusException; -import com.sap.cloudfoundry.client.facade.domain.CloudOrganization; -import com.sap.cloudfoundry.client.facade.domain.CloudSpace; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudMetadata; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudOrganization; -import com.sap.cloudfoundry.client.facade.domain.ImmutableCloudSpace; -import com.sap.cloudfoundry.client.facade.domain.UserRole; -import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; class AuthorizationCheckerTest { @@ -75,40 +74,40 @@ protected CfRolesGetter getRolesGetter(OAuth2AccessTokenWithAdditionalInfo token static Stream checkPermissionsUsingNamesTest() { return Stream.of( - // (0) User has a space developer role and has access - Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), true), - // (1) User has org user & manager roles and no access - Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), false), - // (2) User has a space manager & developer roles and has access - Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER, UserRole.SPACE_DEVELOPER), true), - // (3) User does not have any roles and no access - Arguments.of(Collections.emptySet(), false)); + // (0) User has a space developer role and has access + Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), true), + // (1) User has org user & manager roles and no access + Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), false), + // (2) User has a space manager & developer roles and has access + Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER, UserRole.SPACE_DEVELOPER), true), + // (3) User does not have any roles and no access + Arguments.of(Collections.emptySet(), false)); } static Stream checkPermissionUsingGuidsTest() { return Stream.of( - // (0) User has a space developer role and executes a non read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), false, true), - // (1) User does not have any roles and executes a non read-only request - Arguments.of(Collections.emptySet(), false, false), - // (2) User does not have any roles and executes a read-only request - Arguments.of(Collections.emptySet(), true, false), - // (3) User has a space auditor role and executes a non read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR), false, false), - // (4) User has a space manager role and executes a non read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER), false, false), - // (5) User has a space auditor role and executes a read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR), true, true), - // (6) User has a space manager role and executes a read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER), true, true), - // (7) User has a space developer role and executes a read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), true, true), - // (8) User has a space auditor & manager roles and executes a read-only request - Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR, UserRole.SPACE_MANAGER), true, true), - // (9) User has a org user & manager roles and executes a read-only request - Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), true, false), - // (10) User has a org user & manager roles and executes a read-only request - Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), false, false)); + // (0) User has a space developer role and executes a non read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), false, true), + // (1) User does not have any roles and executes a non read-only request + Arguments.of(Collections.emptySet(), false, false), + // (2) User does not have any roles and executes a read-only request + Arguments.of(Collections.emptySet(), true, false), + // (3) User has a space auditor role and executes a non read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR), false, false), + // (4) User has a space manager role and executes a non read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER), false, false), + // (5) User has a space auditor role and executes a read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR), true, true), + // (6) User has a space manager role and executes a read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_MANAGER), true, true), + // (7) User has a space developer role and executes a read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_DEVELOPER), true, true), + // (8) User has a space auditor & manager roles and executes a read-only request + Arguments.of(EnumSet.of(UserRole.SPACE_AUDITOR, UserRole.SPACE_MANAGER), true, true), + // (9) User has a org user & manager roles and executes a read-only request + Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), true, false), + // (10) User has a org user & manager roles and executes a read-only request + Arguments.of(EnumSet.of(UserRole.ORGANIZATION_USER, UserRole.ORGANIZATION_MANAGER), false, false)); } @ParameterizedTest @@ -152,7 +151,7 @@ void testCheckPermissionsWithNonUUIDSpaceIDString() { private void setUpMocks(Set spaceRoles, Exception exception) { var token = Mockito.mock(OAuth2AccessTokenWithAdditionalInfo.class); - when(tokenService.getToken(anyString())).thenReturn(token); + when(tokenService.getToken(anyString(), anyString())).thenReturn(token); if (exception != null) { when(rolesGetter.getRoles(SPACE_ID, USER_ID)).thenThrow(exception); } else { @@ -185,11 +184,13 @@ private CloudSpace getCloudSpace(CloudOrganization organization) { } private UserInfo getUserInfo() { - OAuth2AccessTokenWithAdditionalInfo accessToken = new OAuth2AccessTokenWithAdditionalInfo(new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, - "token_value", - Instant.now(), - Instant.now().plus(5, ChronoUnit.MINUTES)), - Collections.emptyMap()); + OAuth2AccessTokenWithAdditionalInfo accessToken = new OAuth2AccessTokenWithAdditionalInfo( + new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, + "token_value", + Instant.now(), + Instant.now() + .plus(5, ChronoUnit.MINUTES)), + Collections.emptyMap()); return new UserInfo(USER_ID.toString(), USERNAME, accessToken); } diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGeneratorTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGeneratorTest.java index 72c9ac614a..51d8bcf056 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGeneratorTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/BasicTokenGeneratorTest.java @@ -1,17 +1,13 @@ package org.cloudfoundry.multiapps.controller.web.util; -import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.EXPIRES_AT_KEY; -import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.USER_NAME; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; - import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; +import com.sap.cloudfoundry.client.facade.util.RestUtil; import org.cloudfoundry.multiapps.controller.core.security.token.parsers.TokenParserChain; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; @@ -26,9 +22,12 @@ import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.oauth2.core.OAuth2AccessToken; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; -import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient; -import com.sap.cloudfoundry.client.facade.util.RestUtil; +import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.EXPIRES_AT_KEY; +import static com.sap.cloudfoundry.client.facade.oauth2.TokenFactory.USER_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; class BasicTokenGeneratorTest { @@ -93,11 +92,16 @@ void testParseTokenNoCurrentOauthToken() { @Test void testParseTokenWithCurrentOauthToken() { AccessToken mockedAccessToken = Mockito.mock(AccessToken.class); + OAuth2AccessTokenWithAdditionalInfo oAuth2AccessTokenWithAdditionalInfo = Mockito.mock(OAuth2AccessTokenWithAdditionalInfo.class); Mockito.when(mockedAccessToken.getValue()) .thenReturn("token_value".getBytes(StandardCharsets.UTF_8)); Optional optionalAccessToken = Optional.of(mockedAccessToken); - Mockito.when(tokenReuser.getTokenWithExpirationAfter(any(), anyLong())) + Mockito.when(tokenReuser.getTokenWithExpirationAfterOrReuseCurrent(any(), anyLong(), any())) .thenReturn(optionalAccessToken); + Mockito.when(oAuth2AccessTokenWithAdditionalInfo.getAdditionalInfo()) + .thenReturn(Map.of("user_id", "1234")); + Mockito.when(oAuthClient.getToken()) + .thenReturn(oAuth2AccessTokenWithAdditionalInfo); basicTokenGenerator.generate(TOKEN_STRING); Mockito.verify(tokenParserChain) .parse(any()); diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuserTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuserTest.java index 13f5ae9470..cbdf30dc60 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuserTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/TokenReuserTest.java @@ -1,9 +1,5 @@ package org.cloudfoundry.multiapps.controller.web.util; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; - import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneId; @@ -12,6 +8,7 @@ import java.util.List; import java.util.Optional; +import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import org.cloudfoundry.multiapps.controller.persistence.model.AccessToken; import org.cloudfoundry.multiapps.controller.persistence.query.AccessTokenQuery; import org.cloudfoundry.multiapps.controller.persistence.services.AccessTokenService; @@ -23,7 +20,9 @@ import org.mockito.MockitoAnnotations; import org.springframework.security.oauth2.core.OAuth2AccessToken; -import com.sap.cloudfoundry.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; class TokenReuserTest { @@ -38,41 +37,6 @@ void setUp() throws Exception { .close(); } - @Test - void testGetTokenWithExpirationAfterNoTokensInDatabase() { - AccessTokenQuery accessTokenQuery = getMockedAccessTokenQuery(); - Mockito.when(accessTokenQuery.list()) - .thenReturn(Collections.emptyList()); - Optional token = tokenReuser.getTokenWithExpirationAfter("username", 100); - assertTrue(token.isEmpty()); - } - - @Test - void testGetTokenWithExpirationAfterTokenShouldBeReused() { - AccessTokenQuery accessTokenQuery = getMockedAccessTokenQuery(); - LocalDateTime datePlus5Mins = ZonedDateTime.now() - .plus(Duration.ofSeconds(5 * 60)) - .toLocalDateTime(); - AccessToken accessToken = getMockedAccessToken(datePlus5Mins); - Mockito.when(accessTokenQuery.list()) - .thenReturn(List.of(accessToken)); - Optional token = tokenReuser.getTokenWithExpirationAfter("test_user", 100); - assertTrue(token.isPresent()); - } - - @Test - void testGetTokenWithExpirationAfterTokenShouldNotBeReused() { - AccessTokenQuery accessTokenQuery = getMockedAccessTokenQuery(); - LocalDateTime dateMinus5Mins = ZonedDateTime.now() - .minus(Duration.ofSeconds(5 * 60)) - .toLocalDateTime(); - AccessToken accessToken = getMockedAccessToken(dateMinus5Mins); - Mockito.when(accessTokenQuery.list()) - .thenReturn(List.of(accessToken)); - Optional token = tokenReuser.getTokenWithExpirationAfter("test_user", 100); - assertTrue(token.isEmpty()); - } - @Test void testGetTokenWithExpirationAfterOrReuseCurrentNoTokensInDatabase() { AccessTokenQuery accessTokenQuery = getMockedAccessTokenQuery(); @@ -129,7 +93,7 @@ void testGetTokenWithExpirationAfterOrReuseCurrentTokensMatch() { private AccessTokenQuery getMockedAccessTokenQuery() { AccessTokenQuery accessTokenQuery = Mockito.mock(AccessTokenQuery.class); - Mockito.when(accessTokenQuery.username(anyString())) + Mockito.when(accessTokenQuery.userGuid(anyString())) .thenReturn(accessTokenQuery); Mockito.when(accessTokenQuery.orderByExpiresAt(any())) .thenReturn(accessTokenQuery);