From cc0341252054cbc47565f1e53ed55b5a0b4adcd3 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 10 Jun 2022 13:06:20 +0300 Subject: [PATCH 01/10] chore: Add an ability to manually configure bitbucket oAuth token Signed-off-by: Igor Vinokur --- .../oauth1/NoopOAuthAuthenticator.java | 5 +- ...ucketServerPersonalAccessTokenFetcher.java | 18 +++++- .../server/bitbucket/BitbucketURLParser.java | 56 +++++++++++++++++-- .../server/BitbucketServerApiClient.java | 8 ++- .../server/HttpBitbucketServerApiClient.java | 11 +++- .../server/NoopBitbucketServerApiClient.java | 5 +- ...horizingFactoryParametersResolverTest.java | 8 ++- .../BitbucketServerScmFileResolverTest.java | 7 ++- .../bitbucket/BitbucketURLParserTest.java | 8 ++- .../HttpBitbucketServerApiClientTest.java | 4 +- 10 files changed, 105 insertions(+), 25 deletions(-) diff --git a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java index 62c1d012967..b8f1edf31c3 100644 --- a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java +++ b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -49,7 +49,6 @@ public String computeAuthorizationHeader(String userId, String requestMethod, St @Override public String getLocalAuthenticateUrl() { - throw new RuntimeException( - "The fallback noop authenticator cannot be used for authentication. Make sure OAuth is properly configured."); + return "Empty URL"; } } 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 8d91ac00111..c1101abaade 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -25,6 +25,8 @@ import org.eclipse.che.api.factory.server.bitbucket.server.BitbucketPersonalAccessToken; import org.eclipse.che.api.factory.server.bitbucket.server.BitbucketServerApiClient; import org.eclipse.che.api.factory.server.bitbucket.server.BitbucketUser; +import org.eclipse.che.api.factory.server.bitbucket.server.HttpBitbucketServerApiClient; +import org.eclipse.che.api.factory.server.bitbucket.server.NoopBitbucketServerApiClient; import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher; import org.eclipse.che.api.factory.server.scm.exception.ScmBadRequestException; @@ -33,6 +35,7 @@ import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.security.oauth1.NoopOAuthAuthenticator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,6 +106,19 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheUser, String scmS @Override public Optional isValid(PersonalAccessToken personalAccessToken) throws ScmCommunicationException, ScmUnauthorizedException { + // If BitBucket oAuth is not configured try to find a manually added user namespace token. + if (bitbucketServerApiClient instanceof NoopBitbucketServerApiClient) { + HttpBitbucketServerApiClient apiClient = + new HttpBitbucketServerApiClient( + personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); + try { + apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); + return Optional.of(Boolean.TRUE); + } catch (ScmItemNotFoundException exception) { + // Even if the user not found, it means the token is valid. + return Optional.of(Boolean.TRUE); + } + } if (!bitbucketServerApiClient.isConnected(personalAccessToken.getScmProviderUrl())) { LOG.debug("not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); return Optional.empty(); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index f278fb58d9e..300d3af7751 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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,13 +17,20 @@ import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; +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; +import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.StringUtils; /** @@ -35,6 +42,7 @@ public class BitbucketURLParser { private final DevfileFilenamesProvider devfileFilenamesProvider; + private final PersonalAccessTokenManager personalAccessTokenManager; private static final String bitbucketUrlPatternTemplate = "^(?%s)/scm/(?[^/]++)/(?[^.]++).git(\\?at=)?(?[\\w\\d-_]*)"; private final List bitbucketUrlPatterns = new ArrayList<>(); @@ -42,8 +50,10 @@ public class BitbucketURLParser { @Inject public BitbucketURLParser( @Nullable @Named("che.integration.bitbucket.server_endpoints") String bitbucketEndpoints, - DevfileFilenamesProvider devfileFilenamesProvider) { + DevfileFilenamesProvider devfileFilenamesProvider, + PersonalAccessTokenManager personalAccessTokenManager) { this.devfileFilenamesProvider = devfileFilenamesProvider; + this.personalAccessTokenManager = personalAccessTokenManager; if (bitbucketEndpoints != null) { for (String bitbucketEndpoint : Splitter.on(",").split(bitbucketEndpoints)) { String trimmedEndpoint = StringUtils.trimEnd(bitbucketEndpoint, '/'); @@ -54,8 +64,23 @@ public BitbucketURLParser( } public boolean isValid(@NotNull String url) { - return !bitbucketUrlPatterns.isEmpty() - && bitbucketUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); + if (!bitbucketUrlPatterns.isEmpty()) { + return bitbucketUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); + } else { + // If Bitbucket server URL is not configured try to find it in a manually added user namespace + // token. + String trimmedUrl = url.substring(0, url.indexOf("/scm")); + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), trimmedUrl); + return token.isPresent() && token.get().getScmProviderUrl().equals(trimmedUrl); + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + return false; + } + } } /** @@ -64,8 +89,25 @@ public boolean isValid(@NotNull String url) { * BitbucketUrl objects. */ public BitbucketUrl parse(String url) { - if (bitbucketUrlPatterns.isEmpty()) { + String trimmedUrl = url.substring(0, url.indexOf("/scm")); + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), trimmedUrl); + if (token.isPresent()) { + Pattern pattern = + Pattern.compile(format(bitbucketUrlPatternTemplate, token.get().getScmProviderUrl())); + Matcher matcher = pattern.matcher(url); + if (matcher.matches()) { + return parse(matcher); + } + } + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + throw new UnsupportedOperationException("Token is not valid"); + } throw new UnsupportedOperationException( "The Bitbucket integration is not configured properly and cannot be used at this moment." + "Please refer to docs to check the Bitbucket integration instructions"); @@ -82,6 +124,10 @@ public BitbucketUrl parse(String url) { format( "The given url %s is not a valid Bitbucket server URL. Check either URL or server configuration.", url))); + return parse(matcher); + } + + private BitbucketUrl parse(Matcher matcher) { String host = matcher.group("host"); String project = matcher.group("project"); String repoName = matcher.group("repo"); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/BitbucketServerApiClient.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/BitbucketServerApiClient.java index 2a6b090791d..c6d0b3c0e15 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/BitbucketServerApiClient.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/BitbucketServerApiClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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,6 +17,7 @@ import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException; import org.eclipse.che.api.factory.server.scm.exception.ScmItemNotFoundException; import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.subject.Subject; /** Bitbucket Server API client. */ @@ -36,13 +37,14 @@ BitbucketUser getUser(Subject cheUser) throws ScmUnauthorizedException, ScmCommunicationException, ScmItemNotFoundException; /** - * @param slug + * @param slug scm username. + * @param token token to override. Pass {@code null} to use token from the authentication flow. * @return - Retrieve the {@link BitbucketUser} matching the supplied userSlug. * @throws ScmItemNotFoundException * @throws ScmUnauthorizedException * @throws ScmCommunicationException */ - BitbucketUser getUser(String slug) + BitbucketUser getUser(String slug, @Nullable String token) throws ScmItemNotFoundException, ScmUnauthorizedException, ScmCommunicationException; /** diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/HttpBitbucketServerApiClient.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/HttpBitbucketServerApiClient.java index d9ae5c3e331..4790f3d781d 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/HttpBitbucketServerApiClient.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/HttpBitbucketServerApiClient.java @@ -46,6 +46,7 @@ import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException; import org.eclipse.che.api.factory.server.scm.exception.ScmItemNotFoundException; import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.subject.Subject; @@ -128,12 +129,16 @@ public BitbucketUser getUser(Subject cheUser) } @Override - public BitbucketUser getUser(String slug) + public BitbucketUser getUser(String slug, @Nullable String token) throws ScmItemNotFoundException, ScmUnauthorizedException, ScmCommunicationException { URI uri = serverUri.resolve("/rest/api/1.0/users/" + slug); HttpRequest request = HttpRequest.newBuilder(uri) - .headers("Authorization", computeAuthorizationHeader("GET", uri.toString())) + .headers( + "Authorization", + token != null + ? "Bearer " + token + : computeAuthorizationHeader("GET", uri.toString())) .timeout(DEFAULT_HTTP_TIMEOUT) .build(); @@ -308,7 +313,7 @@ private Optional findCurrentUser(Set userSlugs) throws ScmCommunicationException, ScmUnauthorizedException, ScmItemNotFoundException { for (String userSlug : userSlugs) { - BitbucketUser user = getUser(userSlug); + BitbucketUser user = getUser(userSlug, null); try { getPersonalAccessTokens(userSlug); return Optional.of(user); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/NoopBitbucketServerApiClient.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/NoopBitbucketServerApiClient.java index 5d42d37cf17..0806e1ef702 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/NoopBitbucketServerApiClient.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/server/NoopBitbucketServerApiClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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,6 +17,7 @@ import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException; import org.eclipse.che.api.factory.server.scm.exception.ScmItemNotFoundException; import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.subject.Subject; /** @@ -37,7 +38,7 @@ public BitbucketUser getUser(Subject cheUser) } @Override - public BitbucketUser getUser(String slug) + public BitbucketUser getUser(String slug, @Nullable String token) throws ScmItemNotFoundException, ScmUnauthorizedException, ScmCommunicationException { throw new RuntimeException( "The fallback noop api client cannot be used for real operation. Make sure Bitbucket OAuth1 is properly configured."); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerAuthorizingFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerAuthorizingFactoryParametersResolverTest.java index 7e1cb226786..bb411f2ae61 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerAuthorizingFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerAuthorizingFactoryParametersResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -68,7 +69,10 @@ public class BitbucketServerAuthorizingFactoryParametersResolverTest { @BeforeMethod protected void init() { bitbucketURLParser = - new BitbucketURLParser("http://bitbucket.2mcl.com", devfileFilenamesProvider); + new BitbucketURLParser( + "http://bitbucket.2mcl.com", + devfileFilenamesProvider, + mock(PersonalAccessTokenManager.class)); assertNotNull(this.bitbucketURLParser); bitbucketServerFactoryParametersResolver = new BitbucketServerAuthorizingFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolverTest.java index 94c6d7e8bb5..8e9ea04dbca 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolverTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -14,6 +14,7 @@ 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.when; import static org.testng.Assert.*; @@ -47,7 +48,9 @@ public class BitbucketServerScmFileResolverTest { @BeforeMethod protected void init() { - bitbucketURLParser = new BitbucketURLParser(SCM_URL, devfileFilenamesProvider); + bitbucketURLParser = + new BitbucketURLParser( + SCM_URL, devfileFilenamesProvider, mock(PersonalAccessTokenManager.class)); assertNotNull(this.bitbucketURLParser); serverScmFileResolver = new BitbucketServerScmFileResolver( diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java index 373b21c2951..1498ad48f0c 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -11,9 +11,11 @@ */ package org.eclipse.che.api.factory.server.bitbucket; +import static org.mockito.Mockito.mock; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -34,7 +36,9 @@ public class BitbucketURLParserTest { public void setUp() { bitbucketURLParser = new BitbucketURLParser( - "https://bitbucket.2mcl.com,https://bbkt.com", devfileFilenamesProvider); + "https://bitbucket.2mcl.com,https://bbkt.com", + devfileFilenamesProvider, + mock(PersonalAccessTokenManager.class)); } /** Check URLs are valid with regexp */ diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/HttpBitbucketServerApiClientTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/HttpBitbucketServerApiClientTest.java index 6a8276c1989..0c1f2f06d03 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/HttpBitbucketServerApiClientTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/HttpBitbucketServerApiClientTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -95,7 +95,7 @@ public void testGetUser() .withHeader("Content-Type", "application/json; charset=utf-8") .withBodyFile("bitbucket/rest/api/1.0/users/ksmster/response.json"))); - BitbucketUser user = bitbucketServer.getUser("ksmster"); + BitbucketUser user = bitbucketServer.getUser("ksmster", null); assertNotNull(user); } From 17c82bb6f7d553e43d4ff2bedca40adb6e0cadd9 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 17 Jun 2022 16:48:42 +0300 Subject: [PATCH 02/10] fixup! chore: Add an ability to manually configure bitbucket oAuth token --- .../KubernetesPersonalAccessTokenManager.java | 11 +++- ...ucketServerPersonalAccessTokenFetcher.java | 3 +- .../server/bitbucket/BitbucketURLParser.java | 24 ++++---- .../gitlab/GitlabOAuthTokenFetcher.java | 10 +++- .../server/gitlab/GitlabUrlParser.java | 58 +++++++++++++++++-- .../GitlabFactoryParametersResolverTest.java | 9 ++- .../gitlab/GitlabScmFileResolverTest.java | 7 ++- .../server/gitlab/GitlabUrlParserTest.java | 9 ++- .../factory/server/gitlab/GitlabUrlTest.java | 8 ++- .../scm/PersonalAccessTokenManager.java | 16 ++++- 10 files changed, 126 insertions(+), 29 deletions(-) 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 b145d363915..dad8ab42048 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -135,6 +135,13 @@ public Optional get(Subject cheUser, String scmServerUrl) throws ScmConfigurationPersistenceException, ScmUnauthorizedException, ScmCommunicationException { + return get(cheUser, scmServerUrl, true); + } + + @Override + public Optional get(Subject cheUser, String scmServerUrl, boolean validate) + throws ScmConfigurationPersistenceException, ScmUnauthorizedException, + ScmCommunicationException { try { for (KubernetesNamespaceMeta namespaceMeta : namespaceFactory.list()) { List secrets = @@ -156,7 +163,7 @@ public Optional get(Subject cheUser, String scmServerUrl) annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME), annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_ID), new String(Base64.getDecoder().decode(secret.getData().get("token")))); - if (scmPersonalAccessTokenFetcher.isValid(token)) { + if (!validate || scmPersonalAccessTokenFetcher.isValid(token)) { return Optional.of(token); } else { // Removing token that is no longer valid. If several tokens exist the next one could 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 c1101abaade..e57ea77a4af 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 @@ -107,7 +107,8 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheUser, String scmS public Optional isValid(PersonalAccessToken personalAccessToken) throws ScmCommunicationException, ScmUnauthorizedException { // If BitBucket oAuth is not configured try to find a manually added user namespace token. - if (bitbucketServerApiClient instanceof NoopBitbucketServerApiClient) { + if (bitbucketServerApiClient instanceof NoopBitbucketServerApiClient + && personalAccessToken.getScmTokenName().equals("bitbucket-server")) { HttpBitbucketServerApiClient apiClient = new HttpBitbucketServerApiClient( personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 300d3af7751..050b1ff38a2 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -69,17 +69,21 @@ public boolean isValid(@NotNull String url) { } else { // If Bitbucket server URL is not configured try to find it in a manually added user namespace // token. - String trimmedUrl = url.substring(0, url.indexOf("/scm")); - try { - Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), trimmedUrl); - return token.isPresent() && token.get().getScmProviderUrl().equals(trimmedUrl); - } catch (ScmConfigurationPersistenceException - | ScmUnauthorizedException - | ScmCommunicationException exception) { - return false; + String serverUrl = + url.substring(0, url.indexOf("/scm") > 0 ? url.indexOf("/scm") : url.length()); + if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)).matcher(url).matches()) { + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), serverUrl, false); + return token.isPresent() && token.get().getScmTokenName().equals("bitbucket-server"); + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + return false; + } } + return false; } } 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 00796b83a05..8bc3ecb487c 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 @@ -149,9 +149,13 @@ public Optional isValid(PersonalAccessToken personalAccessToken) { GitlabApiClient gitlabApiClient = getApiClient(personalAccessToken.getScmProviderUrl()); if (gitlabApiClient == null || !gitlabApiClient.isConnected(personalAccessToken.getScmProviderUrl())) { - LOG.debug( - "not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); - return Optional.empty(); + if (personalAccessToken.getScmTokenName().equals("gitlab")) { + gitlabApiClient = new GitlabApiClient(personalAccessToken.getScmProviderUrl()); + } else { + LOG.debug( + "not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); + return Optional.empty(); + } } if (personalAccessToken.getScmTokenName() != null && personalAccessToken.getScmTokenName().startsWith(OAUTH_2_PREFIX)) { diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java index 0e371171980..a1ebcf491c6 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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,12 +17,19 @@ import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Named; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; +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; +import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.StringUtils; /** @@ -33,6 +40,7 @@ public class GitlabUrlParser { private final DevfileFilenamesProvider devfileFilenamesProvider; + private final PersonalAccessTokenManager personalAccessTokenManager; private static final List gitlabUrlPatternTemplates = List.of( "^(?%s)/(?[^/]++)/(?[^./]++).git", @@ -44,8 +52,10 @@ public class GitlabUrlParser { @Inject public GitlabUrlParser( @Nullable @Named("che.integration.gitlab.server_endpoints") String bitbucketEndpoints, - DevfileFilenamesProvider devfileFilenamesProvider) { + DevfileFilenamesProvider devfileFilenamesProvider, + PersonalAccessTokenManager personalAccessTokenManager) { this.devfileFilenamesProvider = devfileFilenamesProvider; + this.personalAccessTokenManager = personalAccessTokenManager; if (bitbucketEndpoints != null) { for (String bitbucketEndpoint : Splitter.on(",").split(bitbucketEndpoints)) { String trimmedEndpoint = StringUtils.trimEnd(bitbucketEndpoint, '/'); @@ -58,8 +68,30 @@ public GitlabUrlParser( } public boolean isValid(@NotNull String url) { - return !gitlabUrlPatterns.isEmpty() - && gitlabUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); + if (!gitlabUrlPatterns.isEmpty()) { + return gitlabUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); + } else { + // If Gitlab URL is not configured, try to find it in a manually added user namespace + // token. + Matcher matcher = Pattern.compile("[^/|:]/").matcher(url); + if (matcher.find()) { + String serverUrl = url.substring(0, url.indexOf(matcher.group()) + 1); + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), serverUrl, false); + if (token.isPresent()) { + PersonalAccessToken accessToken = token.get(); + return accessToken.getScmTokenName().equals("gitlab"); + } + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + return false; + } + } + } + return false; } /** @@ -69,6 +101,20 @@ public boolean isValid(@NotNull String url) { public GitlabUrl parse(String url) { if (gitlabUrlPatterns.isEmpty()) { + String trimmedEndpoint = StringUtils.trimEnd(url, '/'); + Matcher matcher = Pattern.compile("[^/|:]/").matcher(url); + if (matcher.find()) { + String serverUrl = + trimmedEndpoint.substring(0, trimmedEndpoint.indexOf(matcher.group()) + 1); + Optional optional = + gitlabUrlPatternTemplates.stream() + .map(t -> Pattern.compile(format(t, serverUrl)).matcher(url)) + .filter(Matcher::matches) + .findAny(); + if (optional.isPresent()) { + return parse(optional.get()); + } + } throw new UnsupportedOperationException( "The gitlab integration is not configured properly and cannot be used at this moment." + "Please refer to docs to check the Gitlab integration instructions"); @@ -85,6 +131,10 @@ public GitlabUrl parse(String url) { format( "The given url %s is not a valid Gitlab server URL. Check either URL or server configuration.", url))); + return parse(matcher); + } + + private GitlabUrl parse(Matcher matcher) { String host = matcher.group("host"); String userName = matcher.group("user"); String project = matcher.group("project"); diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabFactoryParametersResolverTest.java index 7c57f2444a6..5498524255c 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabFactoryParametersResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -71,7 +72,11 @@ public class GitlabFactoryParametersResolverTest { @BeforeMethod protected void init() { - gitlabUrlParser = new GitlabUrlParser("http://gitlab.2mcl.com", devfileFilenamesProvider); + gitlabUrlParser = + new GitlabUrlParser( + "http://gitlab.2mcl.com", + devfileFilenamesProvider, + mock(PersonalAccessTokenManager.class)); assertNotNull(this.gitlabUrlParser); gitlabFactoryParametersResolver = new GitlabFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolverTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolverTest.java index ee419a08c86..3e57afbe615 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolverTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -14,6 +14,7 @@ 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.when; import static org.testng.Assert.*; @@ -47,7 +48,9 @@ public class GitlabScmFileResolverTest { @BeforeMethod protected void init() { - gitlabUrlParser = new GitlabUrlParser(SCM_URL, devfileFilenamesProvider); + gitlabUrlParser = + new GitlabUrlParser( + SCM_URL, devfileFilenamesProvider, mock(PersonalAccessTokenManager.class)); assertNotNull(this.gitlabUrlParser); gitlabScmFileResolver = new GitlabScmFileResolver( diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParserTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParserTest.java index 82c39ca17fa..55e5fab9cc3 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParserTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -11,9 +11,11 @@ */ package org.eclipse.che.api.factory.server.gitlab; +import static org.mockito.Mockito.mock; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -33,7 +35,10 @@ public class GitlabUrlParserTest { @BeforeMethod public void setUp() { gitlabUrlParser = - new GitlabUrlParser("https://gitlab1.com,https://gitlab.foo.xxx", devfileFilenamesProvider); + new GitlabUrlParser( + "https://gitlab1.com,https://gitlab.foo.xxx", + devfileFilenamesProvider, + mock(PersonalAccessTokenManager.class)); } /** Check URLs are valid with regexp */ diff --git a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlTest.java b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlTest.java index d9407a4a691..f08f92d0d3b 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlTest.java +++ b/wsmaster/che-core-api-factory-gitlab/src/test/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -13,11 +13,13 @@ import static java.lang.String.format; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import java.util.Arrays; import java.util.Iterator; +import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLocation; import org.mockito.Mock; @@ -45,7 +47,9 @@ public class GitlabUrlTest { protected void init() { when(devfileFilenamesProvider.getConfiguredDevfileFilenames()) .thenReturn(Arrays.asList("devfile.yaml", "foo.bar")); - gitlabUrlParser = new GitlabUrlParser("https://gitlab.net", devfileFilenamesProvider); + gitlabUrlParser = + new GitlabUrlParser( + "https://gitlab.net", devfileFilenamesProvider, mock(PersonalAccessTokenManager.class)); } /** Check when there is devfile in the repository */ diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java index 585567c1399..1c47909ff4b 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -51,4 +51,18 @@ PersonalAccessToken fetchAndSave(Subject cheUser, String scmServerUrl) Optional get(Subject cheUser, String scmServerUrl) throws ScmConfigurationPersistenceException, ScmUnauthorizedException, ScmCommunicationException; + + /** + * Gets {@link PersonalAccessToken} from permanent storage. + * + * @param cheUser + * @param scmServerUrl + * @param validate + * @return personal access token + * @throws ScmConfigurationPersistenceException - problem occurred during communication with * + * permanent storage. + */ + Optional get(Subject cheUser, String scmServerUrl, boolean validate) + throws ScmConfigurationPersistenceException, ScmUnauthorizedException, + ScmCommunicationException; } From e627d6a7f59d19ef5adfdb9224873b49e12a927e Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Wed, 22 Jun 2022 09:06:01 +0300 Subject: [PATCH 03/10] fixup! fixup! chore: Add an ability to manually configure bitbucket oAuth token --- .../server/scm/PersonalAccessTokenManager.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java index 1c47909ff4b..8d08cfd4b1e 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java @@ -42,8 +42,8 @@ PersonalAccessToken fetchAndSave(Subject cheUser, String scmServerUrl) /** * Gets {@link PersonalAccessToken} from permanent storage. * - * @param cheUser - * @param scmServerUrl + * @param cheUser Che user object + * @param scmServerUrl Git provider endpoint * @return personal access token * @throws ScmConfigurationPersistenceException - problem occurred during communication with * * permanent storage. @@ -55,9 +55,10 @@ Optional get(Subject cheUser, String scmServerUrl) /** * Gets {@link PersonalAccessToken} from permanent storage. * - * @param cheUser - * @param scmServerUrl - * @param validate + * @param cheUser Che user object + * @param scmServerUrl Git provider endpoint + * @param validate {@code false} to skip the token validation and avoid API call, otherwise {@code + * true} * @return personal access token * @throws ScmConfigurationPersistenceException - problem occurred during communication with * * permanent storage. From e3e73786a8889c3b2ed29f5e873d02937be57559 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Wed, 22 Jun 2022 09:43:35 +0300 Subject: [PATCH 04/10] fixup! fixup! chore: Add an ability to manually configure bitbucket oAuth token --- ...ucketServerPersonalAccessTokenFetcher.java | 28 +++++++++---------- ...tServerPersonalAccessTokenFetcherTest.java | 3 +- 2 files changed, 15 insertions(+), 16 deletions(-) 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 e57ea77a4af..2d84b640d9b 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 @@ -26,7 +26,6 @@ import org.eclipse.che.api.factory.server.bitbucket.server.BitbucketServerApiClient; import org.eclipse.che.api.factory.server.bitbucket.server.BitbucketUser; import org.eclipse.che.api.factory.server.bitbucket.server.HttpBitbucketServerApiClient; -import org.eclipse.che.api.factory.server.bitbucket.server.NoopBitbucketServerApiClient; import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenFetcher; import org.eclipse.che.api.factory.server.scm.exception.ScmBadRequestException; @@ -106,21 +105,20 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheUser, String scmS @Override public Optional isValid(PersonalAccessToken personalAccessToken) throws ScmCommunicationException, ScmUnauthorizedException { - // If BitBucket oAuth is not configured try to find a manually added user namespace token. - if (bitbucketServerApiClient instanceof NoopBitbucketServerApiClient - && personalAccessToken.getScmTokenName().equals("bitbucket-server")) { - HttpBitbucketServerApiClient apiClient = - new HttpBitbucketServerApiClient( - personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); - try { - apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); - return Optional.of(Boolean.TRUE); - } catch (ScmItemNotFoundException exception) { - // Even if the user not found, it means the token is valid. - return Optional.of(Boolean.TRUE); - } - } if (!bitbucketServerApiClient.isConnected(personalAccessToken.getScmProviderUrl())) { + // If BitBucket oAuth is not configured check the manually added user namespace token. + if (personalAccessToken.getScmTokenName().equals("bitbucket-server")) { + HttpBitbucketServerApiClient apiClient = + new HttpBitbucketServerApiClient( + personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); + try { + apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); + return Optional.of(Boolean.TRUE); + } catch (ScmItemNotFoundException exception) { + // Even if the user not found, it means that the token is valid. + return Optional.of(Boolean.TRUE); + } + } LOG.debug("not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); return Optional.empty(); } diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java index 1b961803e70..3ca6cd677e3 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -190,6 +190,7 @@ public void shouldSkipToValidateTokensWithUnknownUrls() throws ScmUnauthorizedException, ScmCommunicationException { // given when(personalAccessToken.getScmProviderUrl()).thenReturn(someNotBitbucketURL); + when(personalAccessToken.getScmTokenName()).thenReturn("unknown"); when(bitbucketServerApiClient.isConnected(eq(someNotBitbucketURL))).thenReturn(false); // when Optional result = fetcher.isValid(personalAccessToken); From 9fdb554795f3be2d09d16c59fa77284b83c3ec83 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Thu, 23 Jun 2022 18:15:16 +0300 Subject: [PATCH 05/10] fixup! chore: Add an ability to manually configure bitbucket oAuth token --- ...ucketServerPersonalAccessTokenFetcher.java | 26 +++---- .../server/bitbucket/BitbucketURLParser.java | 62 ++++++++-------- ...tServerPersonalAccessTokenFetcherTest.java | 1 - .../server/gitlab/GitlabUrlParser.java | 70 +++++++++++-------- 4 files changed, 82 insertions(+), 77 deletions(-) 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 2d84b640d9b..99a53cb1406 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 @@ -107,20 +107,20 @@ public Optional isValid(PersonalAccessToken personalAccessToken) throws ScmCommunicationException, ScmUnauthorizedException { if (!bitbucketServerApiClient.isConnected(personalAccessToken.getScmProviderUrl())) { // If BitBucket oAuth is not configured check the manually added user namespace token. - if (personalAccessToken.getScmTokenName().equals("bitbucket-server")) { - HttpBitbucketServerApiClient apiClient = - new HttpBitbucketServerApiClient( - personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); - try { - apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); - return Optional.of(Boolean.TRUE); - } catch (ScmItemNotFoundException exception) { - // Even if the user not found, it means that the token is valid. - return Optional.of(Boolean.TRUE); - } + HttpBitbucketServerApiClient apiClient = + new HttpBitbucketServerApiClient( + personalAccessToken.getScmProviderUrl(), new NoopOAuthAuthenticator()); + try { + apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); + return Optional.of(Boolean.TRUE); + } catch (ScmItemNotFoundException exception) { + // Even if the user not found, it means that the token is valid. + return Optional.of(Boolean.TRUE); + } catch (ScmUnauthorizedException | ScmCommunicationException exception) { + LOG.debug( + "not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); + return Optional.empty(); } - LOG.debug("not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); - return Optional.empty(); } try { BitbucketPersonalAccessToken bitbucketPersonalAccessToken = diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 050b1ff38a2..2155d938443 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -63,54 +63,52 @@ public BitbucketURLParser( } } + private boolean userTokenExists(String url) { + String serverUrl = getServerUrl(url); + if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)).matcher(url).matches()) { + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), serverUrl, false); + return token.isPresent() && token.get().getScmTokenName().equals("bitbucket-server"); + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + return false; + } + } + return false; + } + public boolean isValid(@NotNull String url) { if (!bitbucketUrlPatterns.isEmpty()) { return bitbucketUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); } else { // If Bitbucket server URL is not configured try to find it in a manually added user namespace // token. - String serverUrl = - url.substring(0, url.indexOf("/scm") > 0 ? url.indexOf("/scm") : url.length()); - if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)).matcher(url).matches()) { - try { - Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), serverUrl, false); - return token.isPresent() && token.get().getScmTokenName().equals("bitbucket-server"); - } catch (ScmConfigurationPersistenceException - | ScmUnauthorizedException - | ScmCommunicationException exception) { - return false; - } - } - return false; + return userTokenExists(url); } } + private String getServerUrl(String url) { + return url.substring(0, url.indexOf("/scm") > 0 ? url.indexOf("/scm") : url.length()); + } + + private Matcher getPatternMatcherByUrl(String url) { + return Pattern.compile(format(bitbucketUrlPatternTemplate, getServerUrl(url))).matcher(url); + } + /** * Parses url-s like * https://bitbucket.apps.cluster-cb82.cb82.example.opentlc.com/scm/test/test1.git into * BitbucketUrl objects. */ public BitbucketUrl parse(String url) { + if (bitbucketUrlPatterns.isEmpty()) { - String trimmedUrl = url.substring(0, url.indexOf("/scm")); - try { - Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), trimmedUrl); - if (token.isPresent()) { - Pattern pattern = - Pattern.compile(format(bitbucketUrlPatternTemplate, token.get().getScmProviderUrl())); - Matcher matcher = pattern.matcher(url); - if (matcher.matches()) { - return parse(matcher); - } - } - } catch (ScmConfigurationPersistenceException - | ScmUnauthorizedException - | ScmCommunicationException exception) { - throw new UnsupportedOperationException("Token is not valid"); + Matcher patternMatcher = getPatternMatcherByUrl(url); + if (patternMatcher.matches()) { + return parse(patternMatcher); } throw new UnsupportedOperationException( "The Bitbucket integration is not configured properly and cannot be used at this moment." diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java index 3ca6cd677e3..1576d6e5ee5 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerPersonalAccessTokenFetcherTest.java @@ -190,7 +190,6 @@ public void shouldSkipToValidateTokensWithUnknownUrls() throws ScmUnauthorizedException, ScmCommunicationException { // given when(personalAccessToken.getScmProviderUrl()).thenReturn(someNotBitbucketURL); - when(personalAccessToken.getScmTokenName()).thenReturn("unknown"); when(bitbucketServerApiClient.isConnected(eq(someNotBitbucketURL))).thenReturn(false); // when Optional result = fetcher.isValid(personalAccessToken); diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java index a1ebcf491c6..41b9e483323 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java @@ -67,31 +67,49 @@ public GitlabUrlParser( } } + private boolean userTokenExists(String url) { + Matcher serverUrlMatcher = Pattern.compile("[^/|:]/").matcher(url); + if (serverUrlMatcher.find()) { + String serverUrl = url.substring(0, url.indexOf(serverUrlMatcher.group()) + 1); + try { + Optional token = + personalAccessTokenManager.get( + EnvironmentContext.getCurrent().getSubject(), serverUrl, false); + if (token.isPresent()) { + PersonalAccessToken accessToken = token.get(); + return accessToken.getScmTokenName().equals("gitlab"); + } + } catch (ScmConfigurationPersistenceException + | ScmUnauthorizedException + | ScmCommunicationException exception) { + return false; + } + } + return false; + } + public boolean isValid(@NotNull String url) { if (!gitlabUrlPatterns.isEmpty()) { return gitlabUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); } else { // If Gitlab URL is not configured, try to find it in a manually added user namespace // token. - Matcher matcher = Pattern.compile("[^/|:]/").matcher(url); - if (matcher.find()) { - String serverUrl = url.substring(0, url.indexOf(matcher.group()) + 1); - try { - Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), serverUrl, false); - if (token.isPresent()) { - PersonalAccessToken accessToken = token.get(); - return accessToken.getScmTokenName().equals("gitlab"); - } - } catch (ScmConfigurationPersistenceException - | ScmUnauthorizedException - | ScmCommunicationException exception) { - return false; - } - } + return userTokenExists(url); } - return false; + } + + private Optional getPatternMatcherByUrl(String url) { + String trimmedEndpoint = StringUtils.trimEnd(url, '/'); + Matcher serverUrlMatcher = Pattern.compile("[^/|:]/").matcher(url); + if (serverUrlMatcher.find()) { + String serverUrl = + trimmedEndpoint.substring(0, trimmedEndpoint.indexOf(serverUrlMatcher.group()) + 1); + return gitlabUrlPatternTemplates.stream() + .map(t -> Pattern.compile(format(t, serverUrl)).matcher(url)) + .filter(Matcher::matches) + .findAny(); + } + return Optional.empty(); } /** @@ -101,19 +119,9 @@ public boolean isValid(@NotNull String url) { public GitlabUrl parse(String url) { if (gitlabUrlPatterns.isEmpty()) { - String trimmedEndpoint = StringUtils.trimEnd(url, '/'); - Matcher matcher = Pattern.compile("[^/|:]/").matcher(url); - if (matcher.find()) { - String serverUrl = - trimmedEndpoint.substring(0, trimmedEndpoint.indexOf(matcher.group()) + 1); - Optional optional = - gitlabUrlPatternTemplates.stream() - .map(t -> Pattern.compile(format(t, serverUrl)).matcher(url)) - .filter(Matcher::matches) - .findAny(); - if (optional.isPresent()) { - return parse(optional.get()); - } + Optional optionalMatcher = getPatternMatcherByUrl(url); + if (optionalMatcher.isPresent()) { + return parse(optionalMatcher.get()); } throw new UnsupportedOperationException( "The gitlab integration is not configured properly and cannot be used at this moment." From afea2c72dd44b9c21088cddae5112a03fb9a12a8 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 24 Jun 2022 14:54:22 +0300 Subject: [PATCH 06/10] Update wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java Co-authored-by: Anatolii Bazko --- .../che/api/factory/server/bitbucket/BitbucketURLParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 2155d938443..1b561e458fb 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -63,7 +63,7 @@ public BitbucketURLParser( } } - private boolean userTokenExists(String url) { + private boolean isUserTokenExists(String repositoryUrl) { String serverUrl = getServerUrl(url); if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)).matcher(url).matches()) { try { From bac2296fd03fa11faed03ab73dcfe52af8bef3d9 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 24 Jun 2022 14:54:41 +0300 Subject: [PATCH 07/10] Update wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java Co-authored-by: Anatolii Bazko --- .../che/api/factory/server/bitbucket/BitbucketURLParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 1b561e458fb..8d2a3995602 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -90,7 +90,7 @@ public boolean isValid(@NotNull String url) { } } - private String getServerUrl(String url) { + private String getServerUrl(String repositoryUrl) { return url.substring(0, url.indexOf("/scm") > 0 ? url.indexOf("/scm") : url.length()); } From 3944a013ad552f07eb76a954a5e53cdcf4901036 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Fri, 24 Jun 2022 16:08:03 +0300 Subject: [PATCH 08/10] fixup! chore: Add an ability to manually configure bitbucket oAuth token --- .../KubernetesPersonalAccessTokenManager.java | 9 +---- ...ucketServerPersonalAccessTokenFetcher.java | 7 ++-- .../server/bitbucket/BitbucketURLParser.java | 18 ++++++---- .../gitlab/GitlabOAuthTokenFetcher.java | 2 +- .../server/gitlab/GitlabUrlParser.java | 33 +++++++++++-------- .../scm/PersonalAccessTokenManager.java | 15 --------- 6 files changed, 36 insertions(+), 48 deletions(-) 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 dad8ab42048..e705334972f 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 @@ -135,13 +135,6 @@ public Optional get(Subject cheUser, String scmServerUrl) throws ScmConfigurationPersistenceException, ScmUnauthorizedException, ScmCommunicationException { - return get(cheUser, scmServerUrl, true); - } - - @Override - public Optional get(Subject cheUser, String scmServerUrl, boolean validate) - throws ScmConfigurationPersistenceException, ScmUnauthorizedException, - ScmCommunicationException { try { for (KubernetesNamespaceMeta namespaceMeta : namespaceFactory.list()) { List secrets = @@ -163,7 +156,7 @@ public Optional get(Subject cheUser, String scmServerUrl, b annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME), annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_ID), new String(Base64.getDecoder().decode(secret.getData().get("token")))); - if (!validate || scmPersonalAccessTokenFetcher.isValid(token)) { + if (scmPersonalAccessTokenFetcher.isValid(token)) { return Optional.of(token); } else { // Removing token that is no longer valid. If several tokens exist the next one could 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 99a53cb1406..2f307229580 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 @@ -113,10 +113,9 @@ public Optional isValid(PersonalAccessToken personalAccessToken) try { apiClient.getUser(personalAccessToken.getScmUserName(), personalAccessToken.getToken()); return Optional.of(Boolean.TRUE); - } catch (ScmItemNotFoundException exception) { - // Even if the user not found, it means that the token is valid. - return Optional.of(Boolean.TRUE); - } catch (ScmUnauthorizedException | ScmCommunicationException exception) { + } catch (ScmItemNotFoundException + | ScmUnauthorizedException + | ScmCommunicationException exception) { LOG.debug( "not a valid url {} for current fetcher ", personalAccessToken.getScmProviderUrl()); return Optional.empty(); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 8d2a3995602..18331807443 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -46,6 +46,7 @@ public class BitbucketURLParser { private static final String bitbucketUrlPatternTemplate = "^(?%s)/scm/(?[^/]++)/(?[^.]++).git(\\?at=)?(?[\\w\\d-_]*)"; private final List bitbucketUrlPatterns = new ArrayList<>(); + private static final String OAUTH_PROVIDER_NAME = "bitbucket-server"; @Inject public BitbucketURLParser( @@ -64,13 +65,14 @@ public BitbucketURLParser( } private boolean isUserTokenExists(String repositoryUrl) { - String serverUrl = getServerUrl(url); - if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)).matcher(url).matches()) { + String serverUrl = getServerUrl(repositoryUrl); + if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)) + .matcher(repositoryUrl) + .matches()) { try { Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), serverUrl, false); - return token.isPresent() && token.get().getScmTokenName().equals("bitbucket-server"); + personalAccessTokenManager.get(EnvironmentContext.getCurrent().getSubject(), serverUrl); + return token.isPresent() && token.get().getScmTokenName().equals(OAUTH_PROVIDER_NAME); } catch (ScmConfigurationPersistenceException | ScmUnauthorizedException | ScmCommunicationException exception) { @@ -86,12 +88,14 @@ public boolean isValid(@NotNull String url) { } else { // If Bitbucket server URL is not configured try to find it in a manually added user namespace // token. - return userTokenExists(url); + return isUserTokenExists(url); } } private String getServerUrl(String repositoryUrl) { - return url.substring(0, url.indexOf("/scm") > 0 ? url.indexOf("/scm") : url.length()); + return repositoryUrl.substring( + 0, + repositoryUrl.indexOf("/scm") > 0 ? repositoryUrl.indexOf("/scm") : repositoryUrl.length()); } private Matcher getPatternMatcherByUrl(String url) { 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 8bc3ecb487c..f85a6f37adf 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 @@ -149,7 +149,7 @@ public Optional isValid(PersonalAccessToken personalAccessToken) { GitlabApiClient gitlabApiClient = getApiClient(personalAccessToken.getScmProviderUrl()); if (gitlabApiClient == null || !gitlabApiClient.isConnected(personalAccessToken.getScmProviderUrl())) { - if (personalAccessToken.getScmTokenName().equals("gitlab")) { + if (personalAccessToken.getScmTokenName().equals(OAUTH_PROVIDER_NAME)) { gitlabApiClient = new GitlabApiClient(personalAccessToken.getScmProviderUrl()); } else { LOG.debug( diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java index 41b9e483323..5a6ae11d9a5 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java @@ -48,6 +48,7 @@ public class GitlabUrlParser { "^(?%s)/(?[^/]++)/(?[^/]++)(/)?(?[^/]++)?(/)?", "^(?%s)/(?[^/]++)/(?[^/]++)(/)?(?[^/]++)?/-/tree/(?[^/]++)(/)?(?[^/]++)?"); private final List gitlabUrlPatterns = new ArrayList<>(); + private static final String OAUTH_PROVIDER_NAME = "gitlab"; @Inject public GitlabUrlParser( @@ -67,17 +68,16 @@ public GitlabUrlParser( } } - private boolean userTokenExists(String url) { - Matcher serverUrlMatcher = Pattern.compile("[^/|:]/").matcher(url); - if (serverUrlMatcher.find()) { - String serverUrl = url.substring(0, url.indexOf(serverUrlMatcher.group()) + 1); + private boolean isUserTokenExists(String repositoryUrl) { + Optional serverUrlOptional = getServerUrl(repositoryUrl); + if (serverUrlOptional.isPresent()) { + String serverUrl = serverUrlOptional.get(); try { Optional token = - personalAccessTokenManager.get( - EnvironmentContext.getCurrent().getSubject(), serverUrl, false); + personalAccessTokenManager.get(EnvironmentContext.getCurrent().getSubject(), serverUrl); if (token.isPresent()) { PersonalAccessToken accessToken = token.get(); - return accessToken.getScmTokenName().equals("gitlab"); + return accessToken.getScmTokenName().equals(OAUTH_PROVIDER_NAME); } } catch (ScmConfigurationPersistenceException | ScmUnauthorizedException @@ -94,16 +94,14 @@ public boolean isValid(@NotNull String url) { } else { // If Gitlab URL is not configured, try to find it in a manually added user namespace // token. - return userTokenExists(url); + return isUserTokenExists(url); } } private Optional getPatternMatcherByUrl(String url) { - String trimmedEndpoint = StringUtils.trimEnd(url, '/'); - Matcher serverUrlMatcher = Pattern.compile("[^/|:]/").matcher(url); - if (serverUrlMatcher.find()) { - String serverUrl = - trimmedEndpoint.substring(0, trimmedEndpoint.indexOf(serverUrlMatcher.group()) + 1); + Optional serverUrlOptional = getServerUrl(url); + if (serverUrlOptional.isPresent()) { + String serverUrl = serverUrlOptional.get(); return gitlabUrlPatternTemplates.stream() .map(t -> Pattern.compile(format(t, serverUrl)).matcher(url)) .filter(Matcher::matches) @@ -112,6 +110,15 @@ private Optional getPatternMatcherByUrl(String url) { return Optional.empty(); } + private Optional getServerUrl(String repositoryUrl) { + Matcher serverUrlMatcher = Pattern.compile("[^/|:]/").matcher(repositoryUrl); + if (serverUrlMatcher.find()) { + return Optional.of( + repositoryUrl.substring(0, repositoryUrl.indexOf(serverUrlMatcher.group()) + 1)); + } + return Optional.empty(); + } + /** * Parses url-s like https://gitlab.apps.cluster-327a.327a.example.opentlc.com/root/proj1.git into * {@link GitlabUrl} objects. diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java index 8d08cfd4b1e..c2d7e4742fd 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/scm/PersonalAccessTokenManager.java @@ -51,19 +51,4 @@ PersonalAccessToken fetchAndSave(Subject cheUser, String scmServerUrl) Optional get(Subject cheUser, String scmServerUrl) throws ScmConfigurationPersistenceException, ScmUnauthorizedException, ScmCommunicationException; - - /** - * Gets {@link PersonalAccessToken} from permanent storage. - * - * @param cheUser Che user object - * @param scmServerUrl Git provider endpoint - * @param validate {@code false} to skip the token validation and avoid API call, otherwise {@code - * true} - * @return personal access token - * @throws ScmConfigurationPersistenceException - problem occurred during communication with * - * permanent storage. - */ - Optional get(Subject cheUser, String scmServerUrl, boolean validate) - throws ScmConfigurationPersistenceException, ScmUnauthorizedException, - ScmCommunicationException; } From 19cfabf2e7f9b2e82d9cae65eb2e180c6707f9c1 Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Mon, 27 Jun 2022 11:42:29 +0300 Subject: [PATCH 09/10] fixup! chore: Add an ability to manually configure bitbucket oAuth token --- .../org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java index b8f1edf31c3..86d5e07f481 100644 --- a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java +++ b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java @@ -49,6 +49,6 @@ public String computeAuthorizationHeader(String userId, String requestMethod, St @Override public String getLocalAuthenticateUrl() { - return "Empty URL"; + return "Noop URL"; } } From b09e14aa2586f05e458ecb47b65d56805d82d03b Mon Sep 17 00:00:00 2001 From: Igor Vinokur Date: Mon, 27 Jun 2022 14:28:36 +0300 Subject: [PATCH 10/10] fixup! chore: Add an ability to manually configure bitbucket oAuth token --- .../eclipse/che/security/oauth1/NoopOAuthAuthenticator.java | 2 +- .../che/api/factory/server/bitbucket/BitbucketURLParser.java | 4 ++-- .../che/api/factory/server/gitlab/GitlabUrlParser.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java index 86d5e07f481..5680fdfa4bc 100644 --- a/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java +++ b/wsmaster/che-core-api-auth-bitbucket/src/main/java/org/eclipse/che/security/oauth1/NoopOAuthAuthenticator.java @@ -15,7 +15,7 @@ /** * Dummy implementation of @{@link OAuthAuthenticator} used in the case if no Bitbucket Server - * integration is configured. + * integration is configured to register an empty @{@link BitbucketServerApiClient}. */ public class NoopOAuthAuthenticator extends OAuthAuthenticator { public NoopOAuthAuthenticator() { diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 18331807443..f71fa21b7da 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -64,7 +64,7 @@ public BitbucketURLParser( } } - private boolean isUserTokenExists(String repositoryUrl) { + private boolean isUserTokenPresent(String repositoryUrl) { String serverUrl = getServerUrl(repositoryUrl); if (Pattern.compile(format(bitbucketUrlPatternTemplate, serverUrl)) .matcher(repositoryUrl) @@ -88,7 +88,7 @@ public boolean isValid(@NotNull String url) { } else { // If Bitbucket server URL is not configured try to find it in a manually added user namespace // token. - return isUserTokenExists(url); + return isUserTokenPresent(url); } } diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java index 5a6ae11d9a5..1b0e7bb8149 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabUrlParser.java @@ -68,7 +68,7 @@ public GitlabUrlParser( } } - private boolean isUserTokenExists(String repositoryUrl) { + private boolean isUserTokenPresent(String repositoryUrl) { Optional serverUrlOptional = getServerUrl(repositoryUrl); if (serverUrlOptional.isPresent()) { String serverUrl = serverUrlOptional.get(); @@ -94,7 +94,7 @@ public boolean isValid(@NotNull String url) { } else { // If Gitlab URL is not configured, try to find it in a manually added user namespace // token. - return isUserTokenExists(url); + return isUserTokenPresent(url); } }