/*******************************************************************************
* Copyright (c) 2012-2017 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.plugin.github.ide.authenticator;
import com.google.common.collect.Lists;
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.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper;
import org.eclipse.che.api.ssh.shared.dto.SshPairDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.oauth.OAuth2Authenticator;
import org.eclipse.che.ide.api.oauth.OAuth2AuthenticatorUrlProvider;
import org.eclipse.che.ide.api.ssh.SshServiceClient;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.plugin.github.ide.GitHubLocalizationConstant;
import org.eclipse.che.plugin.ssh.key.client.SshKeyUploader;
import org.eclipse.che.plugin.ssh.key.client.SshKeyUploaderRegistry;
import org.eclipse.che.plugin.ssh.key.client.manage.SshKeyManagerPresenter;
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;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
/**
* @author Roman Nikitenko
*/
public class GitHubAuthenticatorImpl implements OAuth2Authenticator, OAuthCallback, GitHubAuthenticatorViewImpl.ActionDelegate {
public static final String GITHUB_HOST = "github.com";
public static final String GITHUB = "github";
AsyncCallback<OAuthStatus> callback;
private final SshKeyUploaderRegistry 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;
private String authenticationUrl;
@Inject
public GitHubAuthenticatorImpl(SshKeyUploaderRegistry registry,
SshServiceClient sshServiceClient,
GitHubAuthenticatorView view,
DialogFactory dialogFactory,
GitHubLocalizationConstant locale,
NotificationManager notificationManager,
AppContext appContext) {
this.registry = registry;
this.sshServiceClient = sshServiceClient;
this.view = view;
this.view.setDelegate(this);
this.locale = locale;
this.baseUrl = appContext.getMasterEndpoint();
this.dialogFactory = dialogFactory;
this.notificationManager = notificationManager;
this.appContext = appContext;
}
@Override
public void authenticate(String authenticationUrl, @NotNull final AsyncCallback<OAuthStatus> callback) {
this.authenticationUrl = authenticationUrl;
this.callback = callback;
view.showDialog();
}
public Promise<OAuthStatus> authenticate(String authenticationUrl) {
this.authenticationUrl = authenticationUrl;
return AsyncPromiseHelper.createFromAsyncRequest(new AsyncPromiseHelper.RequestCall<OAuthStatus>() {
@Override
public void makeCall(AsyncCallback<OAuthStatus> callback) {
GitHubAuthenticatorImpl.this.callback = callback;
view.showDialog();
}
});
}
@Override
public String getProviderName() {
return GITHUB;
}
@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;
if (authenticationUrl == null) {
authWindow = new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this);
} else {
authWindow = new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this);
}
authWindow.loginWithOAuth();
}
private String getAuthUrl() {
return OAuth2AuthenticatorUrlProvider.get(baseUrl, "github", appContext.getCurrentUser().getProfile().getUserId(), Lists
.asList("user", new String[]{"repo", "write:public_key"}));
}
private void generateSshKeys(final OAuthStatus authStatus) {
final SshKeyUploader githubKeyUploader = registry.getUploader(GITHUB_HOST);
if (githubKeyUploader != null) {
String userId = appContext.getCurrentUser().getProfile().getUserId();
githubKeyUploader.uploadKey(userId, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
callback.onSuccess(authStatus);
notificationManager.notify(locale.authMessageKeyUploadSuccess(), SUCCESS, FLOAT_MODE);
}
@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.VCS_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(OAuth2Authenticator.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(OAuth2Authenticator.class, arg.getCause());
}
});
}
}