diff --git a/infrastructures/infrastructure-factory/pom.xml b/infrastructures/infrastructure-factory/pom.xml index 5ed6b03f83..b4647fdf9b 100644 --- a/infrastructures/infrastructure-factory/pom.xml +++ b/infrastructures/infrastructure-factory/pom.xml @@ -51,10 +51,6 @@ jakarta.ws.rs jakarta.ws.rs-api - - org.eclipse.che.core - che-core-api-auth - org.eclipse.che.core che-core-api-core diff --git a/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManager.java b/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManager.java index 1249405bcb..4323d7728c 100644 --- a/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManager.java +++ b/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManager.java @@ -14,7 +14,6 @@ package org.eclipse.che.api.factory.server.scm.kubernetes; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher.OAUTH_2_SUFFIX; import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.KubernetesSecretAnnotationNames.ANNOTATION_AUTOMOUNT; import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.KubernetesSecretAnnotationNames.ANNOTATION_DEV_WORKSPACE_MOUNT_PATH; import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.KubernetesSecretAnnotationNames.ANNOTATION_GIT_CREDENTIALS; @@ -176,7 +175,7 @@ public class KubernetesGitCredentialManager implements GitCredentialManager { private String getUsernameSegment(PersonalAccessToken personalAccessToken) { // Special characters are not allowed in URL username segment, so we need to escape them. PercentEscaper percentEscaper = new PercentEscaper("", false); - return personalAccessToken.getScmProviderName().startsWith(OAUTH_2_SUFFIX) + return personalAccessToken.isOAuthToken() ? "oauth2" : isNullOrEmpty(personalAccessToken.getScmOrganization()) ? percentEscaper.escape(personalAccessToken.getScmUserName()) diff --git a/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesPersonalAccessTokenManager.java b/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesPersonalAccessTokenManager.java index 73a9aa2986..2e7831ee85 100644 --- a/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesPersonalAccessTokenManager.java +++ b/infrastructures/infrastructure-factory/src/main/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesPersonalAccessTokenManager.java @@ -12,6 +12,7 @@ package org.eclipse.che.api.factory.server.scm.kubernetes; import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.Boolean.parseBoolean; import static org.eclipse.che.commons.lang.StringUtils.trimEnd; import com.google.common.annotations.VisibleForTesting; @@ -62,6 +63,7 @@ public class KubernetesPersonalAccessTokenManager implements PersonalAccessToken public static final String NAME_PATTERN = "personal-access-token-"; public static final String ANNOTATION_CHE_USERID = "che.eclipse.org/che-userid"; + public static final String ANNOTATION_SCM_IS_OAUTH_TOKEN = "che.eclipse.org/scm-is-oauth-token"; public static final String ANNOTATION_SCM_ORGANIZATION = "che.eclipse.org/scm-organization"; public static final String ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_ID = "che.eclipse.org/scm-personal-access-token-id"; @@ -96,6 +98,9 @@ public class KubernetesPersonalAccessTokenManager implements PersonalAccessToken .withName(NameGenerator.generate(NAME_PATTERN, 5)) .withAnnotations( new ImmutableMap.Builder() + .put( + ANNOTATION_SCM_IS_OAUTH_TOKEN, + Boolean.toString(personalAccessToken.isOAuthToken())) .put(ANNOTATION_CHE_USERID, personalAccessToken.getCheUserId()) .put(ANNOTATION_SCM_URL, personalAccessToken.getScmProviderUrl()) .put( @@ -194,6 +199,7 @@ public class KubernetesPersonalAccessTokenManager implements PersonalAccessToken PersonalAccessToken personalAccessToken = new PersonalAccessToken( + parseBoolean(secretAnnotations.get(ANNOTATION_SCM_IS_OAUTH_TOKEN)), personalAccessTokenParams.getScmProviderUrl(), secretAnnotations.get(ANNOTATION_CHE_USERID), personalAccessTokenParams.getOrganization(), @@ -278,6 +284,7 @@ public class KubernetesPersonalAccessTokenManager implements PersonalAccessToken private PersonalAccessTokenParams secret2PersonalAccessTokenParams(Secret secret) { Map secretAnnotations = secret.getMetadata().getAnnotations(); + boolean isOauth = parseBoolean(secretAnnotations.get(ANNOTATION_SCM_IS_OAUTH_TOKEN)); String token = new String(Base64.getDecoder().decode(secret.getData().get("token"))).trim(); String configuredOAuthProviderName = secretAnnotations.get(ANNOTATION_SCM_PROVIDER_NAME); String configuredTokenId = secretAnnotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_ID); @@ -285,6 +292,7 @@ public class KubernetesPersonalAccessTokenManager implements PersonalAccessToken String configuredScmServerUrl = secretAnnotations.get(ANNOTATION_SCM_URL); return new PersonalAccessTokenParams( + isOauth, trimEnd(configuredScmServerUrl, '/'), configuredOAuthProviderName, configuredTokenId, diff --git a/infrastructures/infrastructure-factory/src/test/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManagerTest.java b/infrastructures/infrastructure-factory/src/test/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManagerTest.java index 621bc5838a..b04b3b0263 100644 --- a/infrastructures/infrastructure-factory/src/test/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManagerTest.java +++ b/infrastructures/infrastructure-factory/src/test/java/org/eclipse/che/api/factory/server/scm/kubernetes/KubernetesGitCredentialManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2023 Red Hat, Inc. + * Copyright (c) 2012-2024 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -92,8 +92,14 @@ public class KubernetesGitCredentialManagerTest { PersonalAccessToken token = new PersonalAccessToken( - "https://bitbucket.com", "cheUser", "username", "token-name", "tid-23434", "token123"); - + false, + "https://bitbucket.com", + "cheUser", + "cheOrganization", + "username", + "bitbucket", + "tid-23434", + "token123"); // when kubernetesGitCredentialManager.createOrReplace(token); // then @@ -113,6 +119,7 @@ public class KubernetesGitCredentialManagerTest { KubernetesNamespaceMeta namespaceMeta = new KubernetesNamespaceMetaImpl("test"); PersonalAccessToken token = new PersonalAccessToken( + false, "https://bitbucket-server.com:5648", "cheUser", "cheOrganization", @@ -198,10 +205,12 @@ public class KubernetesGitCredentialManagerTest { KubernetesNamespaceMeta namespaceMeta = new KubernetesNamespaceMetaImpl("test"); PersonalAccessToken token = new PersonalAccessToken( + false, "https://bitbucket.com:5648", "cheUser", + "cheOrganization", "username", - "token-name", + "bitbucket", "tid-23434", "token123"); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/OAuthTokenSecretsConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/OAuthTokenSecretsConfigurator.java index 5daa3575fd..4ad21d23b3 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/OAuthTokenSecretsConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/OAuthTokenSecretsConfigurator.java @@ -11,11 +11,12 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; +import static java.lang.Boolean.parseBoolean; + import com.google.common.collect.ImmutableMap; import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; -import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher; import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException; import org.eclipse.che.api.factory.server.scm.exception.ScmConfigurationPersistenceException; @@ -40,6 +41,7 @@ public class OAuthTokenSecretsConfigurator implements NamespaceConfigurator { private static final String ANNOTATION_SCM_URL = "che.eclipse.org/scm-url"; private static final String ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME = "che.eclipse.org/scm-personal-access-token-name"; + public static final String ANNOTATION_SCM_IS_OAUTH_TOKEN = "che.eclipse.org/scm-is-oauth-token"; private static final Map SEARCH_LABELS = ImmutableMap.of( @@ -66,10 +68,8 @@ public class OAuthTokenSecretsConfigurator implements NamespaceConfigurator { && s.getMetadata() .getAnnotations() .containsKey(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME) - && s.getMetadata() - .getAnnotations() - .get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME) - .startsWith(PersonalAccessTokenFetcher.OAUTH_2_SUFFIX)) + && parseBoolean( + s.getMetadata().getAnnotations().get(ANNOTATION_SCM_IS_OAUTH_TOKEN))) .forEach( s -> { try { diff --git a/wsmaster/che-core-api-auth/src/main/java/org/eclipse/che/security/oauth/EmbeddedOAuthAPI.java b/wsmaster/che-core-api-auth/src/main/java/org/eclipse/che/security/oauth/EmbeddedOAuthAPI.java index 82c276fd89..7c51d6ec97 100644 --- a/wsmaster/che-core-api-auth/src/main/java/org/eclipse/che/security/oauth/EmbeddedOAuthAPI.java +++ b/wsmaster/che-core-api-auth/src/main/java/org/eclipse/che/security/oauth/EmbeddedOAuthAPI.java @@ -184,35 +184,31 @@ public class EmbeddedOAuthAPI implements OAuthAPI { if (token != null) { return token; } - Optional tokenOptional = - personalAccessTokenManager.get(subject, oauthProvider, null); - if (tokenOptional.isPresent()) { - PersonalAccessToken tokenDto = tokenOptional.get(); - return newDto(OAuthToken.class).withToken(tokenDto.getToken()); - } throw new UnauthorizedException( "OAuth token for user " + subject.getUserId() + " was not found"); } catch (IOException e) { throw new ServerException(e.getLocalizedMessage(), e); - } catch (ScmCommunicationException - | ScmUnauthorizedException - | ScmConfigurationPersistenceException e) { - throw new RuntimeException(e); } } @Override public void invalidateToken(String oauthProvider) - throws NotFoundException, UnauthorizedException, ServerException { + throws NotFoundException, UnauthorizedException { OAuthAuthenticator oauth = getAuthenticator(oauthProvider); - OAuthToken oauthToken = getToken(oauthProvider); try { - if (!oauth.invalidateToken(oauthToken.getToken())) { + Optional tokenOptional = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), oauthProvider, null); + if (tokenOptional.isPresent() && !oauth.invalidateToken(tokenOptional.get().getToken())) { throw new UnauthorizedException( "OAuth token for provider " + oauthProvider + " was not found"); } - } catch (IOException e) { - throw new ServerException(e.getMessage()); + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException + | IOException e) { + throw new UnauthorizedException( + "OAuth token for provider " + oauthProvider + " was not found"); } } diff --git a/wsmaster/che-core-api-factory-azure-devops/src/main/java/org/eclipse/che/api/factory/server/azure/devops/AzureDevOpsPersonalAccessTokenFetcher.java b/wsmaster/che-core-api-factory-azure-devops/src/main/java/org/eclipse/che/api/factory/server/azure/devops/AzureDevOpsPersonalAccessTokenFetcher.java index 8b44fc4b89..daf74b436c 100644 --- a/wsmaster/che-core-api-factory-azure-devops/src/main/java/org/eclipse/che/api/factory/server/azure/devops/AzureDevOpsPersonalAccessTokenFetcher.java +++ b/wsmaster/che-core-api-factory-azure-devops/src/main/java/org/eclipse/che/api/factory/server/azure/devops/AzureDevOpsPersonalAccessTokenFetcher.java @@ -82,12 +82,11 @@ public class AzureDevOpsPersonalAccessTokenFetcher implements PersonalAccessToke try { oAuthToken = oAuthAPI.getToken(AzureDevOps.PROVIDER_NAME); - String tokenName = NameGenerator.generate(OAUTH_2_SUFFIX, 5); String tokenId = NameGenerator.generate("id-", 5); Optional> valid = isValid( new PersonalAccessTokenParams( - scmServerUrl, tokenName, tokenId, oAuthToken.getToken(), null)); + true, scmServerUrl, "azure-devops", tokenId, oAuthToken.getToken(), null)); if (valid.isEmpty()) { throw buildScmUnauthorizedException(cheSubject); } else if (!valid.get().first) { @@ -99,7 +98,7 @@ public class AzureDevOpsPersonalAccessTokenFetcher implements PersonalAccessToke scmServerUrl, cheSubject.getUserId(), valid.get().second, - tokenName, + "azure-devops", tokenId, oAuthToken.getToken()); } catch (UnauthorizedException e) { @@ -132,8 +131,7 @@ public class AzureDevOpsPersonalAccessTokenFetcher implements PersonalAccessToke try { AzureDevOpsUser user; - if (personalAccessToken.getScmProviderName() != null - && personalAccessToken.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (personalAccessToken.getScmProviderName() != null && personalAccessToken.isOAuthToken()) { user = azureDevOpsApiClient.getUserWithOAuthToken(personalAccessToken.getToken()); } else { user = @@ -155,8 +153,7 @@ public class AzureDevOpsPersonalAccessTokenFetcher implements PersonalAccessToke try { AzureDevOpsUser user; - if (params.getScmProviderName() != null - && params.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (params.isOAuthToken()) { user = azureDevOpsApiClient.getUserWithOAuthToken(params.getToken()); } else { user = azureDevOpsApiClient.getUserWithPAT(params.getToken(), params.getOrganization()); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcher.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcher.java index 90fbaaae67..a9a46bed33 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcher.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcher.java @@ -95,11 +95,12 @@ public class BitbucketServerPersonalAccessTokenFetcher implements PersonalAccess bitbucketServerApiClient.createPersonalAccessTokens(tokenName, DEFAULT_TOKEN_SCOPE); LOG.debug("Token created = {} for {}", token.getId(), token.getUser()); return new PersonalAccessToken( + true, scmServerUrl, EnvironmentContext.getCurrent().getSubject().getUserId(), user.getName(), user.getSlug(), - token.getName(), + "bitbucket-server", valueOf(token.getId()), token.getToken()); } catch (ScmBadRequestException | ScmItemNotFoundException e) { diff --git a/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcher.java b/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcher.java index 8887c76f31..ccd6c51f4f 100644 --- a/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcher.java +++ b/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcher.java @@ -97,7 +97,7 @@ public class BitbucketPersonalAccessTokenFetcher implements PersonalAccessTokenF Optional> valid = isValid( new PersonalAccessTokenParams( - scmServerUrl, tokenName, tokenId, oAuthToken.getToken(), null)); + true, scmServerUrl, tokenName, tokenId, oAuthToken.getToken(), null)); if (valid.isEmpty()) { throw buildScmUnauthorizedException(cheSubject); } else if (!valid.get().first) { diff --git a/wsmaster/che-core-api-factory-bitbucket/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcherTest.java b/wsmaster/che-core-api-factory-bitbucket/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcherTest.java index 06eea49475..39a56700c2 100644 --- a/wsmaster/che-core-api-factory-bitbucket/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcherTest.java +++ b/wsmaster/che-core-api-factory-bitbucket/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketPersonalAccessTokenFetcherTest.java @@ -18,7 +18,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static java.net.HttpURLConnection.HTTP_FORBIDDEN; -import static org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher.OAUTH_2_SUFFIX; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -87,7 +86,12 @@ public class BitbucketPersonalAccessTokenFetcherTest { .withBodyFile("bitbucket/rest/user/response.json"))); PersonalAccessTokenParams personalAccessTokenParams = new PersonalAccessTokenParams( - "https://bitbucket.org/", "scmTokenName", "scmTokenId", bitbucketOauthToken, null); + true, + "https://bitbucket.org/", + "scmTokenName", + "scmTokenId", + bitbucketOauthToken, + null); assertTrue( bitbucketPersonalAccessTokenFetcher.isValid(personalAccessTokenParams).isEmpty(), "Should not validate SCM server with trailing /"); @@ -165,7 +169,7 @@ public class BitbucketPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - "https://bitbucket.org", "params-name", "tid-23434", bitbucketOauthToken, null); + false, "https://bitbucket.org", "params-name", "tid-23434", bitbucketOauthToken, null); Optional> valid = bitbucketPersonalAccessTokenFetcher.isValid(params); assertTrue(valid.isPresent()); @@ -187,11 +191,7 @@ public class BitbucketPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - "https://bitbucket.org", - OAUTH_2_SUFFIX + "-params-name", - "tid-23434", - bitbucketOauthToken, - null); + true, "https://bitbucket.org", "azure-devops", "tid-23434", bitbucketOauthToken, null); Optional> valid = bitbucketPersonalAccessTokenFetcher.isValid(params); assertTrue(valid.isPresent()); @@ -204,11 +204,7 @@ public class BitbucketPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - "https://bitbucket.org", - OAUTH_2_SUFFIX + "-token-name", - "tid-23434", - bitbucketOauthToken, - null); + true, "https://bitbucket.org", "azure-devops", "tid-23434", bitbucketOauthToken, null); assertFalse(bitbucketPersonalAccessTokenFetcher.isValid(params).isPresent()); } diff --git a/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubPersonalAccessTokenFetcher.java b/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubPersonalAccessTokenFetcher.java index 1d077ca3b4..5d9bf82a1a 100644 --- a/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubPersonalAccessTokenFetcher.java +++ b/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubPersonalAccessTokenFetcher.java @@ -139,7 +139,7 @@ public abstract class AbstractGithubPersonalAccessTokenFetcher Optional> valid = isValid( new PersonalAccessTokenParams( - scmServerUrl, providerName, tokenId, oAuthToken.getToken(), null)); + true, scmServerUrl, providerName, tokenId, oAuthToken.getToken(), null)); if (valid.isEmpty()) { throw buildScmUnauthorizedException(cheSubject); } else if (!valid.get().first) { @@ -184,8 +184,7 @@ public abstract class AbstractGithubPersonalAccessTokenFetcher } try { - if (personalAccessToken.getScmProviderName() != null - && personalAccessToken.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (personalAccessToken.isOAuthToken()) { String[] scopes = githubApiClient.getTokenScopes(personalAccessToken.getToken()).second; return Optional.of(containsScopes(scopes, DEFAULT_TOKEN_SCOPES)); } else { @@ -217,8 +216,7 @@ public abstract class AbstractGithubPersonalAccessTokenFetcher } } try { - if (params.getScmProviderName() != null - && params.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (params.getScmProviderName() != null && params.isOAuthToken()) { Pair pair = apiClient.getTokenScopes(params.getToken()); return Optional.of( Pair.of( diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubGitUserDataFetcherTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubGitUserDataFetcherTest.java index 412b1e9ecf..7afce65d22 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubGitUserDataFetcherTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubGitUserDataFetcherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2023 Red Hat, Inc. + * Copyright (c) 2012-2024 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -17,8 +17,9 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -26,9 +27,11 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.common.Slf4jNotifier; import com.google.common.net.HttpHeaders; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; +import java.util.Optional; import org.eclipse.che.api.factory.server.scm.GitUserData; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; +import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.security.oauth.OAuthAPI; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -80,8 +83,11 @@ public class GithubGitUserDataFetcherTest { @Test public void shouldFetchGitUserData() throws Exception { - OAuthToken oAuthToken = newDto(OAuthToken.class).withToken(githubOauthToken).withScope("repo"); - when(oAuthTokenFetcher.getToken(anyString())).thenReturn(oAuthToken); + PersonalAccessToken token = mock(PersonalAccessToken.class); + when(token.getToken()).thenReturn(githubOauthToken); + when(token.getScmProviderUrl()).thenReturn(wireMockServer.url("/")); + when(personalAccessTokenManager.get(any(Subject.class), eq("github"), eq(null))) + .thenReturn(Optional.of(token)); GitUserData gitUserData = githubGUDFetcher.fetchGitUserData(); diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubPersonalAccessTokenFetcherTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubPersonalAccessTokenFetcherTest.java index 1614db1d95..2ab0861e78 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubPersonalAccessTokenFetcherTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubPersonalAccessTokenFetcherTest.java @@ -19,7 +19,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static java.net.HttpURLConnection.HTTP_FORBIDDEN; import static org.eclipse.che.api.factory.server.github.GithubPersonalAccessTokenFetcher.DEFAULT_TOKEN_SCOPES; -import static org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher.OAUTH_2_SUFFIX; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -91,7 +90,7 @@ public class GithubPersonalAccessTokenFetcherTest { .withBodyFile("github/rest/user/response.json"))); PersonalAccessTokenParams personalAccessTokenParams = new PersonalAccessTokenParams( - "https://github.com/", "scmTokenName", "scmTokenId", githubOauthToken, null); + true, "https://github.com/", "scmTokenName", "scmTokenId", githubOauthToken, null); assertTrue( githubPATFetcher.isValid(personalAccessTokenParams).isEmpty(), "Should not validate SCM server with trailing /"); @@ -213,7 +212,7 @@ public class GithubPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - wireMockServer.url("/"), "token-name", "tid-23434", githubOauthToken, null); + false, wireMockServer.url("/"), "token-name", "tid-23434", githubOauthToken, null); Optional> valid = githubPATFetcher.isValid(params); assertTrue(valid.isPresent()); @@ -235,11 +234,7 @@ public class GithubPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - wireMockServer.url("/"), - OAUTH_2_SUFFIX + "-params-name", - "tid-23434", - githubOauthToken, - null); + true, wireMockServer.url("/"), "github", "tid-23434", githubOauthToken, null); Optional> valid = githubPATFetcher.isValid(params); assertTrue(valid.isPresent()); @@ -252,11 +247,7 @@ public class GithubPersonalAccessTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - wireMockServer.url("/"), - OAUTH_2_SUFFIX + "-token-name", - "tid-23434", - githubOauthToken, - null); + true, wireMockServer.url("/"), "github", "tid-23434", githubOauthToken, null); assertFalse(githubPATFetcher.isValid(params).isPresent()); } diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcher.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcher.java index 8a9e3b1b13..476e65d7e7 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcher.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcher.java @@ -106,12 +106,11 @@ public class GitlabOAuthTokenFetcher implements PersonalAccessTokenFetcher { OAuthToken oAuthToken; try { oAuthToken = oAuthAPI.getToken(OAUTH_PROVIDER_NAME); - String tokenName = NameGenerator.generate(OAUTH_2_SUFFIX, 5); String tokenId = NameGenerator.generate("id-", 5); Optional> valid = isValid( new PersonalAccessTokenParams( - scmServerUrl, tokenName, tokenId, oAuthToken.getToken(), null)); + true, scmServerUrl, OAUTH_PROVIDER_NAME, tokenId, oAuthToken.getToken(), null)); if (valid.isEmpty()) { throw buildScmUnauthorizedException(cheSubject); } else if (!valid.get().first) { @@ -123,7 +122,7 @@ public class GitlabOAuthTokenFetcher implements PersonalAccessTokenFetcher { scmServerUrl, cheSubject.getUserId(), valid.get().second, - tokenName, + OAUTH_PROVIDER_NAME, tokenId, oAuthToken.getToken()); } catch (UnauthorizedException e) { @@ -160,8 +159,7 @@ public class GitlabOAuthTokenFetcher implements PersonalAccessTokenFetcher { return Optional.empty(); } } - if (personalAccessToken.getScmProviderName() != null - && personalAccessToken.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (personalAccessToken.getScmProviderName() != null && personalAccessToken.isOAuthToken()) { // validation OAuth token by special API call try { GitlabOauthTokenInfo info = @@ -199,8 +197,7 @@ public class GitlabOAuthTokenFetcher implements PersonalAccessTokenFetcher { } try { GitlabUser user = gitlabApiClient.getUser(params.getToken()); - if (params.getScmProviderName() != null - && params.getScmProviderName().startsWith(OAUTH_2_SUFFIX)) { + if (params.getScmProviderName() != null && params.isOAuthToken()) { // validation OAuth token by special API call GitlabOauthTokenInfo info = gitlabApiClient.getOAuthTokenInfo(params.getToken()); return Optional.of( diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcherTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcherTest.java index cb5e0e0446..4ac493198f 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcherTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabOAuthTokenFetcherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2023 Red Hat, Inc. + * Copyright (c) 2012-2024 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -179,7 +179,7 @@ public class GitlabOAuthTokenFetcherTest { PersonalAccessTokenParams params = new PersonalAccessTokenParams( - wireMockServer.baseUrl(), "oauth2-token-name", "tid-23434", "token123", null); + true, wireMockServer.baseUrl(), "oauth2-token-name", "tid-23434", "token123", null); Optional> valid = oAuthTokenFetcher.isValid(params); diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUserDataFetcherTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUserDataFetcherTest.java index 89e97458c4..5e16f9d060 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUserDataFetcherTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUserDataFetcherTest.java @@ -17,8 +17,9 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -26,9 +27,11 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.common.Slf4jNotifier; import com.google.common.net.HttpHeaders; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; +import java.util.Optional; import org.eclipse.che.api.factory.server.scm.GitUserData; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; +import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.security.oauth.OAuthAPI; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -78,9 +81,11 @@ public class GitlabUserDataFetcherTest { @Test public void shouldFetchGitUserData() throws Exception { - OAuthToken oAuthToken = - newDto(OAuthToken.class).withToken("oauthtoken").withScope("api write_repository openid"); - when(oAuthTokenFetcher.getToken(anyString())).thenReturn(oAuthToken); + PersonalAccessToken token = mock(PersonalAccessToken.class); + when(token.getToken()).thenReturn("oauthtoken"); + when(token.getScmProviderUrl()).thenReturn(wireMockServer.url("/")); + when(personalAccessTokenManager.get(any(Subject.class), eq("gitlab"), eq(null))) + .thenReturn(Optional.of(token)); GitUserData gitUserData = gitlabUserDataFetcher.fetchGitUserData(); assertEquals(gitUserData.getScmUsername(), "John Smith"); diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/AuthorizingFileContentProvider.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/AuthorizingFileContentProvider.java index da5e9fcbdc..48fe066bcd 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/AuthorizingFileContentProvider.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/AuthorizingFileContentProvider.java @@ -12,7 +12,6 @@ package org.eclipse.che.api.factory.server.scm; import static com.google.common.base.Strings.isNullOrEmpty; -import static org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher.OAUTH_2_SUFFIX; import static org.eclipse.che.api.factory.server.scm.exception.ExceptionMessages.getDevfileConnectionErrorMessage; import java.io.FileNotFoundException; @@ -82,11 +81,7 @@ public class AuthorizingFileContentProvider if (isNullOrEmpty(credentials)) { PersonalAccessToken token = personalAccessTokenManager.getAndStore(remoteFactoryUrl.getProviderUrl()); - authorization = - formatAuthorization( - token.getToken(), - token.getScmProviderName() == null - || !token.getScmProviderName().startsWith(OAUTH_2_SUFFIX)); + authorization = formatAuthorization(token.getToken(), token.isOAuthToken()); } else { authorization = getCredentialsAuthorization(credentials); } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessToken.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessToken.java index 82ff18a4a2..4ea46fd3f1 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessToken.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessToken.java @@ -21,6 +21,7 @@ import org.eclipse.che.commons.env.EnvironmentContext; */ public class PersonalAccessToken { + private final boolean isOAuthToken; private final String scmProviderUrl; private final String scmUserName; /** Organization that user belongs to. Can be null if user is not a member of any organization. */ @@ -32,6 +33,7 @@ public class PersonalAccessToken { private final String cheUserId; public PersonalAccessToken( + boolean isOAuthToken, String scmProviderUrl, String cheUserId, String scmOrganization, @@ -39,6 +41,7 @@ public class PersonalAccessToken { String scmProviderName, String scmTokenId, String token) { + this.isOAuthToken = isOAuthToken; this.scmProviderUrl = scmProviderUrl; this.scmOrganization = scmOrganization; this.scmUserName = scmUserName; @@ -55,11 +58,12 @@ public class PersonalAccessToken { String scmProviderName, String scmTokenId, String token) { - this(scmProviderUrl, cheUserId, null, scmUserName, scmProviderName, scmTokenId, token); + this(true, scmProviderUrl, cheUserId, null, scmUserName, scmProviderName, scmTokenId, token); } public PersonalAccessToken(String scmProviderUrl, String scmUserName, String token) { this( + true, scmProviderUrl, EnvironmentContext.getCurrent().getSubject().getUserId(), null, @@ -93,6 +97,10 @@ public class PersonalAccessToken { return cheUserId; } + public boolean isOAuthToken() { + return isOAuthToken; + } + @Nullable public String getScmOrganization() { return scmOrganization; @@ -103,7 +111,8 @@ public class PersonalAccessToken { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PersonalAccessToken that = (PersonalAccessToken) o; - return Objects.equal(scmProviderUrl, that.scmProviderUrl) + return Objects.equal(isOAuthToken, that.isOAuthToken) + && Objects.equal(scmProviderUrl, that.scmProviderUrl) && Objects.equal(scmUserName, that.scmUserName) && Objects.equal(scmOrganization, that.scmOrganization) && Objects.equal(scmProviderName, that.scmProviderName) @@ -115,6 +124,7 @@ public class PersonalAccessToken { @Override public int hashCode() { return Objects.hashCode( + isOAuthToken, scmProviderUrl, scmUserName, scmOrganization, @@ -127,7 +137,9 @@ public class PersonalAccessToken { @Override public String toString() { return "PersonalAccessToken{" - + "scmProviderUrl='" + + "isOAuthToken=" + + isOAuthToken + + ", scmProviderUrl='" + scmProviderUrl + '\'' + ", scmUserName='" @@ -136,7 +148,7 @@ public class PersonalAccessToken { + ", scmOrganization='" + scmOrganization + '\'' - + ", scmTokenName='" + + ", scmProviderName='" + scmProviderName + '\'' + ", scmTokenId='" @@ -147,6 +159,7 @@ public class PersonalAccessToken { + '\'' + ", cheUserId='" + cheUserId + + '\'' + '}'; } } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenFetcher.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenFetcher.java index bcd5d606ab..a0e7c734ce 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenFetcher.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenFetcher.java @@ -19,10 +19,6 @@ import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.commons.subject.Subject; public interface PersonalAccessTokenFetcher { - - /** Prefix for token names indication it is OAuth token (to differentiate from PAT-s) */ - String OAUTH_2_SUFFIX = "-oauth2"; - /** * Retrieve new PersonalAccessToken from concrete scm provider * diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenParams.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenParams.java index 3b1a7a292f..254ba2d140 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenParams.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenParams.java @@ -13,6 +13,7 @@ package org.eclipse.che.api.factory.server.scm; /** An object to hold parameters for creating a personal access token. */ public class PersonalAccessTokenParams { + private final boolean isOAuthToken; private final String scmProviderUrl; private final String scmProviderName; private final String scmTokenId; @@ -20,11 +21,13 @@ public class PersonalAccessTokenParams { private final String organization; public PersonalAccessTokenParams( + boolean isOAuthToken, String scmProviderUrl, String scmProviderName, String scmTokenId, String token, String organization) { + this.isOAuthToken = isOAuthToken; this.scmProviderUrl = scmProviderUrl; this.scmProviderName = scmProviderName; this.scmTokenId = scmTokenId; @@ -51,4 +54,8 @@ public class PersonalAccessTokenParams { public String getOrganization() { return organization; } + + public boolean isOAuthToken() { + return isOAuthToken; + } }