Added support of Idenvity brokering mechanism of Keycloak for Multi-user Che

6.19.x
Max Shaposhnik 2017-12-21 17:50:03 +02:00 committed by GitHub
parent a6efd2d986
commit 8ff1be36f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 1135 additions and 783 deletions

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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<String, String> 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,"

View File

@ -588,6 +588,7 @@
"enabled" : true,
"clientAuthenticatorType" : "client-secret",
"secret" : "b59b1baf-df65-455d-b185-fda173e29d1b",
"defaultRoles": [ "read-token" ],
"redirectUris" : [ ],
"webOrigins" : [ ],
"notBefore" : 0,

View File

@ -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.

View File

@ -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<OAuthToken> callback) {
asyncRequestFactory
.createGetRequest(restContext + "/token?oauth_provider=" + oauthProvider)
.send(callback);
}
public Promise<OAuthToken> getToken(String oauthProvider) {
return asyncRequestFactory
.createGetRequest(restContext + "/token?oauth_provider=" + oauthProvider)
.send(unmarshallerFactory.newUnmarshaller(OAuthToken.class));
}
}

View File

@ -60,6 +60,10 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>

View File

@ -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;

View File

@ -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<Project>() {
@Override
public void apply(Project arg) throws OperationException {
if (callback != null) {
callback.onCompleted();
}
project -> {
if (callback != null) {
callback.onCompleted();
}
})
.catchError(
new Operation<PromiseError>() {
@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<Project, Promise<Project>>() {
@Override
public Promise<Project> apply(Project project) throws FunctionException {
subscriber.onSuccess();
return projectResolver.resolve(project);
}
project -> {
subscriber.onSuccess();
return projectResolver.resolve(project);
})
.catchErrorPromise(
new Function<PromiseError, Promise<Project>>() {
@ -175,27 +172,18 @@ public class ProjectImporter extends AbstractImporter {
credentialsDialog
.askCredentials()
.then(
new Operation<Credentials>() {
@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<Project>() {
@Override
public void apply(Project project) throws OperationException {
callback.onSuccess(project);
}
})
.catchError(
new Operation<PromiseError>() {
@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<Project>() {
@Override
public void apply(Project project) throws OperationException {
callback.onSuccess(project);
}
})
.catchError(
new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
callback.onFailure(error.getCause());
}
});
oAuthServiceClient.getToken(
providerName,
new AsyncRequestCallback<OAuthToken>(
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"));

View File

@ -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;
/**

View File

@ -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<Project> importPromise;
@Mock private Project importedProject;
@Mock private OAuthServiceClient oAuthServiceClient;
@Mock private DtoUnmarshallerFactory unmarshallerFactory;
@Captor private ArgumentCaptor<Function<Project, Promise<Project>>> 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

View File

@ -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.

View File

@ -54,10 +54,18 @@
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>

View File

@ -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)
*/

View File

@ -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);
}

View File

@ -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<String, String> 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<String, String> splitQuery(String query) {
Map<String, String> 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;
}
}

View File

@ -45,6 +45,10 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>

View File

@ -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 <Y> Promise<Y> performOperationWithTokenRequestIfNeeded(
final RemoteGitOperation<Y> operation) {
return operation
.perform(null)
.catchErrorPromise(
new Function<PromiseError, Promise<Y>>() {
@Override
public Promise<Y> apply(PromiseError error) throws FunctionException {
if (getErrorCode(error.getCause()) == ErrorCodes.UNAUTHORIZED_GIT_OPERATION) {
Map<String, String> 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<Y> {
Promise<Y> perform(Credentials credentials);
}
}

View File

@ -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 {
* </ul>
*
* @param removeDeletedRefs if <code>true</code> then delete removed refs from local repository
* @param credentials credentials to perform vcs authorization
*/
Promise<Void> fetch(Path project, String remote, List<String> refspec, boolean removeDeletedRefs);
Promise<Void> fetch(
Path project,
String remote,
List<String> 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<PullResponse> pull(Path project, String refSpec, String remote, boolean rebase);
Promise<PullResponse> 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 <code>true</code> disables the check. This can cause the remote
* repository to lose commits
* @param credentials credentials to perform vcs authorization
*/
Promise<PushResponse> push(Path project, List<String> refSpec, String remote, boolean force);
Promise<PushResponse> push(
Path project, List<String> refSpec, String remote, boolean force, Credentials credentials);
/**
* Clones one remote repository to local one (over WebSocket).

View File

@ -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<PushResponse> push(
Path project, List<String> refSpec, String remote, boolean force) {
Path project, List<String> 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<Void> fetch(
Path project, String remote, List<String> refspec, boolean removeDeletedRefs) {
Path project,
String remote,
List<String> 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<PullResponse> pull(Path project, String refSpec, String remote, boolean rebase) {
public Promise<PullResponse> 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)

View File

@ -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<PushResponse>() {
@Override
public Promise<PushResponse> 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);
}
}

View File

@ -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<Void>() {
@Override
public Promise<Void> 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);

View File

@ -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<PullResponse>() {
@Override
public Promise<PullResponse> 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;
}
}

View File

@ -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<PushResponse>() {
@Override
public Promise<PushResponse> 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);

View File

@ -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);

View File

@ -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);

View File

@ -41,6 +41,10 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>

View File

@ -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<GitHubRepository> getRepository(String user, String repository);
Promise<GitHubRepository> getRepository(String oauthToken, String user, String repository);
/** Get list of available public and private repositories of the authorized user. */
Promise<List<GitHubRepository>> getRepositoriesList();
/**
* Get list of available public and private repositories of the authorized user.
*
* @param oauthToken Github OAuth authorization token
*/
Promise<List<GitHubRepository>> 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<GitHubRepositoryList> getForks(String user, String repository);
Promise<GitHubRepositoryList> 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<GitHubRepository> fork(String user, String repository);
Promise<GitHubRepository> 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<GitHubPullRequestList> getPullRequests(@NotNull String owner, @NotNull String repository);
Promise<GitHubPullRequestList> 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<GitHubPullRequestList> getPullRequests(String owner, String repository, String head);
Promise<GitHubPullRequestList> 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<GitHubPullRequest> 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<GitHubRepositoryList> callback);
@NotNull String oauthToken,
String userName,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<GitHubRepositoryList> callback);
@NotNull String oauthToken,
String organization,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<GitHubRepositoryList> callback);
@NotNull String oauthToken,
String account,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<Collaborators> callback);
/** Get the list of the organizations, where authorized user is a member. */
Promise<List<GitHubUser>> getOrganizations();
/**
* Get the list of the organizations, where authorized user is a member.
*
* @param oauthToken Github OAuth authorization token
*/
Promise<List<GitHubUser>> getOrganizations(@NotNull String oauthToken);
/** Get authorized user information. */
Promise<GitHubUser> getUserInfo();
/**
* Get authorized user information.
*
* @param oauthToken Github OAuth authorization token
*/
Promise<GitHubUser> 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<Void> callback);
void updatePublicKey(@NotNull String oauthToken, @NotNull AsyncRequestCallback<Void> 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<GitHubPullRequest> updatePullRequest(
String user, String repository, String pullRequestId, GitHubPullRequest pullRequest);
@NotNull String oauthToken,
String user,
String repository,
String pullRequestId,
GitHubPullRequest pullRequest);
}

View File

@ -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<GitHubRepository> getRepository(String user, String repository) {
public Promise<GitHubRepository> 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<List<GitHubRepository>> getRepositoriesList() {
public Promise<List<GitHubRepository>> 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<GitHubRepositoryList> getForks(String user, String repository) {
public Promise<GitHubRepositoryList> 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<GitHubRepository> fork(String user, String repository) {
public Promise<GitHubRepository> 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<GitHubIssueComment> 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<GitHubPullRequestList> 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<GitHubPullRequestList> 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<GitHubPullRequest> 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<GitHubPullRequest> 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<GitHubRepositoryList> callback) {
@NotNull String oauthToken,
String userName,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<Collaborators> 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<List<GitHubUser>> getOrganizations() {
public Promise<List<GitHubUser>> 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<GitHubUser> getUserInfo() {
public Promise<GitHubUser> 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<GitHubRepositoryList> callback) {
@NotNull String oauthToken,
String organization,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<GitHubRepositoryList> callback) {
@NotNull String oauthToken,
String account,
@NotNull AsyncRequestCallback<GitHubRepositoryList> 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<Void> callback) {
public void updatePublicKey(String oauthToken, @NotNull AsyncRequestCallback<Void> 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<GitHubPullRequest> 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));
}

View File

@ -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<Void> 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<Void>() {
@Override
protected void onSuccess(Void o) {
callback.onSuccess(o);
}
oAuthServiceClient
.getToken("github")
.then(
result -> {
gitHubService.updatePublicKey(
result.getToken(),
new AsyncRequestCallback<Void>() {
@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();
}

View File

@ -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();
}

View File

@ -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<MutableProje
private static final RegExp WHITE_SPACE = RegExp.compile("^\\s");
private final DtoFactory dtoFactory;
private GitHubClientService gitHubClientService;
private GitHubServiceClient gitHubClientService;
private Map<String, List<GitHubRepository>> 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<MutableProje
public GithubImporterPagePresenter(
GithubImporterPageView view,
OAuth2AuthenticatorRegistry gitHubAuthenticatorRegistry,
GitHubClientService gitHubClientService,
GitHubServiceClient gitHubClientService,
DtoFactory dtoFactory,
AppContext appContext,
GitHubLocalizationConstant locale) {
GitHubLocalizationConstant locale,
OAuthServiceClient oAuthServiceClient,
NotificationManager notificationManager) {
this.view = view;
this.baseUrl = appContext.getMasterApiEndpoint();
this.appContext = appContext;
this.gitHubAuthenticator = gitHubAuthenticatorRegistry.getAuthenticator("github");
this.gitHubClientService = gitHubClientService;
this.dtoFactory = dtoFactory;
this.oAuthServiceClient = oAuthServiceClient;
this.notificationManager = notificationManager;
this.view.setDelegate(this);
this.locale = locale;
}
@ -260,32 +267,16 @@ public class GithubImporterPagePresenter extends AbstractWizardPage<MutableProje
private void getUserRepositoriesAndOrganizations() {
showProcessing(true);
Promise<GitHubUser> userInfo = gitHubClientService.getUserInfo();
Promise<List<GitHubUser>> organizations = gitHubClientService.getOrganizations();
Promise<List<GitHubRepository>> allRepositories = gitHubClientService.getRepositoriesList();
doRequest(userInfo, organizations, allRepositories);
}
protected void doRequest(
Promise<GitHubUser> userInfo,
Promise<List<GitHubUser>> organizations,
Promise<List<GitHubRepository>> allRepositories) {
Promises.all(userInfo, organizations, allRepositories)
.then(
new Operation<JsArrayMixed>() {
@Override
public void apply(JsArrayMixed arg) throws OperationException {
onSuccessRequest(arg);
}
})
.catchError(
new Operation<PromiseError>() {
@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<MutableProje
showProcessing(false);
if (arg.getCause() instanceof UnauthorizedException) {
authorize();
} else {
notificationManager.notify(locale.authorizationFailed(), FAIL, FLOAT_MODE);
}
}
@ -365,7 +358,7 @@ public class GithubImporterPagePresenter extends AbstractWizardPage<MutableProje
Map<String, String> login2OrgName = getLogin2OrgName(gitHubOrganizations);
for (String orgName : login2OrgName.values()) {
repositories.put(orgName, new ArrayList<GitHubRepository>());
repositories.put(orgName, new ArrayList<>());
}
for (GitHubRepository gitHubRepository : gitHubRepositories) {
@ -410,14 +403,7 @@ public class GithubImporterPagePresenter extends AbstractWizardPage<MutableProje
projectsData.add(projectData);
}
Collections.sort(
projectsData,
new Comparator<ProjectData>() {
@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();

View File

@ -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);

View File

@ -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<AsyncCallback<OAuthStatus>> asyncCallbackCaptor;
@Captor
private ArgumentCaptor<AsyncRequestCallback<Map<String, List<GitHubRepository>>>>
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<String, String> parameters;
@Mock private Promise<GitHubUser> gitHubUserPromise;
@Mock private Promise<List<GitHubUser>> gitHubOrgsPromise;
@Mock private Promise<List<GitHubRepository>> 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.<Set>anyObject());
verify(view).setAccountNames(org.mockito.ArgumentMatchers.<Set>any());
verify(view, times(2)).showGithubPanel();
verify(view).setRepositories(org.mockito.ArgumentMatchers.<List<ProjectData>>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<String>) anyObject());
verify(view, never()).setAccountNames(any());
verify(view, never()).showGithubPanel();
verify(view, never())
.setRepositories(org.mockito.ArgumentMatchers.<List<ProjectData>>anyObject());
verify(view, never()).setRepositories(org.mockito.ArgumentMatchers.any());
}
@Test
public void onRepositorySelectedTest() {
ProjectData projectData =
new ProjectData(
"name", "description", "type", new ArrayList<String>(), "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<OAuthStatus> 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<String>) anyObject());
verify(view, never()).setAccountNames(any());
verify(view, never()).showGithubPanel();
verify(view, never())
.setRepositories(org.mockito.ArgumentMatchers.<List<ProjectData>>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<OAuthStatus> asyncCallback = asyncCallbackCaptor.getValue();

View File

@ -37,10 +37,6 @@
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>

View File

@ -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());
}

View File

@ -45,6 +45,10 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>

View File

@ -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<HostUser> getUserInfo() {
return gitHubClientService
.getUserInfo()
return oAuthServiceClient
.getToken(SERVICE_NAME.toLowerCase())
.thenPromise(token -> gitHubClientService.getUserInfo(token.getToken()))
.then(
new Function<GitHubUser, HostUser>() {
@Override
@ -111,15 +116,11 @@ public class GitHubHostingService implements VcsHostingService {
@Override
public Promise<Repository> getRepository(String owner, String repositoryName) {
return gitHubClientService
.getRepository(owner, repositoryName)
.then(
new Function<GitHubRepository, Repository>() {
@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<GitHubRepository, Repository>) this::valueOf);
}
@NotNull
@ -159,8 +160,9 @@ public class GitHubHostingService implements VcsHostingService {
@Override
public Promise<Repository> 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<GitHubRepository, Promise<Repository>>() {
@Override
@ -232,8 +234,12 @@ public class GitHubHostingService implements VcsHostingService {
@Override
public Promise<PullRequest> 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<GitHubPullRequestList, Promise<PullRequest>>() {
@Override
@ -260,8 +266,10 @@ public class GitHubHostingService implements VcsHostingService {
@NotNull final String repository,
@NotNull final AsyncCallback<List<PullRequest>> callback) {
gitHubClientService
.getPullRequests(owner, repository)
oAuthServiceClient
.getToken(SERVICE_NAME.toLowerCase())
.thenPromise(
token -> gitHubClientService.getPullRequests(token.getToken(), owner, repository))
.then(
result -> {
final List<PullRequest> pullRequests = new ArrayList<>();
@ -284,8 +292,10 @@ public class GitHubHostingService implements VcsHostingService {
*/
private Promise<List<PullRequest>> 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<GitHubPullRequestList, List<PullRequest>>() {
@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<GitHubPullRequest, PullRequest>() {
@Override
@ -395,8 +408,9 @@ public class GitHubHostingService implements VcsHostingService {
@NotNull final String owner,
@NotNull final String repository,
@NotNull final AsyncCallback<List<Repository>> callback) {
gitHubClientService
.getForks(owner, repository)
oAuthServiceClient
.getToken(SERVICE_NAME.toLowerCase())
.thenPromise(token -> gitHubClientService.getForks(token.getToken(), owner, repository))
.then(
gitHubRepositoryList -> {
final List<Repository> repositories = new ArrayList<>();
@ -413,8 +427,9 @@ public class GitHubHostingService implements VcsHostingService {
}
private Promise<List<Repository>> 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<GitHubRepositoryList, List<Repository>>() {
@Override
@ -520,15 +535,17 @@ public class GitHubHostingService implements VcsHostingService {
@Override
public Promise<PullRequest> updatePullRequest(
String owner, String repository, PullRequest pullRequest) {
return gitHubClientService
.updatePullRequest(owner, repository, pullRequest.getNumber(), valueOf(pullRequest))
.then(
new Function<GitHubPullRequest, PullRequest>() {
@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<GitHubPullRequest, PullRequest>) this::valueOf);
}
private GitHubPullRequest valueOf(PullRequest pullRequest) {

View File

@ -29,6 +29,10 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
@ -45,10 +49,6 @@
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>

View File

@ -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;
}
}

View File

@ -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<GitHubKey> gitHubUserPublicKeys = getUserPublicKeys(url, answer);
for (GitHubKey gitHubUserPublicKey : gitHubUserPublicKeys) {

View File

@ -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<ProjectImporter> projectImporterMultibinder =

View File

@ -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<GitHubRepository> listRepositories() throws ApiException {
public List<GitHubRepository> 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<GitHubUser> listOrganizations() throws ApiException {
public List<GitHubUser> 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);

View File

@ -45,6 +45,10 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>

View File

@ -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<String, String> 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<PushResponse> 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())) {

View File

@ -42,10 +42,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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<Link> 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"));
}
}

View File

@ -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<SshKeyUploader> 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();
}
}

View File

@ -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.

View File

@ -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() {}
}

View File

@ -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);
}
}