org.jetbrains.idea.svn.dialogs.SvnInteractiveAuthenticationProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.jetbrains.idea.svn.dialogs.SvnInteractiveAuthenticationProvider.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jetbrains.idea.svn.dialogs;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.security.cert.X509Certificate;

import javax.swing.SwingUtilities;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnAuthenticationManager;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnConfiguration;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.auth.ProviderType;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
import org.tmatesoft.svn.core.auth.SVNSSHAuthentication;
import org.tmatesoft.svn.core.auth.SVNSSLAuthentication;
import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication;
import org.tmatesoft.svn.core.internal.wc.ISVNHostOptions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.util.WaitForProgressToShow;

public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationProvider {
    private static final Logger LOG = Logger
            .getInstance("#org.jetbrains.idea.svn.dialogs.SvnInteractiveAuthenticationProvider");
    private final Project myProject;
    private static final ThreadLocal<MyCallState> myCallState = new ThreadLocal<MyCallState>();
    private final SvnAuthenticationManager myManager;

    public SvnInteractiveAuthenticationProvider(final SvnVcs vcs, SvnAuthenticationManager manager) {
        myManager = manager;
        myProject = vcs.getProject();
    }

    public static void clearCallState() {
        myCallState.set(null);
    }

    public static boolean wasCalled() {
        return myCallState.get() != null && myCallState.get().isWasCalled();
    }

    public static boolean wasCancelled() {
        return myCallState.get() != null && myCallState.get().isWasCancelled();
    }

    public SVNAuthentication requestClientAuthentication(final String kind, final SVNURL url, final String realm,
            final SVNErrorMessage errorMessage, final SVNAuthentication previousAuth,
            final boolean authMayBeStored) {
        final MyCallState callState = new MyCallState(true, false);
        myCallState.set(callState);
        // once we came here, we don't know _correct_ auth todo +-
        final SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
        configuration.clearCredentials(kind, realm);

        final SVNAuthentication[] result = new SVNAuthentication[1];
        Runnable command = null;

        final boolean authCredsOn = authMayBeStored
                && myManager.getHostOptionsProvider().getHostOptions(url).isAuthStorageEnabled();

        final String userName = previousAuth != null && previousAuth.getUserName() != null
                ? previousAuth.getUserName()
                : myManager.getDefaultUsername(kind, url);
        if (ISVNAuthenticationManager.PASSWORD.equals(kind)) {// || ISVNAuthenticationManager.USERNAME.equals(kind)) {
            command = new Runnable() {
                public void run() {
                    SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myProject);
                    dialog.setup(realm, userName, authCredsOn);
                    setTitle(dialog, errorMessage);
                    dialog.show();
                    if (dialog.isOK()) {
                        result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(),
                                dialog.isSaveAllowed(), url, false);
                    }
                }
            };
        } else if (ISVNAuthenticationManager.USERNAME.equals(kind)) {
            if (ApplicationManager.getApplication().isUnitTestMode()) {
                return new SVNUserNameAuthentication(userName, false);
            }
            command = new Runnable() {
                public void run() {
                    UserNameCredentialsDialog dialog = new UserNameCredentialsDialog(myProject);
                    dialog.setup(realm, userName, authCredsOn);
                    setTitle(dialog, errorMessage);
                    dialog.show();
                    if (dialog.isOK()) {
                        result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url,
                                false);
                    }
                }
            };
        } else if (ISVNAuthenticationManager.SSH.equals(kind)) {
            // In current implementation, pageant connector available = operating system is Windows.
            // So "ssh agent" option will be always available on Windows, even if pageant is not running.
            //final Connector agentConnector = createSshAgentConnector();
            final boolean isAgentAvailable = false;//agentConnector != null && agentConnector.isAvailable();

            command = new Runnable() {
                public void run() {
                    SSHCredentialsDialog dialog = new SSHCredentialsDialog(myProject, realm, userName, authCredsOn,
                            url.getPort(), isAgentAvailable);
                    setTitle(dialog, errorMessage);
                    dialog.show();
                    if (dialog.isOK()) {
                        int port = dialog.getPortNumber();
                        if (dialog.isSshAgentSelected()) {
                            /*if (agentConnector != null) {
                              result[0] =
                                new SVNSSHAuthentication(dialog.getUserName(), new TrileadAgentProxy(agentConnector), port, url, false);
                            }*/
                        } else if (dialog.getKeyFile() != null && dialog.getKeyFile().trim().length() > 0) {
                            String passphrase = dialog.getPassphrase();
                            if (passphrase != null && passphrase.length() == 0) {
                                passphrase = null;
                            }
                            result[0] = new SVNSSHAuthentication(dialog.getUserName(),
                                    new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), url,
                                    false);
                        } else {
                            result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port,
                                    dialog.isSaveAllowed(), url, false);
                        }
                    }
                }
            };
        } else if (ISVNAuthenticationManager.SSL.equals(kind)) {
            command = new Runnable() {
                public void run() {
                    final ISVNHostOptions options = myManager.getHostOptionsProvider().getHostOptions(url);
                    final String file = options.getSSLClientCertFile();
                    final SSLCredentialsDialog dialog = new SSLCredentialsDialog(myProject, realm, authCredsOn);
                    if (!StringUtil.isEmptyOrSpaces(file)) {
                        dialog.setFile(file);
                    }
                    setTitle(dialog, errorMessage);
                    dialog.show();
                    if (dialog.isOK()) {
                        result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()),
                                String.valueOf(dialog.getCertificatePassword()), dialog.getSaveAuth(), url, false);
                    }
                }
            };
        }

        if (command != null) {
            WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command);
            log("3 authentication result: " + result[0]);
        }

        final boolean wasCanceled = result[0] == null;
        callState.setWasCancelled(wasCanceled);
        myManager.requested(ProviderType.interactive, url, realm, kind, wasCanceled);
        return result[0];
    }

    /*@Nullable
    private static Connector createSshAgentConnector() {
      Connector result = null;
        
      try {
        result = ConnectorFactory.getDefault().createConnector();
      }
      catch (AgentProxyException e) {
        LOG.info("Could not create ssh agent connector", e);
      }
        
      return result;
    }  */

    private static void setTitle(@NotNull DialogWrapper dialog, @Nullable SVNErrorMessage errorMessage) {
        dialog.setTitle(errorMessage == null ? SvnBundle.message("dialog.title.authentication.required")
                : SvnBundle.message("dialog.title.authentication.required.was.failed"));
    }

    public int acceptServerAuthentication(final SVNURL url, String realm, final Object certificate,
            final boolean resultMayBeStored) {
        final int[] result = new int[1];
        Runnable command;
        if (certificate instanceof X509Certificate) {
            command = new Runnable() {
                public void run() {
                    ServerSSLDialog dialog = new ServerSSLDialog(myProject, (X509Certificate) certificate,
                            resultMayBeStored);
                    dialog.show();
                    result[0] = dialog.getResult();
                }
            };
        } else if (certificate instanceof byte[]) {
            final String sshKeyAlgorithm = myManager.getSSHKeyAlgorithm();
            command = new Runnable() {
                @Override
                public void run() {
                    final ServerSSHDialog serverSSHDialog = new ServerSSHDialog(myProject, resultMayBeStored,
                            url.toDecodedString(), sshKeyAlgorithm, (byte[]) certificate);
                    serverSSHDialog.show();
                    result[0] = serverSSHDialog.getResult();
                }
            };
        } else {
            VcsBalloonProblemNotifier.showOverChangesView(myProject,
                    "Subversion: unknown certificate type from " + url.toDecodedString(), MessageType.ERROR);
            return REJECTED;
        }
        final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
        if (pi != null) {
            WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, pi.getModalityState());
        } else {
            try {
                SwingUtilities.invokeAndWait(command);
            } catch (InterruptedException e) {
                //
            } catch (InvocationTargetException e) {
                //
            }
        }
        return result[0];
    }

    private void log(final String s) {
        LOG.debug(s);
    }

    public static class MyCallState {
        private final boolean myWasCalled;
        private boolean myWasCancelled;

        public MyCallState(boolean wasCalled, boolean wasCancelled) {
            myWasCalled = wasCalled;
            myWasCancelled = wasCancelled;
        }

        public boolean isWasCalled() {
            return myWasCalled;
        }

        public boolean isWasCancelled() {
            return myWasCancelled;
        }

        public void setWasCancelled(boolean wasCancelled) {
            myWasCancelled = wasCancelled;
        }
    }
}