/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.github.client.authenticator;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.ssh.gwt.client.SshServiceClient;
import org.eclipse.che.api.ssh.shared.dto.SshPairDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.ext.github.client.GitHubLocalizationConstant;
import org.eclipse.che.ide.ext.git.ssh.client.GitSshKeyUploaderRegistry;
import org.eclipse.che.ide.ext.git.ssh.client.SshKeyUploader;
import org.eclipse.che.ide.ext.git.ssh.client.manage.SshKeyManagerPresenter;
import org.eclipse.che.ide.rest.RestContext;
import org.eclipse.che.ide.ui.dialogs.DialogFactory;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.security.oauth.JsOAuthWindow;
import org.eclipse.che.security.oauth.OAuthCallback;
import org.eclipse.che.security.oauth.OAuthStatus;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author Roman Nikitenko
*/
public class GitHubAuthenticatorImpl implements GitHubAuthenticator, OAuthCallback, GitHubAuthenticatorViewImpl.ActionDelegate {
public static final String GITHUB_HOST = "github.com";
AsyncCallback<OAuthStatus> callback;
private final GitSshKeyUploaderRegistry registry;
private final SshServiceClient sshServiceClient;
private final DialogFactory dialogFactory;
private final GitHubAuthenticatorView view;
private final NotificationManager notificationManager;
private final GitHubLocalizationConstant locale;
private final String baseUrl;
private final AppContext appContext;
@Inject
public GitHubAuthenticatorImpl(GitSshKeyUploaderRegistry registry,
SshServiceClient sshServiceClient,
GitHubAuthenticatorView view,
DialogFactory dialogFactory,
GitHubLocalizationConstant locale,
@RestContext String baseUrl,
NotificationManager notificationManager,
AppContext appContext) {
this.registry = registry;
this.sshServiceClient = sshServiceClient;
this.view = view;
this.view.setDelegate(this);
this.locale = locale;
this.baseUrl = baseUrl;
this.dialogFactory = dialogFactory;
this.notificationManager = notificationManager;
this.appContext = appContext;
}
@Override
public void authorize(@NotNull final AsyncCallback<OAuthStatus> callback) {
this.callback = callback;
view.showDialog();
}
@Override
public void onCancelled() {
callback.onFailure(new Exception("Authorization request rejected by user."));
}
@Override
public void onAccepted() {
showAuthWindow();
}
@Override
public void onAuthenticated(OAuthStatus authStatus) {
if (view.isGenerateKeysSelected()) {
generateSshKeys(authStatus);
return;
}
callback.onSuccess(authStatus);
}
private void showAuthWindow() {
JsOAuthWindow authWindow = new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this);
authWindow.loginWithOAuth();
}
private String getAuthUrl() {
String userId = appContext.getCurrentUser().getProfile().getId();
return baseUrl
+ "/oauth/authenticate?oauth_provider=github"
+ "&scope=user,repo,write:public_key&userId=" + userId
+ "&redirect_after_login="
+ Window.Location.getProtocol() + "//"
+ Window.Location.getHost() + "/ws/"
+ appContext.getWorkspace().getName();
}
private void generateSshKeys(final OAuthStatus authStatus) {
final SshKeyUploader githubKeyUploader = registry.getUploader(GITHUB_HOST);
if (githubKeyUploader != null) {
String userId = appContext.getCurrentUser().getProfile().getId();
githubKeyUploader.uploadKey(userId, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
callback.onSuccess(authStatus);
notificationManager.notify(locale.authMessageKeyUploadSuccess(), appContext.getCurrentProject().getRootProject());
}
@Override
public void onFailure(Throwable exception) {
dialogFactory.createMessageDialog(locale.authorizationDialogTitle(), locale.authMessageUnableCreateSshKey(), null)
.show();
callback.onFailure(new Exception(locale.authMessageUnableCreateSshKey()));
getFailedKey();
}
});
} else {
dialogFactory.createMessageDialog(locale.authorizationDialogTitle(), locale.authMessageUnableCreateSshKey(), null).show();
callback.onFailure(new Exception(locale.authMessageUnableCreateSshKey()));
}
}
/** Need to remove failed uploaded pair from local storage if they can't be uploaded to github */
private void getFailedKey() {
sshServiceClient.getPairs(SshKeyManagerPresenter.GIT_SSH_SERVICE)
.then(new Operation<List<SshPairDto>>() {
@Override
public void apply(List<SshPairDto> result) throws OperationException {
for (SshPairDto key : result) {
if (key.getName().equals(GITHUB_HOST)) {
removeFailedKey(key);
return;
}
}
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
Log.error(GitHubAuthenticator.class, arg.getCause());
}
});
}
/**
* Remove failed pair.
*
* @param pair
* failed pair
*/
private void removeFailedKey(@NotNull final SshPairDto pair) {
sshServiceClient.deletePair(pair.getService(), pair.getName())
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
Log.error(GitHubAuthenticator.class, arg.getCause());
}
});
}
}