From 8ff1be36f5a3063e278bc728f81ed161cedb108b Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 21 Dec 2017 17:50:03 +0200 Subject: [PATCH] Added support of Idenvity brokering mechanism of Keycloak for Multi-user Che --- .../server/WsAgentAuthServletModule.java | 6 + .../che/api/deploy/WsMasterModule.java | 7 +- .../che/api/core/cors/CheCorsFilter.java | 7 +- .../keycloak/templates/master-realm.json.erb | 1 + .../che/ide/api/auth}/Credentials.java | 2 +- .../che/ide/api/auth/OAuthServiceClient.java | 54 ++++++ ide/che-core-ide-app/pom.xml | 4 + .../factory/utils/FactoryProjectImporter.java | 2 +- .../projectimport/wizard/ProjectImporter.java | 116 +++++++------ .../ide/user/AskCredentialsDialogImpl.java | 2 +- .../wizard/ProjectImporterTest.java | 13 +- .../askcredentials/AskCredentialsDialog.java | 1 + .../che-multiuser-keycloak-server/pom.xml | 8 + .../server/KeycloakConfigurationService.java | 2 +- .../server/deploy/KeycloakModule.java | 2 + .../KeycloakOAuthAuthenticationService.java | 155 ++++++++++++++++++ .../plugin-git/che-plugin-git-ext-git/pom.xml | 4 + .../git/client/GitAuthActionPresenter.java | 82 +++++++++ .../ide/ext/git/client/GitServiceClient.java | 17 +- .../ext/git/client/GitServiceClientImpl.java | 24 ++- .../git/client/commit/CommitPresenter.java | 58 ++++--- .../ext/git/client/fetch/FetchPresenter.java | 54 +++--- .../ext/git/client/pull/PullPresenter.java | 55 ++++--- .../client/push/PushToRemotePresenter.java | 73 +++++---- .../client/commit/CommitPresenterTest.java | 7 +- .../git/client/fetch/FetchPresenterTest.java | 6 +- .../che-plugin-github-ide/pom.xml | 4 + ...tService.java => GitHubServiceClient.java} | 77 +++++++-- ...Impl.java => GitHubServiceClientImpl.java} | 103 +++++++++--- .../github/ide/GitHubSshKeyUploader.java | 65 ++++---- .../GitHubAuthenticatorImpl.java | 10 +- .../page/GithubImporterPagePresenter.java | 72 ++++---- .../github/ide/inject/GitHubGinModule.java | 6 +- .../page/GithubImporterPagePresenterTest.java | 123 +++----------- .../che-plugin-github-provider-github/pom.xml | 4 - .../github/GitHubOAuthCredentialProvider.java | 30 +--- .../che-plugin-github-pullrequest/pom.xml | 4 + .../client/GitHubHostingService.java | 93 ++++++----- .../che-plugin-github-server/pom.xml | 8 +- .../plugin/github/server/GitHubFactory.java | 36 +--- .../github/server/GitHubKeyUploader.java | 21 +-- .../github/server/inject/GitHubModule.java | 2 - .../github/server/rest/GitHubService.java | 110 +++++++++---- .../che-plugin-pullrequest-ide/pom.xml | 4 + .../pullrequest/client/vcs/GitVcsService.java | 46 +++++- wsagent/che-core-api-oauth/pom.xml | 4 - .../che/security/oauth/OAuthAgentModule.java | 2 - .../oauth/RemoteOAuthTokenProvider.java | 77 --------- .../oauth/RemoteOAuthTokenProviderTest.java | 116 ------------- .../ssh/key/script/SshKeyProviderImpl.java | 26 --- .../plugin/ssh/key/script/SshKeyUploader.java | 2 +- .../che/EnvironmentInitializationFilter.java | 51 ++++++ .../EnvironmentInitializationFilterTest.java | 60 +++++++ 53 files changed, 1135 insertions(+), 783 deletions(-) rename ide/{che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials => che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth}/Credentials.java (95%) create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/OAuthServiceClient.java create mode 100644 multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/KeycloakOAuthAuthenticationService.java create mode 100644 plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitAuthActionPresenter.java rename plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/{GitHubClientService.java => GitHubServiceClient.java} (64%) rename plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/{GitHubClientServiceImpl.java => GitHubServiceClientImpl.java} (69%) delete mode 100644 wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProvider.java delete mode 100644 wsagent/che-core-api-oauth/src/test/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProviderTest.java create mode 100644 wsagent/wsagent-local/src/main/java/org/eclipse/che/EnvironmentInitializationFilter.java create mode 100644 wsagent/wsagent-local/src/test/java/org/eclipse/che/EnvironmentInitializationFilterTest.java diff --git a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentAuthServletModule.java b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentAuthServletModule.java index 0137730440..468417acef 100644 --- a/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentAuthServletModule.java +++ b/assembly/assembly-wsagent-war/src/main/java/org/eclipse/che/wsagent/server/WsAgentAuthServletModule.java @@ -21,10 +21,16 @@ public class WsAgentAuthServletModule extends ServletModule { protected void configureServlets() { if (Boolean.valueOf(System.getenv("CHE_AUTH_ENABLED"))) { configureMultiUserMode(); + } else { + configureSingleUserMode(); } } private void configureMultiUserMode() { filter("/*").through(MachineLoginFilter.class); } + + private void configureSingleUserMode() { + filter("/*").through(org.eclipse.che.EnvironmentInitializationFilter.class); + } } diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 66ab720495..6c1da1538e 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -168,9 +168,6 @@ public class WsMasterModule extends AbstractModule { bind(org.eclipse.che.security.oauth.OAuthAuthenticatorProvider.class) .to(org.eclipse.che.security.oauth.OAuthAuthenticatorProviderImpl.class); - bind(org.eclipse.che.security.oauth.shared.OAuthTokenProvider.class) - .to(org.eclipse.che.security.oauth.OAuthAuthenticatorTokenProvider.class); - bind(org.eclipse.che.security.oauth.OAuthAuthenticationService.class); // installers install(new InstallerModule()); @@ -249,6 +246,10 @@ public class WsMasterModule extends AbstractModule { bind(org.eclipse.che.api.user.server.CheUserCreator.class); bindConstant().annotatedWith(Names.named("che.agents.auth_enabled")).to(false); + + bind(org.eclipse.che.security.oauth.shared.OAuthTokenProvider.class) + .to(org.eclipse.che.security.oauth.OAuthAuthenticatorTokenProvider.class); + bind(org.eclipse.che.security.oauth.OAuthAuthenticationService.class); } private void configureMultiUserMode() { diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/cors/CheCorsFilter.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/cors/CheCorsFilter.java index ed4b4738b8..607a6b040a 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/cors/CheCorsFilter.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/cors/CheCorsFilter.java @@ -49,7 +49,7 @@ public class CheCorsFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { corsFilter = new CorsFilter(); - corsFilter.init(new CodenvyCorsFilterConfig()); + corsFilter.init(new CheCorsFilterConfig()); } @Override @@ -64,11 +64,11 @@ public class CheCorsFilter implements Filter { corsFilter.destroy(); } - private class CodenvyCorsFilterConfig implements FilterConfig { + private class CheCorsFilterConfig implements FilterConfig { private final Map filterParams; - public CodenvyCorsFilterConfig() { + public CheCorsFilterConfig() { filterParams = new HashMap<>(); filterParams.put(PARAM_CORS_ALLOWED_ORIGINS, DEFAULT_ALLOWED_ORIGINS); filterParams.put( @@ -77,6 +77,7 @@ public class CheCorsFilter implements Filter { PARAM_CORS_ALLOWED_HEADERS, "Content-Type," + "X-Requested-With," + + "X-Oauth-Token," + "accept," + "Origin," + "Authorization," diff --git a/dockerfiles/init/modules/keycloak/templates/master-realm.json.erb b/dockerfiles/init/modules/keycloak/templates/master-realm.json.erb index 08c285cff6..8d324e6ab2 100644 --- a/dockerfiles/init/modules/keycloak/templates/master-realm.json.erb +++ b/dockerfiles/init/modules/keycloak/templates/master-realm.json.erb @@ -588,6 +588,7 @@ "enabled" : true, "clientAuthenticatorType" : "client-secret", "secret" : "b59b1baf-df65-455d-b185-fda173e29d1b", + "defaultRoles": [ "read-token" ], "redirectUris" : [ ], "webOrigins" : [ ], "notBefore" : 0, diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/Credentials.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/Credentials.java similarity index 95% rename from ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/Credentials.java rename to ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/Credentials.java index 8486b43ba6..64857fc7c0 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/Credentials.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/Credentials.java @@ -8,7 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ -package org.eclipse.che.ide.ui.dialogs.askcredentials; +package org.eclipse.che.ide.api.auth; /** * Credentials object for subversion operations. diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/OAuthServiceClient.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/OAuthServiceClient.java new file mode 100644 index 0000000000..1f828c50b3 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/auth/OAuthServiceClient.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.ide.api.auth; + +import javax.inject.Inject; +import org.eclipse.che.api.auth.shared.dto.OAuthToken; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.rest.AsyncRequestCallback; +import org.eclipse.che.ide.rest.AsyncRequestFactory; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; + +/** + * Serves connections to OauthAuthentication service. Allows to get OAuth tokens via callback or as + * promise. + * + * @author Sergii Leschenko + * @author Max Shaposhnyk + */ +public class OAuthServiceClient { + private final AsyncRequestFactory asyncRequestFactory; + private final String restContext; + private final DtoUnmarshallerFactory unmarshallerFactory; + + @Inject + public OAuthServiceClient( + AppContext appContext, + AsyncRequestFactory asyncRequestFactory, + DtoUnmarshallerFactory unmarshallerFactory) { + this.asyncRequestFactory = asyncRequestFactory; + this.restContext = appContext.getMasterApiEndpoint() + "/oauth"; + this.unmarshallerFactory = unmarshallerFactory; + } + + public void getToken(String oauthProvider, AsyncRequestCallback callback) { + asyncRequestFactory + .createGetRequest(restContext + "/token?oauth_provider=" + oauthProvider) + .send(callback); + } + + public Promise getToken(String oauthProvider) { + return asyncRequestFactory + .createGetRequest(restContext + "/token?oauth_provider=" + oauthProvider) + .send(unmarshallerFactory.newUnmarshaller(OAuthToken.class)); + } +} diff --git a/ide/che-core-ide-app/pom.xml b/ide/che-core-ide-app/pom.xml index 753714124d..e289549057 100644 --- a/ide/che-core-ide-app/pom.xml +++ b/ide/che-core-ide-app/pom.xml @@ -60,6 +60,10 @@ javax.validation validation-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-core diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java index 38f746ba76..21dd9129ba 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/factory/utils/FactoryProjectImporter.java @@ -46,6 +46,7 @@ import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.Credentials; import org.eclipse.che.ide.api.factory.model.FactoryImpl; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; @@ -62,7 +63,6 @@ import org.eclipse.che.ide.projectimport.wizard.ProjectNotificationSubscriber; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.ui.dialogs.DialogFactory; import org.eclipse.che.ide.ui.dialogs.askcredentials.AskCredentialsDialog; -import org.eclipse.che.ide.ui.dialogs.askcredentials.Credentials; import org.eclipse.che.ide.util.ExceptionUtils; import org.eclipse.che.ide.util.StringUtils; import org.eclipse.che.security.oauth.OAuthStatus; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporter.java index 2943861dd0..195e0dedf8 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporter.java @@ -25,16 +25,16 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.Map; +import org.eclipse.che.api.auth.shared.dto.OAuthToken; import org.eclipse.che.api.core.model.workspace.config.SourceStorage; import org.eclipse.che.api.promises.client.Function; import org.eclipse.che.api.promises.client.FunctionException; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper.RequestCall; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.oauth.OAuth2Authenticator; import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorRegistry; import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorUrlProvider; @@ -43,8 +43,9 @@ import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.wizard.Wizard.CompleteCallback; import org.eclipse.che.ide.projectimport.AbstractImporter; import org.eclipse.che.ide.resource.Path; +import org.eclipse.che.ide.rest.AsyncRequestCallback; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.ui.dialogs.askcredentials.AskCredentialsDialog; -import org.eclipse.che.ide.ui.dialogs.askcredentials.Credentials; import org.eclipse.che.ide.util.ExceptionUtils; import org.eclipse.che.security.oauth.OAuthStatus; @@ -59,6 +60,8 @@ public class ProjectImporter extends AbstractImporter { private final ProjectResolver projectResolver; private final AskCredentialsDialog credentialsDialog; private final OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry; + private final OAuthServiceClient oAuthServiceClient; + private final DtoUnmarshallerFactory unmarshallerFactory; @Inject public ProjectImporter( @@ -67,12 +70,16 @@ public class ProjectImporter extends AbstractImporter { AppContext appContext, ProjectResolver projectResolver, AskCredentialsDialog credentialsDialog, - OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry) { + OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry, + DtoUnmarshallerFactory unmarshaller, + OAuthServiceClient oAuthServiceClient) { super(appContext, subscriberFactory); this.localizationConstant = localizationConstant; this.projectResolver = projectResolver; this.credentialsDialog = credentialsDialog; + this.unmarshallerFactory = unmarshaller; this.oAuth2AuthenticatorRegistry = oAuth2AuthenticatorRegistry; + this.oAuthServiceClient = oAuthServiceClient; } public void importProject(final CompleteCallback callback, MutableProjectConfig projectConfig) { @@ -88,21 +95,15 @@ public class ProjectImporter extends AbstractImporter { startImport(path, projectConfig.getSource()) .then( - new Operation() { - @Override - public void apply(Project arg) throws OperationException { - if (callback != null) { - callback.onCompleted(); - } + project -> { + if (callback != null) { + callback.onCompleted(); } }) .catchError( - new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - if (callback != null) { - callback.onFailure(arg.getCause()); - } + error -> { + if (callback != null) { + callback.onFailure(error.getCause()); } }); } @@ -126,13 +127,9 @@ public class ProjectImporter extends AbstractImporter { .withBody(importConfig) .send() .thenPromise( - new Function>() { - @Override - public Promise apply(Project project) throws FunctionException { - subscriber.onSuccess(); - - return projectResolver.resolve(project); - } + project -> { + subscriber.onSuccess(); + return projectResolver.resolve(project); }) .catchErrorPromise( new Function>() { @@ -175,27 +172,18 @@ public class ProjectImporter extends AbstractImporter { credentialsDialog .askCredentials() .then( - new Operation() { - @Override - public void apply(Credentials credentials) throws OperationException { - sourceStorage.getParameters().put("username", credentials.getUsername()); - sourceStorage.getParameters().put("password", credentials.getPassword()); - doImport(path, sourceStorage) - .then( - new Operation() { - @Override - public void apply(Project project) throws OperationException { - callback.onSuccess(project); - } - }) - .catchError( - new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - callback.onFailure(error.getCause()); - } - }); - } + credentials -> { + sourceStorage.getParameters().put("username", credentials.getUsername()); + sourceStorage.getParameters().put("password", credentials.getPassword()); + doImport(path, sourceStorage) + .then( + project -> { + callback.onSuccess(project); + }) + .catchError( + error -> { + callback.onFailure(error.getCause()); + }); }); } }); @@ -230,21 +218,31 @@ public class ProjectImporter extends AbstractImporter { @Override public void onSuccess(OAuthStatus result) { if (!result.equals(OAuthStatus.NOT_PERFORMED)) { - doImport(path, sourceStorage) - .then( - new Operation() { - @Override - public void apply(Project project) throws OperationException { - callback.onSuccess(project); - } - }) - .catchError( - new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - callback.onFailure(error.getCause()); - } - }); + oAuthServiceClient.getToken( + providerName, + new AsyncRequestCallback( + unmarshallerFactory.newUnmarshaller(OAuthToken.class)) { + @Override + protected void onSuccess(OAuthToken result) { + sourceStorage.getParameters().put("username", result.getToken()); + sourceStorage.getParameters().put("password", result.getToken()); + + doImport(path, sourceStorage) + .then( + project -> { + callback.onSuccess(project); + }) + .catchError( + error -> { + callback.onFailure(error.getCause()); + }); + } + + @Override + protected void onFailure(Throwable exception) { + callback.onFailure(new Exception(exception.getMessage())); + } + }); } else { subscriber.onFailure("Authentication cancelled"); callback.onFailure(new IllegalStateException("Authentication cancelled")); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/user/AskCredentialsDialogImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/user/AskCredentialsDialogImpl.java index ab58512536..1fde6f6fdc 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/user/AskCredentialsDialogImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/user/AskCredentialsDialogImpl.java @@ -26,8 +26,8 @@ import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.ide.CoreLocalizationConstant; +import org.eclipse.che.ide.api.auth.Credentials; import org.eclipse.che.ide.ui.dialogs.askcredentials.AskCredentialsDialog; -import org.eclipse.che.ide.ui.dialogs.askcredentials.Credentials; import org.eclipse.che.ide.ui.window.Window; /** diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporterTest.java index 4c0b98fd43..e766256145 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporterTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projectimport/wizard/ProjectImporterTest.java @@ -21,10 +21,12 @@ import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.project.MutableProjectConfig; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.wizard.Wizard; +import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,6 +57,8 @@ public class ProjectImporterTest { @Mock private Project.ProjectRequest importRequest; @Mock private Promise importPromise; @Mock private Project importedProject; + @Mock private OAuthServiceClient oAuthServiceClient; + @Mock private DtoUnmarshallerFactory unmarshallerFactory; @Captor private ArgumentCaptor>> importProjectCaptor; @@ -77,7 +81,14 @@ public class ProjectImporterTest { importer = new ProjectImporter( - localizationConstant, subscriberFactory, appContext, resolver, null, null); + localizationConstant, + subscriberFactory, + appContext, + resolver, + null, + null, + unmarshallerFactory, + oAuthServiceClient); } @Test diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/AskCredentialsDialog.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/AskCredentialsDialog.java index 12c42836ca..71b7b05d75 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/AskCredentialsDialog.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/askcredentials/AskCredentialsDialog.java @@ -12,6 +12,7 @@ package org.eclipse.che.ide.ui.dialogs.askcredentials; import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.auth.Credentials; /** * Dialog for retrieving credentials for operations. diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml b/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml index 1a1ddd37c4..d3baded05a 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml +++ b/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml @@ -54,10 +54,18 @@ javax.ws.rs javax.ws.rs-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-core + + org.eclipse.che.core + che-core-api-dto + org.eclipse.che.core che-core-api-model diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java index 90cdb89d9d..63dafbf4ad 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java @@ -22,7 +22,7 @@ import org.eclipse.che.api.core.rest.Service; /** * Endpoint which provides keycloak public client authentication information (such as URL, realm, - * cliend_id). + * client_id). * * @author Max Shaposhnik (mshaposh@redhat.com) */ diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java index 364e60f84a..8cd8285582 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java @@ -17,6 +17,7 @@ import org.eclipse.che.api.user.server.spi.ProfileDao; import org.eclipse.che.multiuser.keycloak.server.KeycloakConfigurationService; import org.eclipse.che.multiuser.keycloak.server.KeycloakTokenValidator; import org.eclipse.che.multiuser.keycloak.server.dao.KeycloakProfileDao; +import org.eclipse.che.multiuser.keycloak.server.oauth2.KeycloakOAuthAuthenticationService; public class KeycloakModule extends AbstractModule { @Override @@ -26,6 +27,7 @@ public class KeycloakModule extends AbstractModule { .to(org.eclipse.che.multiuser.keycloak.server.KeycloakHttpJsonRequestFactory.class); bind(TokenValidator.class).to(KeycloakTokenValidator.class); bind(KeycloakConfigurationService.class); + bind(KeycloakOAuthAuthenticationService.class); bind(ProfileDao.class).to(KeycloakProfileDao.class); } diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/KeycloakOAuthAuthenticationService.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/KeycloakOAuthAuthenticationService.java new file mode 100644 index 0000000000..574cac9320 --- /dev/null +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/KeycloakOAuthAuthenticationService.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.multiuser.keycloak.server.oauth2; + +import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.AUTH_SERVER_URL_SETTING; +import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; + +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.impl.DefaultClaims; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import org.eclipse.che.api.auth.shared.dto.OAuthToken; +import org.eclipse.che.api.core.BadRequestException; +import org.eclipse.che.api.core.ConflictException; +import org.eclipse.che.api.core.ForbiddenException; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.UnauthorizedException; +import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; +import org.eclipse.che.api.core.rest.annotations.Required; +import org.eclipse.che.dto.server.DtoFactory; +import org.eclipse.che.multiuser.keycloak.server.KeycloakSettings; + +@Path("/oauth") +public class KeycloakOAuthAuthenticationService { + @Context UriInfo uriInfo; + + @Context SecurityContext security; + + private final KeycloakSettings keycloakConfiguration; + + private final HttpJsonRequestFactory requestFactory; + + @Inject + public KeycloakOAuthAuthenticationService( + KeycloakSettings keycloakConfiguration, HttpJsonRequestFactory requestFactory) { + this.keycloakConfiguration = keycloakConfiguration; + this.requestFactory = requestFactory; + } + + /** + * Performs local and Keycloak accounts linking + * + * @return typically Response that redirect user for OAuth provider site + */ + @GET + @Path("authenticate") + public Response authenticate( + @Required @QueryParam("oauth_provider") String oauthProvider, + @Required @QueryParam("redirect_after_login") String redirectAfterLogin, + @Context HttpServletRequest request) + throws ForbiddenException, BadRequestException { + + Jwt jwtToken = (Jwt) request.getAttribute("token"); + if (jwtToken == null) { + throw new BadRequestException("No token provided."); + } + DefaultClaims claims = (DefaultClaims) jwtToken.getBody(); + final String clientId = claims.getAudience(); + final String nonce = UUID.randomUUID().toString(); + final String sessionState = claims.get("session_state", String.class); + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + final String input = nonce + sessionState + clientId + oauthProvider; + byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); + final String hash = Base64.getUrlEncoder().encodeToString(check); + request.getSession().setAttribute("hash", hash); // TODO: for what? + String accountLinkUrl = + UriBuilder.fromUri(keycloakConfiguration.get().get(AUTH_SERVER_URL_SETTING)) + .path("/realms/{realm}/broker/{provider}/link") + .queryParam("nonce", nonce) + .queryParam("hash", hash) + .queryParam("client_id", clientId) + .queryParam("redirect_uri", redirectAfterLogin) + .build(keycloakConfiguration.get().get(REALM_SETTING), oauthProvider) + .toString(); + return Response.temporaryRedirect(URI.create(accountLinkUrl)).build(); + } + + /** + * Gets OAuth token for user from Keycloak. + * + * @param oauthProvider OAuth provider name + * @return OAuthToken + * @throws ServerException + */ + @GET + @Path("token") + @Produces(MediaType.APPLICATION_JSON) + public OAuthToken token(@Required @QueryParam("oauth_provider") String oauthProvider) + throws ForbiddenException, BadRequestException, ConflictException, NotFoundException, + ServerException, UnauthorizedException { + + try { + String token = + requestFactory + .fromUrl( + UriBuilder.fromUri(keycloakConfiguration.get().get(AUTH_SERVER_URL_SETTING)) + .path("/realms/{realm}/broker/{provider}/token") + .build(keycloakConfiguration.get().get(REALM_SETTING), oauthProvider) + .toString()) + .request() + .asString(); + Map params = splitQuery(token); + return DtoFactory.newDto(OAuthToken.class) + .withToken(params.get("access_token")) + .withScope(params.get("scope")); + } catch (IOException e) { + throw new ServerException(e.getMessage()); + } + } + + private static Map splitQuery(String query) { + Map queryPairs = new HashMap<>(); + Arrays.stream(query.split("&")) + .forEach( + p -> { + int delimiterIndex = p.indexOf("="); + queryPairs.put(p.substring(0, delimiterIndex), p.substring(delimiterIndex + 1)); + }); + return queryPairs; + } +} diff --git a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml index 472aa48834..9c0836b298 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/pom.xml +++ b/plugins/plugin-git/che-plugin-git-ext-git/pom.xml @@ -45,6 +45,10 @@ javax.validation validation-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-core diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitAuthActionPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitAuthActionPresenter.java new file mode 100644 index 0000000000..f7a8f28445 --- /dev/null +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitAuthActionPresenter.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.ide.ext.git.client; + +import static org.eclipse.che.api.git.shared.ProviderInfo.PROVIDER_NAME; +import static org.eclipse.che.ide.util.ExceptionUtils.getAttributes; +import static org.eclipse.che.ide.util.ExceptionUtils.getErrorCode; + +import java.util.Map; +import org.eclipse.che.api.core.ErrorCodes; +import org.eclipse.che.api.promises.client.Function; +import org.eclipse.che.api.promises.client.FunctionException; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.api.promises.client.js.Promises; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; +import org.eclipse.che.ide.api.notification.NotificationManager; + +/** + * Base presenter class for authenticated Git operations. + * + * @author Max Shaposhnik (mshaposh@redhat.com) + */ +public class GitAuthActionPresenter { + + protected NotificationManager notificationManager; + protected GitLocalizationConstant locale; + protected OAuthServiceClient oAuthServiceClient; + + public GitAuthActionPresenter( + NotificationManager notificationManager, + GitLocalizationConstant locale, + OAuthServiceClient oAuthServiceClient) { + this.notificationManager = notificationManager; + this.locale = locale; + this.oAuthServiceClient = oAuthServiceClient; + } + + /** + * Performs git operation. If this operations fails with authorization error the operation will be + * recalled with requested credentials + * + * @param operation operation that might require auth + */ + protected Promise performOperationWithTokenRequestIfNeeded( + final RemoteGitOperation operation) { + return operation + .perform(null) + .catchErrorPromise( + new Function>() { + @Override + public Promise apply(PromiseError error) throws FunctionException { + if (getErrorCode(error.getCause()) == ErrorCodes.UNAUTHORIZED_GIT_OPERATION) { + Map attributes = getAttributes(error.getCause()); + String providerName = attributes.get(PROVIDER_NAME); + + return oAuthServiceClient + .getToken(providerName) + .thenPromise( + token -> + Promises.resolve(new Credentials(token.getToken(), token.getToken()))) + .thenPromise(operation::perform); + } + return Promises.reject(error); + } + }); + } + + /** Remote git operation that can require credentials. */ + protected interface RemoteGitOperation { + Promise perform(Credentials credentials); + } +} diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClient.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClient.java index 154e7e2788..290c0b182e 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClient.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClient.java @@ -29,6 +29,7 @@ import org.eclipse.che.api.git.shared.ShowFileContentResponse; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.auth.Credentials; import org.eclipse.che.ide.resource.Path; /** @@ -65,8 +66,14 @@ public interface GitServiceClient { * * * @param removeDeletedRefs if true then delete removed refs from local repository + * @param credentials credentials to perform vcs authorization */ - Promise fetch(Path project, String remote, List refspec, boolean removeDeletedRefs); + Promise fetch( + Path project, + String remote, + List refspec, + boolean removeDeletedRefs, + Credentials credentials); /** * Get the list of the branches. For now, all branches cannot be returned at once, so the @@ -191,8 +198,10 @@ public interface GitServiceClient { * * @param remote remote remote repository's name * @param rebase use rebase instead of merge + * @param credentials credentials to perform vcs authorization */ - Promise pull(Path project, String refSpec, String remote, boolean rebase); + Promise pull( + Path project, String refSpec, String remote, boolean rebase, Credentials credentials); /** * Push changes from local repository to remote one (sends request over WebSocket). @@ -203,8 +212,10 @@ public interface GitServiceClient { * @param force push refuses to update a remote ref that is not an ancestor of the local ref used * to overwrite it. If true disables the check. This can cause the remote * repository to lose commits + * @param credentials credentials to perform vcs authorization */ - Promise push(Path project, List refSpec, String remote, boolean force); + Promise push( + Path project, List refSpec, String remote, boolean force, Credentials credentials); /** * Clones one remote repository to local one (over WebSocket). diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClientImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClientImpl.java index fdb3ee4a6d..38e2d3e184 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClientImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitServiceClientImpl.java @@ -52,6 +52,7 @@ import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.ide.MimeType; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.Credentials; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.rest.AsyncRequest; @@ -213,13 +214,17 @@ public class GitServiceClientImpl implements GitServiceClient { @Override public Promise push( - Path project, List refSpec, String remote, boolean force) { + Path project, List refSpec, String remote, boolean force, Credentials credentials) { PushRequest pushRequest = dtoFactory .createDto(PushRequest.class) .withRemote(remote) .withRefSpec(refSpec) .withForce(force); + if (credentials != null) { + pushRequest.setUsername(credentials.getUsername()); + pushRequest.setPassword(credentials.getPassword()); + } String url = getWsAgentBaseUrl() + PUSH + "?projectPath=" + encodePath(project); return asyncRequestFactory .createPostRequest(url, pushRequest) @@ -391,25 +396,38 @@ public class GitServiceClientImpl implements GitServiceClient { @Override public Promise fetch( - Path project, String remote, List refspec, boolean removeDeletedRefs) { + Path project, + String remote, + List refspec, + boolean removeDeletedRefs, + Credentials credentials) { FetchRequest fetchRequest = dtoFactory .createDto(FetchRequest.class) .withRefSpec(refspec) .withRemote(remote) .withRemoveDeletedRefs(removeDeletedRefs); + if (credentials != null) { + fetchRequest.setUsername(credentials.getUsername()); + fetchRequest.setPassword(credentials.getPassword()); + } String url = getWsAgentBaseUrl() + FETCH + "?projectPath=" + encodePath(project); return asyncRequestFactory.createPostRequest(url, fetchRequest).send(); } @Override - public Promise pull(Path project, String refSpec, String remote, boolean rebase) { + public Promise pull( + Path project, String refSpec, String remote, boolean rebase, Credentials credentials) { PullRequest pullRequest = dtoFactory .createDto(PullRequest.class) .withRemote(remote) .withRefSpec(refSpec) .withRebase(rebase); + if (credentials != null) { + pullRequest.setUsername(credentials.getUsername()); + pullRequest.setPassword(credentials.getPassword()); + } String url = getWsAgentBaseUrl() + PULL + "?projectPath=" + encodePath(project); return asyncRequestFactory .createPostRequest(url, pullRequest) diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java index e4047c5d04..af39d6bc8e 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenter.java @@ -31,13 +31,18 @@ import java.util.List; import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.eclipse.che.api.core.ErrorCodes; +import org.eclipse.che.api.git.shared.PushResponse; import org.eclipse.che.api.git.shared.Revision; +import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.commons.exception.ServerException; import org.eclipse.che.ide.ext.git.client.DateTimeFormatter; +import org.eclipse.che.ide.ext.git.client.GitAuthActionPresenter; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitServiceClient; import org.eclipse.che.ide.ext.git.client.compare.AlteredFiles; @@ -57,7 +62,8 @@ import org.eclipse.che.ide.ui.dialogs.DialogFactory; * @author Igor Vinokur */ @Singleton -public class CommitPresenter implements CommitView.ActionDelegate, SelectionCallBack { +public class CommitPresenter extends GitAuthActionPresenter + implements CommitView.ActionDelegate, SelectionCallBack { private static final String COMMIT_COMMAND_NAME = "Git commit"; private final SelectableChangesPanelPresenter selectableChangesPanelPresenter; @@ -65,8 +71,6 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall private final AppContext appContext; private final CommitView view; private final GitServiceClient service; - private final GitLocalizationConstant constant; - private final NotificationManager notificationManager; private final DateTimeFormatter dateTimeFormatter; private final GitOutputConsoleFactory gitOutputConsoleFactory; private final ProcessesPanelPresenter consolesPanelPresenter; @@ -84,7 +88,9 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall AppContext appContext, DateTimeFormatter dateTimeFormatter, GitOutputConsoleFactory gitOutputConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter) { + ProcessesPanelPresenter processesPanelPresenter, + OAuthServiceClient oAuthServiceClient) { + super(notificationManager, constant, oAuthServiceClient); this.view = view; this.selectableChangesPanelPresenter = selectableChangesPanelPresenter; this.dialogFactory = dialogFactory; @@ -94,9 +100,6 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall this.consolesPanelPresenter = processesPanelPresenter; this.view.setDelegate(this); this.service = service; - this.constant = constant; - this.notificationManager = notificationManager; - this.view.setChangesPanelView(selectableChangesPanelPresenter.getView()); } @@ -142,7 +145,7 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall }) .catchError( arg -> { - notificationManager.notify(constant.diffFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.diffFailed(), FAIL, FLOAT_MODE); }); service @@ -150,17 +153,17 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall .then(view::setRemoteBranchesList) .catchError( error -> { - notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.branchesListFailed(), FAIL, FLOAT_MODE); }); } private void showAskForAmendDialog() { dialogFactory .createConfirmDialog( - constant.commitTitle(), - constant.commitNothingToCommitMessageText(), - constant.buttonYes(), - constant.buttonNo(), + locale.commitTitle(), + locale.commitNothingToCommitMessageText(), + locale.buttonYes(), + locale.buttonNo(), () -> { view.setValueToAmendCheckBox(true); view.setEnablePushAfterCommitCheckBox(false); @@ -210,7 +213,7 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall }) .catchError( error -> { - notificationManager.notify(constant.addFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.addFailed(), FAIL, FLOAT_MODE); }); } @@ -228,15 +231,20 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall String remoteBranch = view.getRemoteBranch(); String remote = remoteBranch.split("/")[0]; String branch = remoteBranch.split("/")[1]; - service - .push(location, singletonList(branch), remote, false) + performOperationWithTokenRequestIfNeeded( + new RemoteGitOperation() { + @Override + public Promise perform(Credentials credentials) { + return service.push(location, singletonList(branch), remote, false, credentials); + } + }) .then( result -> { - notificationManager.notify(constant.pushSuccess(remote), SUCCESS, FLOAT_MODE); + notificationManager.notify(locale.pushSuccess(remote), SUCCESS, FLOAT_MODE); }) .catchError( error -> { - notificationManager.notify(constant.pushFail(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.pushFail(), FAIL, FLOAT_MODE); }); } @@ -276,23 +284,23 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) { dialogFactory .createMessageDialog( - constant.commitTitle(), constant.initCommitWasNotPerformed(), null) + locale.commitTitle(), locale.initCommitWasNotPerformed(), null) .show(); } else { CommitPresenter.this.view.setMessage(""); - notificationManager.notify(constant.logFailed(), FAIL, NOT_EMERGE_MODE); + notificationManager.notify(locale.logFailed(), FAIL, NOT_EMERGE_MODE); } }); } private void onCommitSuccess(@NotNull final Revision revision) { String date = dateTimeFormatter.getFormattedDate(revision.getCommitTime()); - String message = constant.commitMessage(revision.getId(), date); + String message = locale.commitMessage(revision.getId(), date); if ((revision.getCommitter() != null && revision.getCommitter().getName() != null && !revision.getCommitter().getName().isEmpty())) { - message += " " + constant.commitUser(revision.getCommitter().getName()); + message += " " + locale.commitUser(revision.getCommitter().getName()); } GitOutputConsole console = gitOutputConsoleFactory.create(COMMIT_COMMAND_NAME); console.print(message); @@ -306,7 +314,7 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall && ((ServerException) exception).getErrorCode() == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) { dialogFactory - .createMessageDialog(constant.commitTitle(), constant.committerIdentityInfoEmpty(), null) + .createMessageDialog(locale.commitTitle(), locale.committerIdentityInfoEmpty(), null) .show(); return; } @@ -314,10 +322,10 @@ public class CommitPresenter implements CommitView.ActionDelegate, SelectionCall String errorMessage = (exceptionMessage != null && !exceptionMessage.isEmpty()) ? exceptionMessage - : constant.commitFailed(); + : locale.commitFailed(); GitOutputConsole console = gitOutputConsoleFactory.create(COMMIT_COMMAND_NAME); console.printError(errorMessage); consolesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.commitFailed(), errorMessage, FAIL, FLOAT_MODE); + notificationManager.notify(locale.commitFailed(), errorMessage, FAIL, FLOAT_MODE); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java index 20cf24b9f6..bde4d50d7d 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenter.java @@ -26,12 +26,15 @@ import javax.validation.constraints.NotNull; import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchListMode; -import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.git.client.BranchSearcher; +import org.eclipse.che.ide.ext.git.client.GitAuthActionPresenter; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitServiceClient; import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole; @@ -45,18 +48,15 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; * @author Vlad Zhukovskyi */ @Singleton -public class FetchPresenter implements FetchView.ActionDelegate { +public class FetchPresenter extends GitAuthActionPresenter implements FetchView.ActionDelegate { public static final String FETCH_COMMAND_NAME = "Git fetch"; private final DtoFactory dtoFactory; - private final NotificationManager notificationManager; private final BranchSearcher branchSearcher; private final GitOutputConsoleFactory gitOutputConsoleFactory; private final ProcessesPanelPresenter processesPanelPresenter; private final FetchView view; private final GitServiceClient service; - private final AppContext appContext; - private final GitLocalizationConstant constant; private Project project; @@ -65,12 +65,13 @@ public class FetchPresenter implements FetchView.ActionDelegate { DtoFactory dtoFactory, FetchView view, GitServiceClient service, - AppContext appContext, GitLocalizationConstant constant, NotificationManager notificationManager, BranchSearcher branchSearcher, GitOutputConsoleFactory gitOutputConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter) { + ProcessesPanelPresenter processesPanelPresenter, + OAuthServiceClient oauthServiceClient) { + super(notificationManager, constant, oauthServiceClient); this.dtoFactory = dtoFactory; this.view = view; this.branchSearcher = branchSearcher; @@ -78,8 +79,6 @@ public class FetchPresenter implements FetchView.ActionDelegate { this.processesPanelPresenter = processesPanelPresenter; this.view.setDelegate(this); this.service = service; - this.appContext = appContext; - this.constant = constant; this.notificationManager = notificationManager; } @@ -108,9 +107,9 @@ public class FetchPresenter implements FetchView.ActionDelegate { .catchError( error -> { GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); - console.printError(constant.remoteListFailed()); + console.printError(locale.remoteListFailed()); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.remoteListFailed(), FAIL, FLOAT_MODE); view.setEnableFetchButton(false); }); } @@ -142,11 +141,11 @@ public class FetchPresenter implements FetchView.ActionDelegate { .catchError( error -> { final String errorMessage = - error.getMessage() != null ? error.getMessage() : constant.branchesListFailed(); + error.getMessage() != null ? error.getMessage() : locale.branchesListFailed(); GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); console.printError(errorMessage); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.branchesListFailed(), FAIL, FLOAT_MODE); view.setEnableFetchButton(false); }); } @@ -157,18 +156,27 @@ public class FetchPresenter implements FetchView.ActionDelegate { final String remoteUrl = view.getRepositoryUrl(); final StatusNotification notification = - notificationManager.notify(constant.fetchProcess(), PROGRESS, FLOAT_MODE); + notificationManager.notify(locale.fetchProcess(), PROGRESS, FLOAT_MODE); final GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME); - service - .fetch( - project.getLocation(), view.getRepositoryName(), getRefs(), view.isRemoveDeletedRefs()) + performOperationWithTokenRequestIfNeeded( + new RemoteGitOperation() { + @Override + public Promise perform(Credentials credentials) { + return service.fetch( + project.getLocation(), + view.getRepositoryName(), + getRefs(), + view.isRemoveDeletedRefs(), + credentials); + } + }) .then( ignored -> { - console.print(constant.fetchSuccess(remoteUrl)); + console.print(locale.fetchSuccess(remoteUrl)); processesPanelPresenter.addCommandOutput(console); notification.setStatus(SUCCESS); - notification.setTitle(constant.fetchSuccess(remoteUrl)); + notification.setTitle(locale.fetchSuccess(remoteUrl)); }) .catchError( error -> { @@ -208,16 +216,16 @@ public class FetchPresenter implements FetchView.ActionDelegate { String errorMessage = throwable.getMessage(); notification.setStatus(FAIL); if (errorMessage == null) { - console.printError(constant.fetchFail(remoteUrl)); - notification.setTitle(constant.fetchFail(remoteUrl)); + console.printError(locale.fetchFail(remoteUrl)); + notification.setTitle(locale.fetchFail(remoteUrl)); return; } try { errorMessage = dtoFactory.createDtoFromJson(errorMessage, ServiceError.class).getMessage(); if (errorMessage.equals("Unable get private ssh key")) { - console.printError(constant.messagesUnableGetSshKey()); - notification.setTitle(constant.messagesUnableGetSshKey()); + console.printError(locale.messagesUnableGetSshKey()); + notification.setTitle(locale.messagesUnableGetSshKey()); return; } console.printError(errorMessage); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java index a9bf671e0a..af62e7cd4e 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/pull/PullPresenter.java @@ -10,6 +10,7 @@ */ package org.eclipse.che.ide.ext.git.client.pull; +import static org.eclipse.che.api.core.ErrorCodes.MERGE_CONFLICT; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL; import static org.eclipse.che.api.git.shared.BranchListMode.LIST_REMOTE; import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; @@ -26,13 +27,17 @@ import javax.validation.constraints.NotNull; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchListMode; +import org.eclipse.che.api.git.shared.PullResponse; +import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.Notification; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.ext.git.client.BranchSearcher; +import org.eclipse.che.ide.ext.git.client.GitAuthActionPresenter; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitServiceClient; import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole; @@ -47,16 +52,13 @@ import org.eclipse.che.ide.ui.dialogs.DialogFactory; * @author Vlad Zhukovskyi */ @Singleton -public class PullPresenter implements PullView.ActionDelegate { +public class PullPresenter extends GitAuthActionPresenter implements PullView.ActionDelegate { public static final String PULL_COMMAND_NAME = "Git pull"; private static final String GREEN_COLOR = "lightgreen"; private final PullView view; private final GitServiceClient service; - private final GitLocalizationConstant constant; - private final AppContext appContext; - private final NotificationManager notificationManager; private final DialogFactory dialogFactory; private final BranchSearcher branchSearcher; private final GitOutputConsoleFactory gitOutputConsoleFactory; @@ -68,13 +70,14 @@ public class PullPresenter implements PullView.ActionDelegate { public PullPresenter( PullView view, GitServiceClient service, - AppContext appContext, GitLocalizationConstant constant, NotificationManager notificationManager, DialogFactory dialogFactory, BranchSearcher branchSearcher, GitOutputConsoleFactory gitOutputConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter) { + ProcessesPanelPresenter processesPanelPresenter, + OAuthServiceClient oauthServiceClient) { + super(notificationManager, constant, oauthServiceClient); this.view = view; this.dialogFactory = dialogFactory; this.branchSearcher = branchSearcher; @@ -82,8 +85,6 @@ public class PullPresenter implements PullView.ActionDelegate { this.consolesPanelPresenter = processesPanelPresenter; this.view.setDelegate(this); this.service = service; - this.constant = constant; - this.appContext = appContext; this.notificationManager = notificationManager; } @@ -145,29 +146,39 @@ public class PullPresenter implements PullView.ActionDelegate { view.close(); final StatusNotification notification = - notificationManager.notify(constant.pullProcess(), PROGRESS, FLOAT_MODE); + notificationManager.notify(locale.pullProcess(), PROGRESS, FLOAT_MODE); + GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME); - service - .pull(project.getLocation(), getRefs(), view.getRepositoryName(), view.getRebase()) + performOperationWithTokenRequestIfNeeded( + new RemoteGitOperation() { + @Override + public Promise perform(Credentials credentials) { + return service.pull( + project.getLocation(), + getRefs(), + view.getRepositoryName(), + view.getRebase(), + credentials); + } + }) .then( response -> { - GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME); console.print(response.getCommandOutput(), GREEN_COLOR); consolesPanelPresenter.addCommandOutput(console); notification.setStatus(SUCCESS); if (response.getCommandOutput().contains("Already up-to-date")) { - notification.setTitle(constant.pullUpToDate()); + notification.setTitle(locale.pullUpToDate()); } else { project.synchronize(); - notification.setTitle(constant.pullSuccess(view.getRepositoryUrl())); + notification.setTitle(locale.pullSuccess(view.getRepositoryUrl())); } }) .catchError( error -> { - notification.setStatus(FAIL); - if (getErrorCode(error.getCause()) == ErrorCodes.MERGE_CONFLICT) { + if (getErrorCode(error.getCause()) == MERGE_CONFLICT) { project.synchronize(); } + notification.setStatus(FAIL); handleError(error.getCause(), PULL_COMMAND_NAME, notification); }); } @@ -205,12 +216,12 @@ public class PullPresenter implements PullView.ActionDelegate { int errorCode = getErrorCode(exception); if (errorCode == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) { dialogFactory - .createMessageDialog(constant.pullTitle(), constant.committerIdentityInfoEmpty(), null) + .createMessageDialog(locale.pullTitle(), locale.committerIdentityInfoEmpty(), null) .show(); return; } else if (errorCode == ErrorCodes.UNABLE_GET_PRIVATE_SSH_KEY) { dialogFactory - .createMessageDialog(constant.pullTitle(), constant.messagesUnableGetSshKey(), null) + .createMessageDialog(locale.pullTitle(), locale.messagesUnableGetSshKey(), null) .show(); return; } @@ -219,13 +230,13 @@ public class PullPresenter implements PullView.ActionDelegate { if (errorMessage == null) { switch (commandName) { case REMOTE_REPO_COMMAND_NAME: - errorMessage = constant.remoteListFailed(); + errorMessage = locale.remoteListFailed(); break; case BRANCH_LIST_COMMAND_NAME: - errorMessage = constant.branchesListFailed(); + errorMessage = locale.branchesListFailed(); break; case PULL_COMMAND_NAME: - errorMessage = constant.pullFail(view.getRepositoryUrl()); + errorMessage = locale.pullFail(view.getRepositoryUrl()); break; } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java index 3457659535..109e8c24e1 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/push/PushToRemotePresenter.java @@ -29,7 +29,10 @@ import javax.validation.constraints.NotNull; import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchListMode; -import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.api.git.shared.PushResponse; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.api.resources.Project; @@ -37,6 +40,7 @@ import org.eclipse.che.ide.commons.exception.UnauthorizedException; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.git.client.BranchFilterByRemote; import org.eclipse.che.ide.ext.git.client.BranchSearcher; +import org.eclipse.che.ide.ext.git.client.GitAuthActionPresenter; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitServiceClient; import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole; @@ -51,7 +55,8 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter; * @author Vlad Zhukovskyi */ @Singleton -public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { +public class PushToRemotePresenter extends GitAuthActionPresenter + implements PushToRemoteView.ActionDelegate { public static final String PUSH_COMMAND_NAME = "Git push"; public static final String CONFIG_COMMAND_NAME = "Git config"; @@ -61,9 +66,6 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { private final BranchSearcher branchSearcher; private final PushToRemoteView view; private final GitServiceClient service; - private final AppContext appContext; - private final GitLocalizationConstant constant; - private final NotificationManager notificationManager; private Project project; @Inject @@ -71,19 +73,19 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { DtoFactory dtoFactory, PushToRemoteView view, GitServiceClient service, - AppContext appContext, GitLocalizationConstant constant, NotificationManager notificationManager, BranchSearcher branchSearcher, GitOutputConsoleFactory gitOutputConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter) { + ProcessesPanelPresenter processesPanelPresenter, + OAuthServiceClient oAuthServiceClient) { + super(notificationManager, constant, oAuthServiceClient); this.dtoFactory = dtoFactory; this.branchSearcher = branchSearcher; this.view = view; + this.oAuthServiceClient = oAuthServiceClient; this.view.setDelegate(this); this.service = service; - this.appContext = appContext; - this.constant = constant; this.notificationManager = notificationManager; this.gitOutputConsoleFactory = gitOutputConsoleFactory; this.processesPanelPresenter = processesPanelPresenter; @@ -113,11 +115,11 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { .catchError( error -> { String errorMessage = - error.getMessage() != null ? error.getMessage() : constant.remoteListFailed(); + error.getMessage() != null ? error.getMessage() : locale.remoteListFailed(); GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME); console.printError(errorMessage); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.remoteListFailed(), FAIL, FLOAT_MODE); view.setEnablePushButton(false); }); } @@ -149,11 +151,11 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { String errorMessage = exception.getMessage() != null ? exception.getMessage() - : constant.localBranchesListFailed(); + : locale.localBranchesListFailed(); GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME); console.printError(errorMessage); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.localBranchesListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.localBranchesListFailed(), FAIL, FLOAT_MODE); view.setEnablePushButton(false); } }); @@ -207,9 +209,9 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { @Override public void onFailure(Throwable caught) { GitOutputConsole console = gitOutputConsoleFactory.create(CONFIG_COMMAND_NAME); - console.printError(constant.failedGettingConfig()); + console.printError(locale.failedGettingConfig()); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.failedGettingConfig(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.failedGettingConfig(), FAIL, FLOAT_MODE); } }); } @@ -219,11 +221,11 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { String errorMessage = exception.getMessage() != null ? exception.getMessage() - : constant.remoteBranchesListFailed(); + : locale.remoteBranchesListFailed(); GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME); console.printError(errorMessage); processesPanelPresenter.addCommandOutput(console); - notificationManager.notify(constant.remoteBranchesListFailed(), FAIL, FLOAT_MODE); + notificationManager.notify(locale.remoteBranchesListFailed(), FAIL, FLOAT_MODE); view.setEnablePushButton(false); } }); @@ -287,21 +289,32 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { @Override public void onPushClicked() { final StatusNotification notification = - notificationManager.notify(constant.pushProcess(), PROGRESS, FLOAT_MODE); + notificationManager.notify(locale.pushProcess(), PROGRESS, FLOAT_MODE); final String repository = view.getRepository(); final GitOutputConsole console = gitOutputConsoleFactory.create(PUSH_COMMAND_NAME); - service - .push(project.getLocation(), getRefs(), repository, view.isForcePushSelected()) + + performOperationWithTokenRequestIfNeeded( + new RemoteGitOperation() { + @Override + public Promise perform(Credentials credentials) { + return service.push( + project.getLocation(), + getRefs(), + repository, + view.isForcePushSelected(), + credentials); + } + }) .then( response -> { console.print(response.getCommandOutput()); processesPanelPresenter.addCommandOutput(console); notification.setStatus(SUCCESS); if (response.getCommandOutput().contains("Everything up-to-date")) { - notification.setTitle(constant.pushUpToDate()); + notification.setTitle(locale.pushUpToDate()); } else { - notification.setTitle(constant.pushSuccess(repository)); + notification.setTitle(locale.pushSuccess(repository)); } }) .catchError( @@ -347,25 +360,25 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate { @NotNull Throwable throwable, StatusNotification notification, GitOutputConsole console) { notification.setStatus(FAIL); if (throwable instanceof UnauthorizedException) { - console.printError(constant.messagesNotAuthorizedTitle()); - console.print(constant.messagesNotAuthorizedContent()); - notification.setTitle(constant.messagesNotAuthorizedTitle()); - notification.setContent(constant.messagesNotAuthorizedContent()); + console.printError(locale.messagesNotAuthorizedTitle()); + console.print(locale.messagesNotAuthorizedContent()); + notification.setTitle(locale.messagesNotAuthorizedTitle()); + notification.setContent(locale.messagesNotAuthorizedContent()); return; } String errorMessage = throwable.getMessage(); if (errorMessage == null) { - console.printError(constant.pushFail()); - notification.setTitle(constant.pushFail()); + console.printError(locale.pushFail()); + notification.setTitle(locale.pushFail()); return; } try { errorMessage = dtoFactory.createDtoFromJson(errorMessage, ServiceError.class).getMessage(); if (errorMessage.equals("Unable get private ssh key")) { - console.printError(constant.messagesUnableGetSshKey()); - notification.setTitle(constant.messagesUnableGetSshKey()); + console.printError(locale.messagesUnableGetSshKey()); + notification.setTitle(locale.messagesUnableGetSshKey()); return; } console.printError(errorMessage); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java index 005b8f40ad..2b8fada0a1 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/commit/CommitPresenterTest.java @@ -34,6 +34,7 @@ import org.eclipse.che.api.git.shared.Revision; import org.eclipse.che.api.git.shared.Status; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.commons.exception.ServerException; @@ -61,6 +62,7 @@ public class CommitPresenterTest extends BaseTest { @Mock private CommitView view; @Mock private DateTimeFormatter dateTimeFormatter; @Mock private SelectableChangesPanelPresenter selectableChangesPanelPresenter; + @Mock private OAuthServiceClient oAuthServiceClient; private CommitPresenter presenter; @@ -80,7 +82,8 @@ public class CommitPresenterTest extends BaseTest { appContext, dateTimeFormatter, gitOutputConsoleFactory, - processesPanelPresenter)); + processesPanelPresenter, + oAuthServiceClient)); when(view.getCommitMessage()).thenReturn(EMPTY_TEXT); @@ -116,7 +119,7 @@ public class CommitPresenterTest extends BaseTest { .thenReturn(stringPromise); when(service.branchList(any(Path.class), any(BranchListMode.class))) .thenReturn(branchListPromise); - when(service.push(any(Path.class), anyList(), anyString(), anyBoolean())) + when(service.push(any(Path.class), anyList(), anyString(), anyBoolean(), null)) .thenReturn(pushPromise); when(service.log(any(Path.class), eq(null), anyInt(), anyInt(), anyBoolean())) .thenReturn(logPromise); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java index 5b29613143..84c223cb93 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/fetch/FetchPresenterTest.java @@ -25,6 +25,7 @@ import java.util.List; import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.Remote; import org.eclipse.che.api.promises.client.Operation; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.ext.git.client.BaseTest; import org.eclipse.che.ide.ext.git.client.BranchSearcher; import org.eclipse.che.ide.resource.Path; @@ -43,6 +44,7 @@ public class FetchPresenterTest extends BaseTest { @Mock private FetchView view; @Mock private Branch branch; @Mock private BranchSearcher branchSearcher; + @Mock private OAuthServiceClient oAuthServiceClient; private FetchPresenter presenter; @@ -55,12 +57,12 @@ public class FetchPresenterTest extends BaseTest { dtoFactory, view, service, - appContext, constant, notificationManager, branchSearcher, gitOutputConsoleFactory, - processesPanelPresenter); + processesPanelPresenter, + oAuthServiceClient); when(service.remoteList(any(Path.class), anyString(), anyBoolean())) .thenReturn(remoteListPromise); diff --git a/plugins/plugin-github/che-plugin-github-ide/pom.xml b/plugins/plugin-github/che-plugin-github-ide/pom.xml index 8d23343c84..a78df5fff3 100644 --- a/plugins/plugin-github/che-plugin-github-ide/pom.xml +++ b/plugins/plugin-github/che-plugin-github-ide/pom.xml @@ -41,6 +41,10 @@ javax.validation validation-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-dto diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientService.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClient.java similarity index 64% rename from plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientService.java rename to plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClient.java index 1929dd4799..b492e9e68e 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientService.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClient.java @@ -30,38 +30,47 @@ import org.eclipse.che.plugin.github.shared.GitHubUser; * @author Oksana Vereshchaka * @author Kevin Pollet */ -public interface GitHubClientService { +public interface GitHubServiceClient { /** * Get given repository information. * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository. * @param repository the repository name. */ - Promise getRepository(String user, String repository); + Promise getRepository(String oauthToken, String user, String repository); - /** Get list of available public and private repositories of the authorized user. */ - Promise> getRepositoriesList(); + /** + * Get list of available public and private repositories of the authorized user. + * + * @param oauthToken Github OAuth authorization token + */ + Promise> getRepositoriesList(String oauthToken); /** * Get list of forks for given repository * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository. * @param repository the repository name. */ - Promise getForks(String user, String repository); + Promise getForks( + @NotNull String oauthToken, String user, String repository); /** * Fork the given repository for the authorized user. * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository to fork. * @param repository the repository name. */ - Promise fork(String user, String repository); + Promise fork(@NotNull String oauthToken, String user, String repository); /** * Add a comment to the issue on the given repository. * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository. * @param repository the repository name. * @param issue the issue number. @@ -69,6 +78,7 @@ public interface GitHubClientService { * @param callback callback called when operation is done. */ void commentIssue( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull String issue, @@ -78,23 +88,28 @@ public interface GitHubClientService { /** * Get pull requests for given repository. * + * @param oauthToken Github OAuth authorization token * @param owner the repository owner. * @param repository the repository name. */ - Promise getPullRequests(@NotNull String owner, @NotNull String repository); + Promise getPullRequests( + @NotNull String oauthToken, @NotNull String owner, @NotNull String repository); /** * Get pull requests for given repository. * + * @param oauthToken Github OAuth authorization token * @param owner the repository owner. * @param repository the repository name. * @param head user and branch name in the format of user:ref-name */ - Promise getPullRequests(String owner, String repository, String head); + Promise getPullRequests( + @NotNull String oauthToken, String owner, String repository, String head); /** * Get a pull request by id for a given repository. * + * @param oauthToken Github OAuth authorization token * @param owner the owner of the target repository * @param repository the target repository * @param pullRequestId the Id of the pull request @@ -102,6 +117,7 @@ public interface GitHubClientService { * exist */ void getPullRequest( + @NotNull String oauthToken, @NotNull String owner, @NotNull String repository, @NotNull String pullRequestId, @@ -110,11 +126,13 @@ public interface GitHubClientService { /** * Create a pull request on origin repository * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository. * @param repository the repository name. * @param input the pull request information. */ Promise createPullRequest( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull GitHubPullRequestCreationInput input); @@ -122,59 +140,80 @@ public interface GitHubClientService { /** * Get the list of available public repositories for a GitHub user. * + * @param oauthToken Github OAuth authorization token * @param userName the name of GitHub User * @param callback callback called when operation is done. */ void getRepositoriesByUser( - String userName, @NotNull AsyncRequestCallback callback); + @NotNull String oauthToken, + String userName, + @NotNull AsyncRequestCallback callback); /** * Get the list of available repositories by GitHub organization. * + * @param oauthToken Github OAuth authorization token * @param organization the name of GitHub organization. * @param callback callback called when operation is done. */ void getRepositoriesByOrganization( - String organization, @NotNull AsyncRequestCallback callback); + @NotNull String oauthToken, + String organization, + @NotNull AsyncRequestCallback callback); /** * Get list of available public repositories for GitHub account. * + * @param oauthToken Github OAuth authorization token * @param account the GitHub account. * @param callback callback called when operation is done. */ void getRepositoriesByAccount( - String account, @NotNull AsyncRequestCallback callback); + @NotNull String oauthToken, + String account, + @NotNull AsyncRequestCallback callback); /** * Get list of collaborators of GitHub repository. For detail see GitHub REST API * http://developer.github.com/v3/repos/collaborators/. * + * @param oauthToken Github OAuth authorization token * @param user the owner of the repository. * @param repository the repository name. * @param callback callback called when operation is done. */ void getCollaborators( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull AsyncRequestCallback callback); - /** Get the list of the organizations, where authorized user is a member. */ - Promise> getOrganizations(); + /** + * Get the list of the organizations, where authorized user is a member. + * + * @param oauthToken Github OAuth authorization token + */ + Promise> getOrganizations(@NotNull String oauthToken); - /** Get authorized user information. */ - Promise getUserInfo(); + /** + * Get authorized user information. + * + * @param oauthToken Github OAuth authorization token + */ + Promise getUserInfo(@NotNull String oauthToken); /** * Generate and upload new public key if not exist on github.com. * + * @param oauthToken Github OAuth authorization token * @param callback callback called when operation is done. */ - void updatePublicKey(@NotNull AsyncRequestCallback callback); + void updatePublicKey(@NotNull String oauthToken, @NotNull AsyncRequestCallback callback); /** * Updates github pull request * + * @param oauthToken Github OAuth authorization token * @param user repository owner * @param repository name of repository * @param pullRequestId pull request identifier @@ -182,5 +221,9 @@ public interface GitHubClientService { * @return updated pull request */ Promise updatePullRequest( - String user, String repository, String pullRequestId, GitHubPullRequest pullRequest); + @NotNull String oauthToken, + String user, + String repository, + String pullRequestId, + GitHubPullRequest pullRequest); } diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientServiceImpl.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClientImpl.java similarity index 69% rename from plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientServiceImpl.java rename to plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClientImpl.java index 179aac22f5..7ea1559f2b 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubClientServiceImpl.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubServiceClientImpl.java @@ -33,13 +33,15 @@ import org.eclipse.che.plugin.github.shared.GitHubRepositoryList; import org.eclipse.che.plugin.github.shared.GitHubUser; /** - * Implementation for {@link GitHubClientService}. + * Implementation for {@link GitHubServiceClient}. * * @author Oksana Vereshchaka * @author Stéphane Daviet */ @Singleton -public class GitHubClientServiceImpl implements GitHubClientService { +public class GitHubServiceClientImpl implements GitHubServiceClient { + + private static final String TOKEN_HEADER_NAME = "X-Oauth-Token"; private static final String LIST = "/list"; private static final String LIST_ACCOUNT = "/list/account"; private static final String LIST_ORG = "/list/org"; @@ -63,7 +65,7 @@ public class GitHubClientServiceImpl implements GitHubClientService { private final DtoUnmarshallerFactory dtoUnmarshallerFactory; @Inject - protected GitHubClientServiceImpl( + protected GitHubServiceClientImpl( LoaderFactory loaderFactory, AsyncRequestFactory asyncRequestFactory, AppContext appContext, @@ -79,89 +81,110 @@ public class GitHubClientServiceImpl implements GitHubClientService { } @Override - public Promise getRepository(String user, String repository) { + public Promise getRepository( + @NotNull String oauthToken, String user, String repository) { final String url = baseUrl() + REPOSITORIES + "/" + user + "/" + repository; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubRepository.class)); } /** {@inheritDoc} */ @Override - public Promise> getRepositoriesList() { + public Promise> getRepositoriesList(@NotNull String oauthToken) { String url = baseUrl() + LIST; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newListUnmarshaller(GitHubRepository.class)); } @Override - public Promise getForks(String user, String repository) { + public Promise getForks( + @NotNull String oauthToken, String user, String repository) { return asyncRequestFactory .createGetRequest(baseUrl() + FORKS + '/' + user + '/' + repository) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubRepositoryList.class)); } @Override - public Promise fork(String user, String repository) { + public Promise fork( + @NotNull String oauthToken, String user, String repository) { return asyncRequestFactory .createGetRequest(baseUrl() + CREATE_FORK + '/' + user + '/' + repository) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubRepository.class)); } @Override public void commentIssue( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull String issue, @NotNull GitHubIssueCommentInput input, @NotNull AsyncRequestCallback callback) { String url = baseUrl() + ISSUE_COMMENTS + "/" + user + "/" + repository + "/" + issue; - asyncRequestFactory.createPostRequest(url, input).loader(loader).send(callback); + asyncRequestFactory + .createPostRequest(url, input) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } @Override public Promise getPullRequests( - @NotNull String owner, @NotNull String repository) { + @NotNull String oauthToken, @NotNull String owner, @NotNull String repository) { final String url = baseUrl() + PULL_REQUESTS + '/' + owner + '/' + repository; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubPullRequestList.class)); } @Override public Promise getPullRequests( - String owner, String repository, String head) { + @NotNull String oauthToken, String owner, String repository, String head) { final String url = baseUrl() + PULL_REQUESTS + '/' + owner + '/' + repository + "?head=" + head; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubPullRequestList.class)); } @Override public void getPullRequest( + @NotNull String oauthToken, final String owner, final String repository, final String pullRequestId, final AsyncRequestCallback callback) { String url = baseUrl() + PULL_REQUESTS + "/" + owner + "/" + repository + "/" + pullRequestId; - asyncRequestFactory.createGetRequest(url).loader(loader).send(callback); + asyncRequestFactory + .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } @Override public Promise createPullRequest( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull GitHubPullRequestCreationInput input) { final String url = baseUrl() + PULL_REQUEST + '/' + user + '/' + repository; return asyncRequestFactory .createPostRequest(url, input) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubPullRequest.class)); } @@ -169,38 +192,51 @@ public class GitHubClientServiceImpl implements GitHubClientService { /** {@inheritDoc} */ @Override public void getRepositoriesByUser( - String userName, @NotNull AsyncRequestCallback callback) { + @NotNull String oauthToken, + String userName, + @NotNull AsyncRequestCallback callback) { String params = (userName != null) ? "?username=" + userName : ""; String url = baseUrl() + LIST_USER; - asyncRequestFactory.createGetRequest(url + params).loader(loader).send(callback); + asyncRequestFactory + .createGetRequest(url + params) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } /** {@inheritDoc} */ @Override public void getCollaborators( + @NotNull String oauthToken, @NotNull String user, @NotNull String repository, @NotNull AsyncRequestCallback callback) { String url = baseUrl() + COLLABORATORS + "/" + user + "/" + repository; - asyncRequestFactory.createGetRequest(url).loader(loader).send(callback); + asyncRequestFactory + .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } /** {@inheritDoc} */ @Override - public Promise> getOrganizations() { + public Promise> getOrganizations(@NotNull String oauthToken) { String url = baseUrl() + ORGANIZATIONS; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newListUnmarshaller(GitHubUser.class)); } /** {@inheritDoc} */ @Override - public Promise getUserInfo() { + public Promise getUserInfo(@NotNull String oauthToken) { String url = baseUrl() + USER; return asyncRequestFactory .createGetRequest(url) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubUser.class)); } @@ -208,35 +244,56 @@ public class GitHubClientServiceImpl implements GitHubClientService { /** {@inheritDoc} */ @Override public void getRepositoriesByOrganization( - String organization, @NotNull AsyncRequestCallback callback) { + @NotNull String oauthToken, + String organization, + @NotNull AsyncRequestCallback callback) { String params = (organization != null) ? "?organization=" + organization : ""; String url = baseUrl() + LIST_ORG; - asyncRequestFactory.createGetRequest(url + params).loader(loader).send(callback); + asyncRequestFactory + .createGetRequest(url + params) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } /** {@inheritDoc} */ @Override public void getRepositoriesByAccount( - String account, @NotNull AsyncRequestCallback callback) { + @NotNull String oauthToken, + String account, + @NotNull AsyncRequestCallback callback) { String params = (account != null) ? "?account=" + account : ""; String url = baseUrl() + LIST_ACCOUNT; - asyncRequestFactory.createGetRequest(url + params).loader(loader).send(callback); + asyncRequestFactory + .createGetRequest(url + params) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } /** {@inheritDoc} */ @Override - public void updatePublicKey(@NotNull AsyncRequestCallback callback) { + public void updatePublicKey(String oauthToken, @NotNull AsyncRequestCallback callback) { String url = baseUrl() + SSH_GEN; - asyncRequestFactory.createPostRequest(url, null).loader(loader).send(callback); + asyncRequestFactory + .createPostRequest(url, null) + .header(TOKEN_HEADER_NAME, oauthToken) + .loader(loader) + .send(callback); } @Override public Promise updatePullRequest( - String owner, String repository, String pullRequestId, GitHubPullRequest updateInput) { + @NotNull String oauthToken, + String owner, + String repository, + String pullRequestId, + GitHubPullRequest updateInput) { final String url = baseUrl() + PULL_REQUEST + '/' + owner + '/' + repository + '/' + pullRequestId; return asyncRequestFactory .createRequest(RequestBuilder.PUT, url, updateInput, false) + .header(TOKEN_HEADER_NAME, oauthToken) .loader(loader) .send(dtoUnmarshallerFactory.newUnmarshaller(GitHubPullRequest.class)); } diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubSshKeyUploader.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubSshKeyUploader.java index c36a6a9aa0..4b63765e3e 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubSshKeyUploader.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/GitHubSshKeyUploader.java @@ -18,13 +18,12 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.ide.api.ProductInfoDataProvider; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.commons.exception.UnauthorizedException; import org.eclipse.che.ide.rest.AsyncRequestCallback; -import org.eclipse.che.ide.ui.dialogs.CancelCallback; import org.eclipse.che.ide.ui.dialogs.DialogFactory; -import org.eclipse.che.ide.ui.dialogs.confirm.ConfirmCallback; import org.eclipse.che.plugin.ssh.key.client.SshKeyUploader; import org.eclipse.che.security.oauth.JsOAuthWindow; import org.eclipse.che.security.oauth.OAuthCallback; @@ -39,7 +38,7 @@ import org.eclipse.che.security.oauth.SecurityTokenProvider; @Singleton public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback { - private final GitHubClientService gitHubService; + private final GitHubServiceClient gitHubService; private final String baseUrl; private final GitHubLocalizationConstant constant; private final NotificationManager notificationManager; @@ -47,19 +46,21 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback { private final DialogFactory dialogFactory; private final AppContext appContext; private final SecurityTokenProvider securityTokenProvider; + private final OAuthServiceClient oAuthServiceClient; private AsyncCallback callback; private String userId; @Inject public GitHubSshKeyUploader( - GitHubClientService gitHubService, + GitHubServiceClient gitHubService, GitHubLocalizationConstant constant, NotificationManager notificationManager, ProductInfoDataProvider productInfoDataProvider, DialogFactory dialogFactory, AppContext appContext, - SecurityTokenProvider securityTokenProvider) { + SecurityTokenProvider securityTokenProvider, + OAuthServiceClient oAuthServiceClient) { this.gitHubService = gitHubService; this.baseUrl = appContext.getMasterApiEndpoint(); this.constant = constant; @@ -68,6 +69,7 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback { this.dialogFactory = dialogFactory; this.appContext = appContext; this.securityTokenProvider = securityTokenProvider; + this.oAuthServiceClient = oAuthServiceClient; } /** {@inheritDoc} */ @@ -76,23 +78,32 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback { this.callback = callback; this.userId = userId; - gitHubService.updatePublicKey( - new AsyncRequestCallback() { - @Override - protected void onSuccess(Void o) { - callback.onSuccess(o); - } + oAuthServiceClient + .getToken("github") + .then( + result -> { + gitHubService.updatePublicKey( + result.getToken(), + new AsyncRequestCallback() { + @Override + protected void onSuccess(Void o) { + callback.onSuccess(o); + } - @Override - protected void onFailure(Throwable e) { - if (e instanceof UnauthorizedException) { + @Override + protected void onFailure(Throwable e) { + if (e instanceof UnauthorizedException) { + oAuthLoginStart(); + return; + } + callback.onFailure(e); + } + }); + }) + .catchError( + error -> { oAuthLoginStart(); - return; - } - - callback.onFailure(e); - } - }); + }); } /** Log in github */ @@ -101,18 +112,8 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback { .createConfirmDialog( constant.authorizationDialogTitle(), constant.authorizationDialogText(productInfoDataProvider.getName()), - new ConfirmCallback() { - @Override - public void accepted() { - showPopUp(); - } - }, - new CancelCallback() { - @Override - public void cancelled() { - callback.onFailure(new Exception(constant.authorizationRequestRejected())); - } - }) + () -> showPopUp(), + () -> callback.onFailure(new Exception(constant.authorizationRequestRejected()))) .show(); } diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/authenticator/GitHubAuthenticatorImpl.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/authenticator/GitHubAuthenticatorImpl.java index c421da6965..45ba586542 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/authenticator/GitHubAuthenticatorImpl.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/authenticator/GitHubAuthenticatorImpl.java @@ -56,7 +56,7 @@ public class GitHubAuthenticatorImpl private final GitHubLocalizationConstant locale; private final String baseUrl; private final AppContext appContext; - private final SecurityTokenProvider securityTokenPærovider; + private final SecurityTokenProvider securityTokenProvider; private String authenticationUrl; @Inject @@ -68,11 +68,11 @@ public class GitHubAuthenticatorImpl GitHubLocalizationConstant locale, NotificationManager notificationManager, AppContext appContext, - SecurityTokenProvider securityTokenPærovider) { + SecurityTokenProvider securityTokenProvider) { this.registry = registry; this.sshServiceClient = sshServiceClient; this.view = view; - this.securityTokenPærovider = securityTokenPærovider; + this.securityTokenProvider = securityTokenProvider; this.view.setDelegate(this); this.locale = locale; this.baseUrl = appContext.getMasterApiEndpoint(); @@ -130,10 +130,10 @@ public class GitHubAuthenticatorImpl JsOAuthWindow authWindow; if (authenticationUrl == null) { authWindow = - new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this, securityTokenPærovider); + new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this, securityTokenProvider); } else { authWindow = - new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this, securityTokenPærovider); + new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this, securityTokenProvider); } authWindow.loginWithOAuth(); } diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenter.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenter.java index 76d089118d..3409a652a7 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenter.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenter.java @@ -10,6 +10,9 @@ */ package org.eclipse.che.plugin.github.ide.importer.page; +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; + import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.gwt.core.client.JsArrayMixed; @@ -18,18 +21,16 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.inject.Inject; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.validation.constraints.NotNull; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; +import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.oauth.OAuth2Authenticator; import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorRegistry; import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorUrlProvider; @@ -38,8 +39,8 @@ import org.eclipse.che.ide.api.wizard.AbstractWizardPage; import org.eclipse.che.ide.commons.exception.UnauthorizedException; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.util.NameUtils; -import org.eclipse.che.plugin.github.ide.GitHubClientService; import org.eclipse.che.plugin.github.ide.GitHubLocalizationConstant; +import org.eclipse.che.plugin.github.ide.GitHubServiceClient; import org.eclipse.che.plugin.github.ide.load.ProjectData; import org.eclipse.che.plugin.github.shared.GitHubRepository; import org.eclipse.che.plugin.github.shared.GitHubUser; @@ -65,13 +66,15 @@ public class GithubImporterPagePresenter extends AbstractWizardPage> repositories; private GitHubLocalizationConstant locale; private GithubImporterPageView view; private final String baseUrl; private final AppContext appContext; private OAuth2Authenticator gitHubAuthenticator; + private final OAuthServiceClient oAuthServiceClient; + private final NotificationManager notificationManager; private boolean ignoreChanges; @@ -79,16 +82,20 @@ public class GithubImporterPagePresenter extends AbstractWizardPage userInfo = gitHubClientService.getUserInfo(); - Promise> organizations = gitHubClientService.getOrganizations(); - Promise> allRepositories = gitHubClientService.getRepositoriesList(); - - doRequest(userInfo, organizations, allRepositories); - } - - protected void doRequest( - Promise userInfo, - Promise> organizations, - Promise> allRepositories) { - Promises.all(userInfo, organizations, allRepositories) - .then( - new Operation() { - @Override - public void apply(JsArrayMixed arg) throws OperationException { - onSuccessRequest(arg); - } - }) - .catchError( - new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - onFailRequest(arg); - } - }); + oAuthServiceClient + .getToken(gitHubAuthenticator.getProviderName()) + .thenPromise( + token -> + Promises.all( + gitHubClientService.getUserInfo(token.getToken()), + gitHubClientService.getOrganizations(token.getToken()), + gitHubClientService.getRepositoriesList(token.getToken()))) + .then(this::onSuccessRequest) + .catchError(this::onFailRequest); } protected void onSuccessRequest(JsArrayMixed arg) { @@ -308,6 +299,8 @@ public class GithubImporterPagePresenter extends AbstractWizardPage login2OrgName = getLogin2OrgName(gitHubOrganizations); for (String orgName : login2OrgName.values()) { - repositories.put(orgName, new ArrayList()); + repositories.put(orgName, new ArrayList<>()); } for (GitHubRepository gitHubRepository : gitHubRepositories) { @@ -410,14 +403,7 @@ public class GithubImporterPagePresenter extends AbstractWizardPage() { - @Override - public int compare(ProjectData o1, ProjectData o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + projectsData.sort(Comparator.comparing(ProjectData::getName)); view.setRepositories(projectsData); view.reset(); diff --git a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/inject/GitHubGinModule.java b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/inject/GitHubGinModule.java index 8bcdcdb940..83fbe5dc47 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/inject/GitHubGinModule.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/main/java/org/eclipse/che/plugin/github/ide/inject/GitHubGinModule.java @@ -16,8 +16,8 @@ import com.google.inject.Singleton; import org.eclipse.che.ide.api.extension.ExtensionGinModule; import org.eclipse.che.ide.api.oauth.OAuth2Authenticator; import org.eclipse.che.ide.api.project.wizard.ImportWizardRegistrar; -import org.eclipse.che.plugin.github.ide.GitHubClientService; -import org.eclipse.che.plugin.github.ide.GitHubClientServiceImpl; +import org.eclipse.che.plugin.github.ide.GitHubServiceClient; +import org.eclipse.che.plugin.github.ide.GitHubServiceClientImpl; import org.eclipse.che.plugin.github.ide.authenticator.GitHubAuthenticatorImpl; import org.eclipse.che.plugin.github.ide.importer.GitHubImportWizardRegistrar; @@ -27,7 +27,7 @@ public class GitHubGinModule extends AbstractGinModule { /** {@inheritDoc} */ @Override protected void configure() { - bind(GitHubClientService.class).to(GitHubClientServiceImpl.class).in(Singleton.class); + bind(GitHubServiceClient.class).to(GitHubServiceClientImpl.class).in(Singleton.class); GinMultibinder.newSetBinder(binder(), OAuth2Authenticator.class) .addBinding() .to(GitHubAuthenticatorImpl.class); diff --git a/plugins/plugin-github/che-plugin-github-ide/src/test/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenterTest.java b/plugins/plugin-github/che-plugin-github-ide/src/test/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenterTest.java index 76be63dc04..0521964298 100644 --- a/plugins/plugin-github/che-plugin-github-ide/src/test/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenterTest.java +++ b/plugins/plugin-github/che-plugin-github-ide/src/test/java/org/eclipse/che/plugin/github/ide/importer/page/GithubImporterPagePresenterTest.java @@ -13,11 +13,9 @@ package org.eclipse.che.plugin.github.ide.importer.page; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -27,21 +25,18 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.gwt.core.client.JsArrayMixed; -import com.google.gwt.http.client.Response; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwtmockito.GwtMockitoTestRunner; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor; -import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.app.CurrentUser; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.oauth.OAuth2Authenticator; import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorRegistry; @@ -49,12 +44,9 @@ import org.eclipse.che.ide.api.project.MutableProjectConfig; import org.eclipse.che.ide.api.wizard.Wizard; import org.eclipse.che.ide.commons.exception.UnauthorizedException; import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.rest.AsyncRequestCallback; -import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; -import org.eclipse.che.plugin.github.ide.GitHubClientService; import org.eclipse.che.plugin.github.ide.GitHubLocalizationConstant; +import org.eclipse.che.plugin.github.ide.GitHubServiceClient; import org.eclipse.che.plugin.github.ide.load.ProjectData; -import org.eclipse.che.plugin.github.shared.GitHubRepository; import org.eclipse.che.plugin.github.shared.GitHubUser; import org.eclipse.che.security.oauth.OAuthStatus; import org.junit.Before; @@ -64,8 +56,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; /** * Testing {@link GithubImporterPagePresenter} functionality. @@ -77,30 +67,20 @@ public class GithubImporterPagePresenterTest { @Captor private ArgumentCaptor> asyncCallbackCaptor; - @Captor - private ArgumentCaptor>>> - asyncRequestCallbackRepoListCaptor; - @Mock private Wizard.UpdateDelegate updateDelegate; @Mock private DtoFactory dtoFactory; @Mock private GithubImporterPageView view; - @Mock private GitHubClientService gitHubClientService; - @Mock private DtoUnmarshallerFactory dtoUnmarshallerFactory; - @Mock private NotificationManager notificationManager; + @Mock private GitHubServiceClient gitHubClientService; @Mock private GitHubLocalizationConstant locale; @Mock private MutableProjectConfig dataObject; @Mock private MutableProjectConfig.MutableSourceStorage source; - @Mock private Map parameters; - @Mock private Promise gitHubUserPromise; - @Mock private Promise> gitHubOrgsPromise; - @Mock private Promise> gitHubReposPromise; - @Mock private JsArrayMixed jsArrayMixed; @Mock private GitHubUser gitHubUser; @Mock private PromiseError promiseError; - @Mock private Response response; @Mock private OAuth2Authenticator gitHubAuthenticator; @Mock private OAuth2AuthenticatorRegistry gitHubAuthenticatorRegistry; @Mock private AppContext appContext; + @Mock private OAuthServiceClient oAuthServiceClient; + @Mock private NotificationManager notificationManager; private GithubImporterPagePresenter presenter; @@ -120,7 +100,9 @@ public class GithubImporterPagePresenterTest { gitHubClientService, dtoFactory, appContext, - locale)); + locale, + oAuthServiceClient, + notificationManager)); doReturn(Collections.singletonList(gitHubUser)) .when(presenter) .toOrgList(nullable(JsArrayMixed.class)); @@ -151,68 +133,46 @@ public class GithubImporterPagePresenterTest { @Test public void onLoadRepoClickedWhenGetUserReposIsSuccessful() throws Exception { - doAnswer( - new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - presenter.onSuccessRequest(jsArrayMixed); - return null; - } - }) - .when(presenter) - .doRequest(nullable(Promise.class), nullable(Promise.class), nullable(Promise.class)); when(view.getAccountName()).thenReturn("AccountName"); presenter.onLoadRepoClicked(); - verify(gitHubClientService).getRepositoriesList(); - verify(gitHubClientService).getUserInfo(); - verify(gitHubClientService).getOrganizations(); + verify(gitHubClientService).getRepositoriesList(anyString()); + verify(gitHubClientService).getUserInfo(anyString()); + verify(gitHubClientService).getOrganizations(anyString()); verify(view).setLoaderVisibility(eq(true)); verify(view).setInputsEnableState(eq(false)); verify(view).setLoaderVisibility(eq(false)); verify(view).setInputsEnableState(eq(true)); - verify(view).setAccountNames(org.mockito.ArgumentMatchers.anyObject()); + verify(view).setAccountNames(org.mockito.ArgumentMatchers.any()); verify(view, times(2)).showGithubPanel(); - verify(view).setRepositories(org.mockito.ArgumentMatchers.>anyObject()); + verify(view).setRepositories(org.mockito.ArgumentMatchers.any()); verify(view).reset(); } @Test public void onLoadRepoClickedWhenGetUserReposIsFailed() throws Exception { - doAnswer( - new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - presenter.onFailRequest(promiseError); - return null; - } - }) - .when(presenter) - .doRequest(nullable(Promise.class), nullable(Promise.class), nullable(Promise.class)); - presenter.onLoadRepoClicked(); - verify(gitHubClientService).getRepositoriesList(); - verify(gitHubClientService).getUserInfo(); - verify(gitHubClientService).getOrganizations(); + verify(gitHubClientService).getRepositoriesList(anyString()); + verify(gitHubClientService).getUserInfo(anyString()); + verify(gitHubClientService).getOrganizations(anyString()); verify(view).setLoaderVisibility(eq(true)); verify(view).setInputsEnableState(eq(false)); verify(view).setLoaderVisibility(eq(false)); verify(view).setInputsEnableState(eq(true)); - verify(view, never()).setAccountNames((Set) anyObject()); + verify(view, never()).setAccountNames(any()); verify(view, never()).showGithubPanel(); - verify(view, never()) - .setRepositories(org.mockito.ArgumentMatchers.>anyObject()); + verify(view, never()).setRepositories(org.mockito.ArgumentMatchers.any()); } @Test public void onRepositorySelectedTest() { ProjectData projectData = new ProjectData( - "name", "description", "type", new ArrayList(), "repoUrl", "readOnlyUrl"); + "name", "description", "type", Collections.emptyList(), "repoUrl", "readOnlyUrl"); presenter.onRepositorySelected(projectData); @@ -497,23 +457,13 @@ public class GithubImporterPagePresenterTest { when(user.getId()).thenReturn(userId); final Throwable exception = mock(UnauthorizedException.class); - doAnswer( - new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - presenter.onFailRequest(promiseError); - return null; - } - }) - .when(presenter) - .doRequest(nullable(Promise.class), nullable(Promise.class), nullable(Promise.class)); doReturn(exception).when(promiseError).getCause(); presenter.onLoadRepoClicked(); - verify(gitHubClientService).getRepositoriesList(); - verify(gitHubClientService).getUserInfo(); - verify(gitHubClientService).getOrganizations(); + verify(gitHubClientService).getRepositoriesList(anyString()); + verify(gitHubClientService).getUserInfo(anyString()); + verify(gitHubClientService).getOrganizations(anyString()); verify(gitHubAuthenticator).authenticate(anyString(), asyncCallbackCaptor.capture()); AsyncCallback asyncCallback = asyncCallbackCaptor.getValue(); @@ -522,32 +472,13 @@ public class GithubImporterPagePresenterTest { verify(view, times(2)).setLoaderVisibility(eq(true)); verify(view, times(2)).setInputsEnableState(eq(false)); verify(view, times(2)).setInputsEnableState(eq(true)); - verify(view, never()).setAccountNames((Set) anyObject()); + verify(view, never()).setAccountNames(any()); verify(view, never()).showGithubPanel(); - verify(view, never()) - .setRepositories(org.mockito.ArgumentMatchers.>anyObject()); + verify(view, never()).setRepositories(org.mockito.ArgumentMatchers.any()); } @Test public void onLoadRepoClickedWhenAuthorizeIsSuccessful() throws Exception { - doAnswer( - new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - presenter.onFailRequest(promiseError); - return null; - } - }) - .doAnswer( - new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - presenter.onSuccessRequest(jsArrayMixed); - return null; - } - }) - .when(presenter) - .doRequest(nullable(Promise.class), nullable(Promise.class), nullable(Promise.class)); final Throwable exception = mock(UnauthorizedException.class); String userId = "userId"; CurrentUser user = mock(CurrentUser.class); @@ -558,9 +489,9 @@ public class GithubImporterPagePresenterTest { presenter.onLoadRepoClicked(); - verify(gitHubClientService).getRepositoriesList(); - verify(gitHubClientService).getUserInfo(); - verify(gitHubClientService).getOrganizations(); + verify(gitHubClientService).getRepositoriesList(anyString()); + verify(gitHubClientService).getUserInfo(anyString()); + verify(gitHubClientService).getOrganizations(anyString()); verify(gitHubAuthenticator).authenticate(anyString(), asyncCallbackCaptor.capture()); AsyncCallback asyncCallback = asyncCallbackCaptor.getValue(); diff --git a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml index d19598ccef..8854d821ea 100644 --- a/plugins/plugin-github/che-plugin-github-provider-github/pom.xml +++ b/plugins/plugin-github/che-plugin-github-provider-github/pom.xml @@ -37,10 +37,6 @@ javax.ws.rs javax.ws.rs-api - - org.eclipse.che.core - che-core-api-auth-shared - org.eclipse.che.core che-core-api-core diff --git a/plugins/plugin-github/che-plugin-github-provider-github/src/main/java/org/eclipse/che/ide/ext/git/server/github/GitHubOAuthCredentialProvider.java b/plugins/plugin-github/che-plugin-github-provider-github/src/main/java/org/eclipse/che/ide/ext/git/server/github/GitHubOAuthCredentialProvider.java index d44c7041ee..84ce1ea833 100644 --- a/plugins/plugin-github/che-plugin-github-provider-github/src/main/java/org/eclipse/che/ide/ext/git/server/github/GitHubOAuthCredentialProvider.java +++ b/plugins/plugin-github/che-plugin-github-provider-github/src/main/java/org/eclipse/che/ide/ext/git/server/github/GitHubOAuthCredentialProvider.java @@ -10,51 +10,29 @@ */ package org.eclipse.che.ide.ext.git.server.github; -import java.io.IOException; import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.core.UriBuilder; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.api.git.CredentialsProvider; -import org.eclipse.che.api.git.UserCredential; -import org.eclipse.che.api.git.exception.GitException; +import org.eclipse.che.api.git.GitBasicAuthenticationCredentialsProvider; import org.eclipse.che.api.git.shared.ProviderInfo; import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** @author Sergii Kabashniuk */ @Singleton -public class GitHubOAuthCredentialProvider implements CredentialsProvider { +public class GitHubOAuthCredentialProvider extends GitBasicAuthenticationCredentialsProvider { private static final Logger LOG = LoggerFactory.getLogger(GitHubOAuthCredentialProvider.class); private static String OAUTH_PROVIDER_NAME = "github"; - private final OAuthTokenProvider oAuthTokenProvider; private final String authorizationServicePath; @Inject - public GitHubOAuthCredentialProvider(OAuthTokenProvider oAuthTokenProvider) { - this.oAuthTokenProvider = oAuthTokenProvider; + public GitHubOAuthCredentialProvider() { this.authorizationServicePath = "/oauth/authenticate"; } - @Override - public UserCredential getUserCredential() throws GitException { - try { - OAuthToken token = - oAuthTokenProvider.getToken( - OAUTH_PROVIDER_NAME, EnvironmentContext.getCurrent().getSubject().getUserId()); - if (token != null) { - return new UserCredential(token.getToken(), token.getToken(), OAUTH_PROVIDER_NAME); - } - } catch (IOException e) { - LOG.warn(e.getLocalizedMessage()); - } - return null; - } - @Override public String getId() { return OAUTH_PROVIDER_NAME; @@ -72,7 +50,7 @@ public class GitHubOAuthCredentialProvider implements CredentialsProvider { UriBuilder.fromPath(authorizationServicePath) .queryParam("oauth_provider", OAUTH_PROVIDER_NAME) .queryParam("userId", EnvironmentContext.getCurrent().getSubject().getUserId()) - .queryParam("scope", "repo") + .queryParam("scope", "repo,write:public_key") .build() .toString()); } diff --git a/plugins/plugin-github/che-plugin-github-pullrequest/pom.xml b/plugins/plugin-github/che-plugin-github-pullrequest/pom.xml index 60deac2386..413fc0f2d0 100644 --- a/plugins/plugin-github/che-plugin-github-pullrequest/pom.xml +++ b/plugins/plugin-github/che-plugin-github-pullrequest/pom.xml @@ -45,6 +45,10 @@ javax.validation validation-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-model diff --git a/plugins/plugin-github/che-plugin-github-pullrequest/src/main/java/org/eclipse/che/plugin/pullrequest/client/GitHubHostingService.java b/plugins/plugin-github/che-plugin-github-pullrequest/src/main/java/org/eclipse/che/plugin/pullrequest/client/GitHubHostingService.java index 20907dc034..43c98d2282 100644 --- a/plugins/plugin-github/che-plugin-github-pullrequest/src/main/java/org/eclipse/che/plugin/pullrequest/client/GitHubHostingService.java +++ b/plugins/plugin-github/che-plugin-github-pullrequest/src/main/java/org/eclipse/che/plugin/pullrequest/client/GitHubHostingService.java @@ -28,8 +28,9 @@ import org.eclipse.che.api.promises.client.js.JsPromiseError; import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.app.CurrentUser; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.plugin.github.ide.GitHubClientService; +import org.eclipse.che.plugin.github.ide.GitHubServiceClient; import org.eclipse.che.plugin.github.shared.GitHubPullRequest; import org.eclipse.che.plugin.github.shared.GitHubPullRequestCreationInput; import org.eclipse.che.plugin.github.shared.GitHubPullRequestList; @@ -71,30 +72,34 @@ public class GitHubHostingService implements VcsHostingService { private final AppContext appContext; private final DtoFactory dtoFactory; - private final GitHubClientService gitHubClientService; + private final GitHubServiceClient gitHubClientService; private final HostingServiceTemplates templates; private final String baseUrl; private final SecurityTokenProvider securityTokenProvider; + private final OAuthServiceClient oAuthServiceClient; @Inject public GitHubHostingService( @NotNull final AppContext appContext, @NotNull final DtoFactory dtoFactory, - @NotNull final GitHubClientService gitHubClientService, + @NotNull final GitHubServiceClient gitHubClientService, @NotNull final GitHubTemplates templates, - SecurityTokenProvider securityTokenProvider) { + SecurityTokenProvider securityTokenProvider, + OAuthServiceClient oAuthServiceClient) { this.appContext = appContext; this.dtoFactory = dtoFactory; this.gitHubClientService = gitHubClientService; this.templates = templates; this.baseUrl = appContext.getMasterApiEndpoint(); this.securityTokenProvider = securityTokenProvider; + this.oAuthServiceClient = oAuthServiceClient; } @Override public Promise getUserInfo() { - return gitHubClientService - .getUserInfo() + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise(token -> gitHubClientService.getUserInfo(token.getToken())) .then( new Function() { @Override @@ -111,15 +116,11 @@ public class GitHubHostingService implements VcsHostingService { @Override public Promise getRepository(String owner, String repositoryName) { - return gitHubClientService - .getRepository(owner, repositoryName) - .then( - new Function() { - @Override - public Repository apply(GitHubRepository ghRepo) throws FunctionException { - return valueOf(ghRepo); - } - }); + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> gitHubClientService.getRepository(token.getToken(), owner, repositoryName)) + .then((Function) this::valueOf); } @NotNull @@ -159,8 +160,9 @@ public class GitHubHostingService implements VcsHostingService { @Override public Promise fork(final String owner, final String repository) { - return gitHubClientService - .fork(owner, repository) + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise(token -> gitHubClientService.fork(token.getToken(), owner, repository)) .thenPromise( new Function>() { @Override @@ -232,8 +234,12 @@ public class GitHubHostingService implements VcsHostingService { @Override public Promise getPullRequest( String owner, String repository, String username, final String branchName) { - return gitHubClientService - .getPullRequests(owner, repository, username + ':' + branchName) + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> + gitHubClientService.getPullRequests( + token.getToken(), owner, repository, username + ':' + branchName)) .thenPromise( new Function>() { @Override @@ -260,8 +266,10 @@ public class GitHubHostingService implements VcsHostingService { @NotNull final String repository, @NotNull final AsyncCallback> callback) { - gitHubClientService - .getPullRequests(owner, repository) + oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> gitHubClientService.getPullRequests(token.getToken(), owner, repository)) .then( result -> { final List pullRequests = new ArrayList<>(); @@ -284,8 +292,10 @@ public class GitHubHostingService implements VcsHostingService { */ private Promise> getPullRequests(String owner, String repository) { - return gitHubClientService - .getPullRequests(owner, repository) + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> gitHubClientService.getPullRequests(token.getToken(), owner, repository)) .then( new Function>() { @Override @@ -327,8 +337,11 @@ public class GitHubHostingService implements VcsHostingService { .withHead(brName) .withBase(baseBranchName) .withBody(body); - return gitHubClientService - .createPullRequest(owner, repository, input) + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> + gitHubClientService.createPullRequest(token.getToken(), owner, repository, input)) .then( new Function() { @Override @@ -395,8 +408,9 @@ public class GitHubHostingService implements VcsHostingService { @NotNull final String owner, @NotNull final String repository, @NotNull final AsyncCallback> callback) { - gitHubClientService - .getForks(owner, repository) + oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise(token -> gitHubClientService.getForks(token.getToken(), owner, repository)) .then( gitHubRepositoryList -> { final List repositories = new ArrayList<>(); @@ -413,8 +427,9 @@ public class GitHubHostingService implements VcsHostingService { } private Promise> getForks(final String owner, final String repository) { - return gitHubClientService - .getForks(owner, repository) + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise(token -> gitHubClientService.getForks(token.getToken(), owner, repository)) .then( new Function>() { @Override @@ -520,15 +535,17 @@ public class GitHubHostingService implements VcsHostingService { @Override public Promise updatePullRequest( String owner, String repository, PullRequest pullRequest) { - return gitHubClientService - .updatePullRequest(owner, repository, pullRequest.getNumber(), valueOf(pullRequest)) - .then( - new Function() { - @Override - public PullRequest apply(GitHubPullRequest arg) throws FunctionException { - return valueOf(arg); - } - }); + return oAuthServiceClient + .getToken(SERVICE_NAME.toLowerCase()) + .thenPromise( + token -> + gitHubClientService.updatePullRequest( + token.getToken(), + owner, + repository, + pullRequest.getNumber(), + valueOf(pullRequest))) + .then((Function) this::valueOf); } private GitHubPullRequest valueOf(PullRequest pullRequest) { diff --git a/plugins/plugin-github/che-plugin-github-server/pom.xml b/plugins/plugin-github/che-plugin-github-server/pom.xml index 86a4a770f7..9d87183c7d 100644 --- a/plugins/plugin-github/che-plugin-github-server/pom.xml +++ b/plugins/plugin-github/che-plugin-github-server/pom.xml @@ -29,6 +29,10 @@ com.google.code.gson gson + + com.google.guava + guava + com.google.inject guice @@ -45,10 +49,6 @@ javax.ws.rs javax.ws.rs-api - - org.eclipse.che.core - che-core-api-auth-shared - org.eclipse.che.core che-core-api-core diff --git a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubFactory.java b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubFactory.java index bf0f191f55..402ef1363f 100644 --- a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubFactory.java +++ b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubFactory.java @@ -10,13 +10,9 @@ */ package org.eclipse.che.plugin.github.server; -import com.google.inject.Inject; import java.io.IOException; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; import org.kohsuke.github.GitHub; /** @@ -27,41 +23,17 @@ import org.kohsuke.github.GitHub; */ public class GitHubFactory { - private final OAuthTokenProvider oauthTokenProvider; - - @Inject - private GitHubFactory(OAuthTokenProvider oauthTokenProvider) { - this.oauthTokenProvider = oauthTokenProvider; - } - /** - * Connect to GitHub API + * Connect to GitHub API using OAuth * + * @param oauthToken token for OAuth connection * @return connected GitHub API class */ - public GitHub connect() throws ServerException, UnauthorizedException { + public GitHub oauthConnect(String oauthToken) throws ServerException, UnauthorizedException { try { - return GitHub.connectUsingOAuth(getToken()); + return GitHub.connectUsingOAuth(oauthToken); } catch (IOException e) { throw new ServerException(e.getMessage()); } } - - private String getToken() throws ServerException, UnauthorizedException { - OAuthToken token; - try { - token = - oauthTokenProvider.getToken( - "github", EnvironmentContext.getCurrent().getSubject().getUserId()); - } catch (IOException e) { - throw new ServerException(e.getMessage()); - } - - String oauthToken = token != null ? token.getToken() : null; - if (oauthToken == null || oauthToken.isEmpty()) { - throw new UnauthorizedException("User doesn't have access token to github"); - } - - return oauthToken; - } } diff --git a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubKeyUploader.java b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubKeyUploader.java index 6b1ae1e870..1498911d12 100644 --- a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubKeyUploader.java +++ b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/GitHubKeyUploader.java @@ -10,7 +10,7 @@ */ package org.eclipse.che.plugin.github.server; -import com.google.inject.Inject; +import com.google.common.base.Strings; import com.google.inject.Singleton; import java.io.BufferedReader; import java.io.IOException; @@ -28,15 +28,12 @@ import java.util.regex.Pattern; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.git.GitUrlUtils; -import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.json.JsonHelper; import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.che.plugin.github.shared.GitHubKey; import org.eclipse.che.plugin.ssh.key.script.SshKeyUploader; -import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,31 +44,23 @@ public class GitHubKeyUploader implements SshKeyUploader { private static final Logger LOG = LoggerFactory.getLogger(GitHubKeyUploader.class); private static final Pattern GITHUB_URL_PATTERN = Pattern.compile(".*github\\.com.*"); - private OAuthTokenProvider tokenProvider; - - @Inject - public GitHubKeyUploader(OAuthTokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - @Override public boolean match(String url) { return GitUrlUtils.isSSH(url) && GITHUB_URL_PATTERN.matcher(url).matches(); } @Override - public void uploadKey(String publicKey) throws IOException, UnauthorizedException { - final OAuthToken token = - tokenProvider.getToken("github", EnvironmentContext.getCurrent().getSubject().getUserId()); + public void uploadKey(String publicKey, String oauthToken) + throws IOException, UnauthorizedException { - if (token == null || token.getToken() == null) { + if (Strings.isNullOrEmpty(oauthToken)) { LOG.debug("Token not found, user need to authorize to upload key."); throw new UnauthorizedException("To upload SSH key you need to authorize."); } StringBuilder answer = new StringBuilder(); final String url = - String.format("https://api.github.com/user/keys?access_token=%s", token.getToken()); + String.format("https://api.github.com/user/keys?access_token=%s", oauthToken); final List gitHubUserPublicKeys = getUserPublicKeys(url, answer); for (GitHubKey gitHubUserPublicKey : gitHubUserPublicKeys) { diff --git a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/inject/GitHubModule.java b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/inject/GitHubModule.java index efa3482b9e..c5910e80a9 100644 --- a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/inject/GitHubModule.java +++ b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/inject/GitHubModule.java @@ -15,7 +15,6 @@ import com.google.inject.multibindings.Multibinder; import org.eclipse.che.api.project.server.ProjectImporter; import org.eclipse.che.inject.DynaModule; import org.eclipse.che.plugin.github.server.GitHubDTOFactory; -import org.eclipse.che.plugin.github.server.GitHubFactory; import org.eclipse.che.plugin.github.server.GitHubKeyUploader; import org.eclipse.che.plugin.github.server.GitHubProjectImporter; import org.eclipse.che.plugin.github.server.rest.GitHubService; @@ -32,7 +31,6 @@ public class GitHubModule extends AbstractModule { /** {@inheritDoc} */ @Override protected void configure() { - bind(GitHubFactory.class); bind(GitHubDTOFactory.class); Multibinder projectImporterMultibinder = diff --git a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/rest/GitHubService.java b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/rest/GitHubService.java index d5885ed5e0..773dc661d7 100644 --- a/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/rest/GitHubService.java +++ b/plugins/plugin-github/che-plugin-github-server/src/main/java/org/eclipse/che/plugin/github/server/rest/GitHubService.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.util.List; import javax.inject.Inject; import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; @@ -59,25 +60,42 @@ import org.slf4j.LoggerFactory; */ @Path("/github") public class GitHubService { - @Inject private GitHubFactory gitHubFactory; - @Inject private GitHubDTOFactory gitHubDTOFactory; + private final GitHubDTOFactory gitHubDTOFactory; - @Inject private GitHubKeyUploader githubKeyUploader; + private final GitHubKeyUploader githubKeyUploader; - @Inject private SshServiceClient sshServiceClient; + private final SshServiceClient sshServiceClient; + + private final GitHubFactory gitHubFactory; + + private static final String AUTH_HEADER_NAME = "X-Oauth-Token"; private static final Logger LOG = LoggerFactory.getLogger(GitHubService.class); + @Inject + public GitHubService( + GitHubDTOFactory gitHubDTOFactory, + GitHubKeyUploader githubKeyUploader, + SshServiceClient sshServiceClient, + GitHubFactory gitHubFactory) { + this.gitHubDTOFactory = gitHubDTOFactory; + this.githubKeyUploader = githubKeyUploader; + this.sshServiceClient = sshServiceClient; + this.gitHubFactory = gitHubFactory; + } + @GET @Path("repositories/{user}/{repository}") @Produces(MediaType.APPLICATION_JSON) public GitHubRepository getUserRepository( - @PathParam("user") String user, @PathParam("repository") String repository) + @PathParam("user") String user, + @PathParam("repository") String repository, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createRepository( - gitHubFactory.connect().getUser(user).getRepository(repository)); + gitHubFactory.oauthConnect(oauthToken).getUser(user).getRepository(repository)); } catch (IOException e) { LOG.error("Get user info error", e); throw new ServerException(e.getMessage()); @@ -87,11 +105,12 @@ public class GitHubService { @GET @Path("list/user") @Produces(MediaType.APPLICATION_JSON) - public GitHubRepositoryList listRepositoriesByUser(@QueryParam("username") String userName) + public GitHubRepositoryList listRepositoriesByUser( + @QueryParam("username") String userName, @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createRepositoriesList( - gitHubFactory.connect().getUser(userName).listRepositories()); + gitHubFactory.oauthConnect(oauthToken).getUser(userName).listRepositories()); } catch (IOException e) { LOG.error("Get list repositories by user fail", e); throw new ServerException(e.getMessage()); @@ -102,10 +121,12 @@ public class GitHubService { @Path("list/org") @Produces(MediaType.APPLICATION_JSON) public GitHubRepositoryList listRepositoriesByOrganization( - @QueryParam("organization") String organization) throws ApiException { + @QueryParam("organization") String organization, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) + throws ApiException { try { return gitHubDTOFactory.createRepositoriesList( - gitHubFactory.connect().getOrganization(organization).listRepositories()); + gitHubFactory.oauthConnect(oauthToken).getOrganization(organization).listRepositories()); } catch (IOException e) { LOG.error("Get list repositories by organization fail", e); throw new ServerException(e.getMessage()); @@ -115,9 +136,10 @@ public class GitHubService { @GET @Path("list/account") @Produces(MediaType.APPLICATION_JSON) - public GitHubRepositoryList listRepositoriesByAccount(@QueryParam("account") String account) + public GitHubRepositoryList listRepositoriesByAccount( + @QueryParam("account") String account, @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { - GitHub gitHub = gitHubFactory.connect(); + GitHub gitHub = gitHubFactory.oauthConnect(oauthToken); try { // First, try to retrieve organization repositories: return gitHubDTOFactory.createRepositoriesList( @@ -137,10 +159,12 @@ public class GitHubService { @GET @Path("list") @Produces(MediaType.APPLICATION_JSON) - public List listRepositories() throws ApiException { + public List listRepositories(@HeaderParam(AUTH_HEADER_NAME) String oauthToken) + throws ApiException { try { return gitHubDTOFactory - .createRepositoriesList(gitHubFactory.connect().getMyself().listRepositories()) + .createRepositoriesList( + gitHubFactory.oauthConnect(oauthToken).getMyself().listRepositories()) .getRepositories(); } catch (IOException e) { LOG.error("Get list repositories fail", e); @@ -152,13 +176,15 @@ public class GitHubService { @Path("forks/{user}/{repository}") @Produces(MediaType.APPLICATION_JSON) public GitHubRepositoryList forks( - @PathParam("user") String user, @PathParam("repository") String repository) + @PathParam("user") String user, + @PathParam("repository") String repository, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { GitHubRepositoryList gitHubRepositoryList; try { gitHubRepositoryList = gitHubDTOFactory.createRepositoriesList(); - - for (GHRepository ghRepository : gitHubFactory.connect().getMyself().listRepositories()) { + for (GHRepository ghRepository : + gitHubFactory.oauthConnect(oauthToken).getMyself().listRepositories()) { if (ghRepository.isFork() && ghRepository.getName().equals(repository)) { gitHubRepositoryList = gitHubDTOFactory.createRepositoriesList(ghRepository); break; @@ -175,11 +201,13 @@ public class GitHubService { @Path("createfork/{user}/{repository}") @Produces(MediaType.APPLICATION_JSON) public GitHubRepository fork( - @PathParam("user") String user, @PathParam("repository") String repository) + @PathParam("user") String user, + @PathParam("repository") String repository, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createRepository( - gitHubFactory.connect().getUser(user).getRepository(repository).fork()); + gitHubFactory.oauthConnect(oauthToken).getUser(user).getRepository(repository).fork()); } catch (IOException e) { LOG.error("Fork fail", e); throw new ServerException(e.getMessage()); @@ -193,11 +221,12 @@ public class GitHubService { @PathParam("user") String user, @PathParam("repository") String repository, @PathParam("issue") String issue, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken, GitHubIssueCommentInput input) throws ApiException { try { gitHubFactory - .connect() + .oauthConnect(oauthToken) .getUser(user) .getRepository(repository) .getIssue(Integer.getInteger(issue)) @@ -214,12 +243,13 @@ public class GitHubService { public GitHubPullRequestList listPullRequestsByRepository( @PathParam("user") String user, @PathParam("repository") String repository, - @QueryParam("head") String head) + @QueryParam("head") String head, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createPullRequestsList( gitHubFactory - .connect() + .oauthConnect(oauthToken) .getUser(user) .getRepository(repository) .queryPullRequests() @@ -238,12 +268,13 @@ public class GitHubService { public GitHubPullRequestList getPullRequestsById( @PathParam("user") String user, @PathParam("repository") String repository, - @PathParam("pullRequestId") String pullRequestId) + @PathParam("pullRequestId") String pullRequestId, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createPullRequestsList( gitHubFactory - .connect() + .oauthConnect(oauthToken) .getUser(user) .getRepository(repository) .getPullRequest(Integer.valueOf(pullRequestId))); @@ -259,12 +290,13 @@ public class GitHubService { public GitHubPullRequest createPullRequest( @PathParam("user") String user, @PathParam("repository") String repository, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken, GitHubPullRequestCreationInput input) throws ApiException { try { GHPullRequest pullRequest = gitHubFactory - .connect() + .oauthConnect(oauthToken) .getUser(user) .getRepository(repository) .createPullRequest( @@ -285,12 +317,13 @@ public class GitHubService { @PathParam("user") String user, @PathParam("repository") String repository, @PathParam("pullRequestId") String pullRequestId, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken, GitHubPullRequest pullRequest) throws ServerException, UnauthorizedException { try { final GHPullRequest ghPullRequest = gitHubFactory - .connect() + .oauthConnect(oauthToken) .getUser(user) .getRepository(repository) .getPullRequest(Integer.valueOf(pullRequestId)); @@ -311,10 +344,12 @@ public class GitHubService { @GET @Path("orgs") @Produces(MediaType.APPLICATION_JSON) - public List listOrganizations() throws ApiException { + public List listOrganizations(@HeaderParam(AUTH_HEADER_NAME) String oauthToken) + throws ApiException { try { return gitHubDTOFactory - .createCollaborators(gitHubFactory.connect().getMyself().getAllOrganizations()) + .createCollaborators( + gitHubFactory.oauthConnect(oauthToken).getMyself().getAllOrganizations()) .getCollaborators(); } catch (IOException e) { LOG.error("Getting list of available organizations fail", e); @@ -325,9 +360,10 @@ public class GitHubService { @GET @Path("user") @Produces(MediaType.APPLICATION_JSON) - public GitHubUser getUserInfo() throws ApiException { + public GitHubUser getUserInfo(@HeaderParam(AUTH_HEADER_NAME) String oauthToken) + throws ApiException { try { - return gitHubDTOFactory.createUser(gitHubFactory.connect().getMyself()); + return gitHubDTOFactory.createUser(GitHub.connectUsingOAuth(oauthToken).getMyself()); } catch (IOException e) { LOG.error("Getting user info fail", e); throw new ServerException(e.getMessage()); @@ -338,11 +374,17 @@ public class GitHubService { @Path("collaborators/{user}/{repository}") @Produces(MediaType.APPLICATION_JSON) public Collaborators collaborators( - @PathParam("user") String user, @PathParam("repository") String repository) + @PathParam("user") String user, + @PathParam("repository") String repository, + @HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { try { return gitHubDTOFactory.createCollaborators( - gitHubFactory.connect().getUser(user).getRepository(repository).getCollaborators()); + gitHubFactory + .oauthConnect(oauthToken) + .getUser(user) + .getRepository(repository) + .getCollaborators()); } catch (IOException e) { LOG.error("Get collaborators fail", e); throw new ServerException(e.getMessage()); @@ -351,7 +393,7 @@ public class GitHubService { @POST @Path("ssh/generate") - public void updateSSHKey() throws ApiException { + public void updateSSHKey(@HeaderParam(AUTH_HEADER_NAME) String oauthToken) throws ApiException { final String host = "github.com"; SshPair sshPair = null; try { @@ -374,7 +416,7 @@ public class GitHubService { // update public key try { - githubKeyUploader.uploadKey(sshPair.getPublicKey()); + githubKeyUploader.uploadKey(sshPair.getPublicKey(), oauthToken); } catch (IOException e) { LOG.error("Upload github ssh key fail", e); throw new GitException(e.getMessage(), e); diff --git a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/pom.xml b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/pom.xml index d28b7e0989..0f5e845c8e 100644 --- a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/pom.xml +++ b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/pom.xml @@ -45,6 +45,10 @@ javax.validation validation-api + + org.eclipse.che.core + che-core-api-auth-shared + org.eclipse.che.core che-core-api-core diff --git a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java index 3c0d6ca6aa..0311fa7b37 100644 --- a/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java +++ b/plugins/plugin-pullrequest-parent/che-plugin-pullrequest-ide/src/main/java/org/eclipse/che/plugin/pullrequest/client/vcs/GitVcsService.java @@ -11,12 +11,17 @@ package org.eclipse.che.plugin.pullrequest.client.vcs; import static java.util.Collections.emptyList; +import static org.eclipse.che.api.core.ErrorCodes.UNAUTHORIZED_GIT_OPERATION; +import static org.eclipse.che.api.git.shared.ProviderInfo.PROVIDER_NAME; +import static org.eclipse.che.ide.util.ExceptionUtils.getAttributes; +import static org.eclipse.che.ide.util.ExceptionUtils.getErrorCode; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.eclipse.che.api.core.model.workspace.config.ProjectConfig; @@ -31,10 +36,13 @@ import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.js.JsPromiseError; import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.auth.Credentials; +import org.eclipse.che.ide.api.auth.OAuthServiceClient; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.git.client.GitServiceClient; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; +import org.eclipse.che.ide.util.StringUtils; /** Git backed implementation for {@link VcsService}. */ @Singleton @@ -44,16 +52,19 @@ public class GitVcsService implements VcsService { private final GitServiceClient service; private final DtoFactory dtoFactory; private final AppContext appContext; + private final OAuthServiceClient oAuthServiceClient; @Inject public GitVcsService( final DtoFactory dtoFactory, final DtoUnmarshallerFactory dtoUnmarshallerFactory, final GitServiceClient service, - final AppContext appContext) { + final AppContext appContext, + final OAuthServiceClient oAuthServiceClient) { this.dtoFactory = dtoFactory; this.service = service; this.appContext = appContext; + this.oAuthServiceClient = oAuthServiceClient; } @Override @@ -204,7 +215,38 @@ public class GitVcsService implements VcsService { appContext.getRootProject().getLocation(), Collections.singletonList(localBranchName), remote, - true) + true, + null) + .catchErrorPromise( + error -> { + if (getErrorCode(error.getCause()) != UNAUTHORIZED_GIT_OPERATION) { + return null; + } + Map attributes = getAttributes(error.getCause()); + String providerName = attributes.get(PROVIDER_NAME); + if (!StringUtils.isNullOrEmpty(providerName)) { + return pushBranchAuthenticated(remote, localBranchName, providerName); + } else if (BRANCH_UP_TO_DATE_ERROR_MESSAGE.equalsIgnoreCase(error.getMessage())) { + return Promises.reject( + JsPromiseError.create(new BranchUpToDateException(localBranchName))); + } else { + return Promises.reject(error); + } + }); + } + + public Promise pushBranchAuthenticated( + final String remote, final String localBranchName, final String providerName) { + return oAuthServiceClient + .getToken(providerName) + .thenPromise( + token -> + service.push( + appContext.getRootProject().getLocation(), + Collections.singletonList(localBranchName), + remote, + true, + new Credentials(token.getToken(), token.getToken()))) .catchErrorPromise( error -> { if (BRANCH_UP_TO_DATE_ERROR_MESSAGE.equalsIgnoreCase(error.getMessage())) { diff --git a/wsagent/che-core-api-oauth/pom.xml b/wsagent/che-core-api-oauth/pom.xml index 266ffd611c..9a7f73e3a7 100644 --- a/wsagent/che-core-api-oauth/pom.xml +++ b/wsagent/che-core-api-oauth/pom.xml @@ -42,10 +42,6 @@ org.eclipse.che.core che-core-api-core - - org.eclipse.che.core - che-core-api-dto - org.slf4j slf4j-api diff --git a/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/OAuthAgentModule.java b/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/OAuthAgentModule.java index 7fcdb90ebe..dbd1eeeba2 100644 --- a/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/OAuthAgentModule.java +++ b/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/OAuthAgentModule.java @@ -13,7 +13,6 @@ package org.eclipse.che.security.oauth; import com.google.inject.AbstractModule; import org.eclipse.che.security.oauth.oauth1.RemoteOAuthAuthorizationHeaderProvider; import org.eclipse.che.security.oauth.shared.OAuthAuthorizationHeaderProvider; -import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; /** * Represent single guice module that bind classes to get out tokens from workspace agent. @@ -23,7 +22,6 @@ import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; public class OAuthAgentModule extends AbstractModule { @Override protected void configure() { - bind(OAuthTokenProvider.class).to(RemoteOAuthTokenProvider.class); bind(OAuthAuthorizationHeaderProvider.class).to(RemoteOAuthAuthorizationHeaderProvider.class); } } diff --git a/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProvider.java b/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProvider.java deleted file mode 100644 index 97e454b57f..0000000000 --- a/wsagent/che-core-api-oauth/src/main/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProvider.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.security.oauth; - -import java.io.IOException; -import javax.inject.Inject; -import javax.inject.Named; -import javax.ws.rs.core.UriBuilder; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.api.core.BadRequestException; -import org.eclipse.che.api.core.ConflictException; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.UnauthorizedException; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.api.core.rest.shared.dto.Link; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.security.oauth.shared.OAuthTokenProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Allow get token from OAuth service over http. - * - * @author Max Shaposhnik - * @author Sergii Kabashniuk - */ -public class RemoteOAuthTokenProvider implements OAuthTokenProvider { - private static final Logger LOG = LoggerFactory.getLogger(RemoteOAuthTokenProvider.class); - - private final String apiEndpoint; - - private final HttpJsonRequestFactory httpJsonRequestFactory; - - @Inject - public RemoteOAuthTokenProvider( - @Named("che.api") String apiEndpoint, HttpJsonRequestFactory httpJsonRequestFactory) { - this.apiEndpoint = apiEndpoint; - this.httpJsonRequestFactory = httpJsonRequestFactory; - } - - /** {@inheritDoc} */ - @Override - public OAuthToken getToken(String oauthProviderName, String userId) throws IOException { - if (userId.isEmpty()) { - return null; - } - try { - UriBuilder ub = - UriBuilder.fromUri(apiEndpoint) - .path("/oauth/token") - .queryParam("oauth_provider", oauthProviderName); - Link getTokenLink = - DtoFactory.newDto(Link.class).withHref(ub.build().toString()).withMethod("GET"); - return httpJsonRequestFactory.fromLink(getTokenLink).request().asDto(OAuthToken.class); - } catch (NotFoundException ne) { - LOG.warn("Token not found for user {}", userId); - return null; - } catch (ServerException - | UnauthorizedException - | ForbiddenException - | ConflictException - | BadRequestException e) { - LOG.warn("Exception on token retrieval, message : {}", e.getLocalizedMessage()); - return null; - } - } -} diff --git a/wsagent/che-core-api-oauth/src/test/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProviderTest.java b/wsagent/che-core-api-oauth/src/test/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProviderTest.java deleted file mode 100644 index fd4aebf0a3..0000000000 --- a/wsagent/che-core-api-oauth/src/test/java/org/eclipse/che/security/oauth/RemoteOAuthTokenProviderTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.security.oauth; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; - -import java.io.IOException; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.rest.HttpJsonRequest; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.api.core.rest.HttpJsonResponse; -import org.eclipse.che.api.core.rest.shared.dto.Link; -import org.eclipse.che.commons.test.mockito.answer.SelfReturningAnswer; -import org.eclipse.che.dto.server.DtoFactory; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -@Listeners(value = {MockitoTestNGListener.class}) -public class RemoteOAuthTokenProviderTest { - - private HttpJsonRequest httpJsonRequest; - - private RemoteOAuthTokenProvider tokenProvider; - - @Mock private HttpJsonRequestFactory httpJsonRequestFactory; - @Mock private HttpJsonResponse httpJsonResponse; - - @BeforeMethod - public void setUp() throws Exception { - httpJsonRequest = mock(HttpJsonRequest.class, new SelfReturningAnswer()); - when(httpJsonRequestFactory.fromLink(any())).thenReturn(httpJsonRequest); - tokenProvider = new RemoteOAuthTokenProvider("http://dev.box.com/api", httpJsonRequestFactory); - } - - @Test - public void shouldReturnToken() throws Exception { - // given - OAuthToken expected = DtoFactory.newDto(OAuthToken.class).withScope("scope").withToken("token"); - when(httpJsonResponse.asDto(any(Class.class))).thenReturn(expected); - when(httpJsonRequest.request()).thenReturn(httpJsonResponse); - // when - OAuthToken actual = tokenProvider.getToken("google", "id"); - // then - assertEquals(actual, expected); - } - - @Test - public void shouldConstructCorrectUrl() throws Exception { - // given - OAuthToken expected = DtoFactory.newDto(OAuthToken.class).withScope("scope").withToken("token"); - when(httpJsonResponse.asDto(any(Class.class))).thenReturn(expected); - when(httpJsonRequest.request()).thenReturn(httpJsonResponse); - // when - tokenProvider.getToken("google", "id"); - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Link.class); - verify(httpJsonRequestFactory).fromLink(argumentCaptor.capture()); - Link link = argumentCaptor.getValue(); - assertEquals(link.getMethod(), "GET"); - assertEquals(link.getHref(), "http://dev.box.com/api/oauth/token?oauth_provider=google"); - assertEquals(link.getParameters().size(), 0); - } - - @Test - public void shouldReturnNollForNotExistedProvider() throws Exception { - // given - when(httpJsonRequest.request()).thenReturn(httpJsonResponse); - // when - // then - Assert.assertNull(tokenProvider.getToken("smoogle", "id")); - } - - @Test - public void shouldReturnNullOnNotFoundException() throws Exception { - // given - when(httpJsonRequest.request()).thenThrow(NotFoundException.class); - // when - // then - Assert.assertNull(tokenProvider.getToken("google", "id")); - } - - @Test - public void shouldReturnNullOnIfUserIsEmpty() throws Exception { - // given - // when - // then - Assert.assertNull(tokenProvider.getToken("google", "")); - } - - @Test(expectedExceptions = IOException.class) - public void shouldThrowIoExceptionOnIoException() throws Exception { - // given - when(httpJsonRequest.request()).thenThrow(IOException.class); - // when - // then - Assert.assertNull(tokenProvider.getToken("google", "id")); - } -} diff --git a/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyProviderImpl.java b/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyProviderImpl.java index 2a6e1ac586..3108a0edba 100644 --- a/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyProviderImpl.java +++ b/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyProviderImpl.java @@ -11,13 +11,10 @@ package org.eclipse.che.plugin.ssh.key.script; import com.google.inject.Inject; -import java.io.IOException; -import java.util.Optional; import java.util.Set; import org.eclipse.che.api.core.ErrorCodes; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.core.rest.shared.dto.ExtendedError; import org.eclipse.che.api.ssh.shared.model.SshPair; import org.eclipse.che.dto.server.DtoFactory; @@ -72,29 +69,6 @@ public class SshKeyProviderImpl implements SshKeyProvider { .withMessage("Unable get private ssh key") .withErrorCode(ErrorCodes.UNABLE_GET_PRIVATE_SSH_KEY)); } - - final String publicKey = pair.getPublicKey(); - if (publicKey != null) { - final Optional optionalKeyUploader = - sshKeyUploaders.stream().filter(keyUploader -> keyUploader.match(url)).findFirst(); - if (optionalKeyUploader.isPresent()) { - final SshKeyUploader uploader = optionalKeyUploader.get(); - try { - uploader.uploadKey(publicKey); - } catch (IOException e) { - throw new ServerException(e.getMessage(), e); - } catch (UnauthorizedException e) { - // action might fail without uploaded public SSH key. - LOG.warn( - String.format( - "Unable upload public SSH key with %s", uploader.getClass().getSimpleName()), - e); - } - } else { - // action might fail without uploaded public SSH key. - LOG.warn(String.format("Not found ssh key uploader for %s", host)); - } - } return privateKey.getBytes(); } } diff --git a/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyUploader.java b/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyUploader.java index 88e0b484ce..c4f4ba4b7c 100644 --- a/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyUploader.java +++ b/wsagent/che-core-ssh-key-server/src/main/java/org/eclipse/che/plugin/ssh/key/script/SshKeyUploader.java @@ -26,7 +26,7 @@ public interface SshKeyUploader { * @throws IOException if an i/o error occurs * @throws UnauthorizedException if user is not authorized to access SSH key storage */ - void uploadKey(String publicKey) throws IOException, UnauthorizedException; + void uploadKey(String publicKey, String oauthToken) throws IOException, UnauthorizedException; /** * Check if specified url matched to use current upload provider. diff --git a/wsagent/wsagent-local/src/main/java/org/eclipse/che/EnvironmentInitializationFilter.java b/wsagent/wsagent-local/src/main/java/org/eclipse/che/EnvironmentInitializationFilter.java new file mode 100644 index 0000000000..ab6f89f7f9 --- /dev/null +++ b/wsagent/wsagent-local/src/main/java/org/eclipse/che/EnvironmentInitializationFilter.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che; + +import java.io.IOException; +import javax.inject.Singleton; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.commons.subject.SubjectImpl; + +/** + * Sets dummy subject into {@link EnvironmentContext} + * + * @author Max Shaposhnik (mshaposh@redhat.com) + */ +@Singleton +public class EnvironmentInitializationFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException {} + + @Override + public final void doFilter( + ServletRequest request, ServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + Subject subject = new SubjectImpl("che", "che", "dummy_token", false); + final EnvironmentContext environmentContext = EnvironmentContext.getCurrent(); + try { + environmentContext.setSubject(subject); + filterChain.doFilter(request, response); + } finally { + EnvironmentContext.reset(); + } + } + + public void destroy() {} +} diff --git a/wsagent/wsagent-local/src/test/java/org/eclipse/che/EnvironmentInitializationFilterTest.java b/wsagent/wsagent-local/src/test/java/org/eclipse/che/EnvironmentInitializationFilterTest.java new file mode 100644 index 0000000000..f0f45659c0 --- /dev/null +++ b/wsagent/wsagent-local/src/test/java/org/eclipse/che/EnvironmentInitializationFilterTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNotEquals; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.SubjectImpl; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** @author Max Shaposhnik (mshaposh@redhat.com) */ +@Listeners(value = {MockitoTestNGListener.class}) +public class EnvironmentInitializationFilterTest { + + @Mock private FilterChain chain; + + @Mock private HttpServletRequest request; + + @Mock private HttpServletResponse response; + + @InjectMocks private EnvironmentInitializationFilter filter; + + @Test + public void shouldSkipRequestToProject() throws Exception { + // given + when(request.getMethod()).thenReturn("GET"); + when(request.getRequestURI()).thenReturn("/ws/ws-id"); + + EnvironmentContext context = spy(EnvironmentContext.getCurrent()); + EnvironmentContext.setCurrent(context); + + // when + filter.doFilter(request, response, chain); + + // then + verify(chain).doFilter(eq(request), eq(response)); + verify(context).setSubject(eq(new SubjectImpl("che", "che", "dummy_token", false))); + // after reset + assertNotEquals(EnvironmentContext.getCurrent(), context); + } +}