Merge "Support CredentialsProvider for SSH connections"
This commit is contained in:
commit
573666403d
|
@ -211,6 +211,60 @@ public void setValueNoCopy(char[] newValue) {
|
|||
}
|
||||
}
|
||||
|
||||
/** An item whose value is a boolean choice, presented as Yes/No. */
|
||||
public static class YesNoType extends CredentialItem {
|
||||
private boolean value;
|
||||
|
||||
/**
|
||||
* Initialize a prompt for a single boolean answer.
|
||||
*
|
||||
* @param promptText
|
||||
* prompt to display to the user alongside of the input
|
||||
* field. Should be sufficient text to indicate what to
|
||||
* supply for this item.
|
||||
*/
|
||||
public YesNoType(String promptText) {
|
||||
super(promptText, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
value = false;
|
||||
}
|
||||
|
||||
/** @return the current value */
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new value.
|
||||
*
|
||||
* @param newValue
|
||||
*/
|
||||
public void setValue(boolean newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/** An advice message presented to the user, with no response required. */
|
||||
public static class InformationalMessage extends CredentialItem {
|
||||
/**
|
||||
* Initialize an informational message.
|
||||
*
|
||||
* @param messageText
|
||||
* message to display to the user.
|
||||
*/
|
||||
public InformationalMessage(String messageText) {
|
||||
super(messageText, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// Nothing to clear.
|
||||
}
|
||||
}
|
||||
|
||||
/** Prompt for a username, which is not masked on input. */
|
||||
public static class Username extends StringType {
|
||||
/** Initialize a new username item, with a default username prompt. */
|
||||
|
|
|
@ -80,6 +80,17 @@ public static void setDefault(CredentialsProvider p) {
|
|||
defaultProvider = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provider is interactive with the end-user.
|
||||
*
|
||||
* An interactive provider may try to open a dialog box, or prompt for input
|
||||
* on the terminal, and will wait for a user response. A non-interactive
|
||||
* provider will either populate CredentialItems, or fail.
|
||||
*
|
||||
* @return {@code true} if the provider is interactive with the end-user.
|
||||
*/
|
||||
public abstract boolean isInteractive();
|
||||
|
||||
/**
|
||||
* Check if the provider can supply the necessary {@link CredentialItem}s.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (C) 2010, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.transport;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.UIKeyboardInteractive;
|
||||
import com.jcraft.jsch.UserInfo;
|
||||
|
||||
/** A JSch {@link UserInfo} adapter for a {@link CredentialsProvider}. */
|
||||
public class CredentialsProviderUserInfo implements UserInfo,
|
||||
UIKeyboardInteractive {
|
||||
private final URIish uri;
|
||||
|
||||
private final CredentialsProvider provider;
|
||||
|
||||
private String password;
|
||||
|
||||
private String passphrase;
|
||||
|
||||
/**
|
||||
* Wrap a CredentialsProvider to make it suitable for use with JSch.
|
||||
*
|
||||
* @param session
|
||||
* the JSch session this UserInfo will support authentication on.
|
||||
* @param credentialsProvider
|
||||
* the provider that will perform the authentication.
|
||||
*/
|
||||
public CredentialsProviderUserInfo(Session session,
|
||||
CredentialsProvider credentialsProvider) {
|
||||
this.uri = createURI(session);
|
||||
this.provider = credentialsProvider;
|
||||
}
|
||||
|
||||
private static URIish createURI(Session session) {
|
||||
URIish uri = new URIish();
|
||||
uri = uri.setScheme("ssh");
|
||||
uri = uri.setUser(session.getUserName());
|
||||
uri = uri.setHost(session.getHost());
|
||||
uri = uri.setPort(session.getPort());
|
||||
return uri;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getPassphrase() {
|
||||
return passphrase;
|
||||
}
|
||||
|
||||
public boolean promptPassphrase(String msg) {
|
||||
CredentialItem.StringType v = newPrompt(msg);
|
||||
if (provider.get(uri, v)) {
|
||||
passphrase = v.getValue();
|
||||
return true;
|
||||
} else {
|
||||
passphrase = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean promptPassword(String msg) {
|
||||
CredentialItem.StringType v = newPrompt(msg);
|
||||
if (provider.get(uri, v)) {
|
||||
password = v.getValue();
|
||||
return true;
|
||||
} else {
|
||||
password = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private CredentialItem.StringType newPrompt(String msg) {
|
||||
return new CredentialItem.StringType(msg, true);
|
||||
}
|
||||
|
||||
public boolean promptYesNo(String msg) {
|
||||
CredentialItem.YesNoType v = new CredentialItem.YesNoType(msg);
|
||||
return provider.get(uri, v) && v.getValue();
|
||||
}
|
||||
|
||||
public void showMessage(String msg) {
|
||||
provider.get(uri, new CredentialItem.InformationalMessage(msg));
|
||||
}
|
||||
|
||||
public String[] promptKeyboardInteractive(String destination, String name,
|
||||
String instruction, String[] prompt, boolean[] echo) {
|
||||
CredentialItem.StringType[] v = new CredentialItem.StringType[prompt.length];
|
||||
for (int i = 0; i < prompt.length; i++)
|
||||
v[i] = new CredentialItem.StringType(prompt[i], !echo[i]);
|
||||
|
||||
List<CredentialItem> items = new ArrayList<CredentialItem>();
|
||||
if (instruction != null && instruction.length() > 0)
|
||||
items.add(new CredentialItem.InformationalMessage(instruction));
|
||||
items.addAll(Arrays.asList(v));
|
||||
|
||||
if (!provider.get(uri, items))
|
||||
return null; // cancel
|
||||
|
||||
String[] result = new String[v.length];
|
||||
for (int i = 0; i < v.length; i++)
|
||||
result[i] = v[i].getValue();
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -83,7 +83,8 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory {
|
|||
|
||||
@Override
|
||||
public synchronized Session getSession(String user, String pass,
|
||||
String host, int port, FS fs) throws JSchException {
|
||||
String host, int port, CredentialsProvider credentialsProvider,
|
||||
FS fs) throws JSchException {
|
||||
if (config == null)
|
||||
config = OpenSshConfig.get(fs);
|
||||
|
||||
|
@ -105,6 +106,11 @@ public synchronized Session getSession(String user, String pass,
|
|||
final String pauth = hc.getPreferredAuthentications();
|
||||
if (pauth != null)
|
||||
session.setConfig("PreferredAuthentications", pauth);
|
||||
if (credentialsProvider != null
|
||||
&& (!hc.isBatchMode() || !credentialsProvider.isInteractive())) {
|
||||
session.setUserInfo(new CredentialsProviderUserInfo(session,
|
||||
credentialsProvider));
|
||||
}
|
||||
configure(hc, session);
|
||||
return session;
|
||||
}
|
||||
|
|
|
@ -111,6 +111,8 @@ public static void setInstance(final SshSessionFactory newFactory) {
|
|||
* @param port
|
||||
* port number the server is listening for connections on. May be <=
|
||||
* 0 to indicate the IANA registered port of 22 should be used.
|
||||
* @param credentialsProvider
|
||||
* provider to support authentication, may be null.
|
||||
* @param fs
|
||||
* the file system abstraction which will be necessary to
|
||||
* perform certain file system operations.
|
||||
|
@ -119,14 +121,16 @@ public static void setInstance(final SshSessionFactory newFactory) {
|
|||
* the session could not be created.
|
||||
*/
|
||||
public abstract Session getSession(String user, String pass, String host,
|
||||
int port, FS fs) throws JSchException;
|
||||
int port, CredentialsProvider credentialsProvider, FS fs)
|
||||
throws JSchException;
|
||||
|
||||
/**
|
||||
* Close (or recycle) a session to a host.
|
||||
*
|
||||
* @param session
|
||||
* a session previously obtained from this factory's
|
||||
* {@link #getSession(String,String, String, int, FS)} method.s
|
||||
* {@link #getSession(String,String, String, int, CredentialsProvider, FS)}
|
||||
* method.
|
||||
*/
|
||||
public void releaseSession(final Session session) {
|
||||
if (session.isConnected())
|
||||
|
|
|
@ -128,7 +128,8 @@ protected void initSession() throws TransportException {
|
|||
final String host = uri.getHost();
|
||||
final int port = uri.getPort();
|
||||
try {
|
||||
sock = sch.getSession(user, pass, host, port, local.getFS());
|
||||
sock = sch.getSession(user, pass, host, port,
|
||||
getCredentialsProvider(), local.getFS());
|
||||
if (!sock.isConnected())
|
||||
sock.connect(tms);
|
||||
} catch (JSchException je) {
|
||||
|
|
|
@ -76,6 +76,11 @@ public UsernamePasswordCredentialsProvider(String username, char[] password) {
|
|||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInteractive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(CredentialItem... items) {
|
||||
for (CredentialItem i : items) {
|
||||
|
|
Loading…
Reference in New Issue