Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1117,19 +1117,6 @@ jobs:
- name: platform/openide.util.ui
run: ant $OPTS -f platform/openide.util.ui test

# isolation required by netbinox tests
- name: isolate platform build
run: |
cp -r platform/ _platform/ && cp -r harness/ _harness/ && cp nbbuild/build/nbantext.jar .
cp -r nbbuild/netbeans/platform/ _nb_platform/ && cp -r nbbuild/netbeans/harness/ _nb_harness/
ant $OPTS -quiet clean && rm -Rf platform/ && rm -Rf harness/
mkdir nbbuild/build && mkdir nbbuild/netbeans
mv _platform/ platform/ && mv _harness/ harness/ && mv nbantext.jar nbbuild/build/
mv _nb_platform/ nbbuild/netbeans/platform/ && mv _nb_harness/ nbbuild/netbeans/harness/
- name: platform/netbinox
run: ant $OPTS -f platform/netbinox test -Dtest.config=stableBTD

- name: Create Test Summary
uses: test-summary/action@37b508cfee6d4d080eedd00b5bb240a6a784a6a5 # v2.6
if: failure()
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions ide/git/nbproject/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@
<compile-dependency/>
<run-dependency/>
</dependency>
<dependency>
<code-name-base>org.eclipse.jgit.gpg.bc</code-name-base>
<run-dependency/>
</dependency>
<dependency>
<code-name-base>org.eclipse.jgit.lfs</code-name-base>
<run-dependency/>
</dependency>
<dependency>
<code-name-base>org.eclipse.jgit.ssh.apache</code-name-base>
<run-dependency/>
</dependency>
<dependency>
<code-name-base>org.eclipse.jgit.ssh.apache.agent</code-name-base>
<run-dependency/>
</dependency>
<dependency>
<code-name-base>org.netbeans.api.annotations.common</code-name-base>
<build-prerequisite/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ public char[] getPassword (String uri, String prompt) {
pwd = password.clone();
Arrays.fill(password, (char) 0);
credentialsReady = false;
} else if (passphrase != null) {
// the jgit apache mina client uses password instead of passphrase
// to unlock the identity file, an additional guard could be to
// check for prompt "Passphrase", but that is/could be a localized.
// As only ever either password _or_ passphrase are available, this
// should be save (see fetchCredentials)
pwd = passphrase.clone();
Arrays.fill(passphrase, (char) 0);
credentialsReady = false;
}
return pwd;
}
Expand Down
1 change: 0 additions & 1 deletion ide/ide.kit/manifest.mf
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.ide.kit
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/ide/kit/Bundle.properties
OpenIDE-Module-Specification-Version: 1.66
OpenIDE-Module-Needs: org.netbeans.Netbinox

17 changes: 4 additions & 13 deletions ide/libs.git/nbproject/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
<code-name-base>org.netbeans.libs.git</code-name-base>
<module-dependencies>
<dependency>
<code-name-base>com.jcraft.jsch</code-name-base>
<code-name-base>org.apache.sshd.osgi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>0.1.55</specification-version>
<specification-version>2.17.1</specification-version>
</run-dependency>
</dependency>
<dependency>
Expand All @@ -42,20 +42,11 @@
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.eclipse.jgit.ssh.jsch</code-name-base>
<code-name-base>org.eclipse.jgit.ssh.apache</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>6.7</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.netbeans.libs.jsch.agentproxy</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
<specification-version>1.0</specification-version>
<specification-version>7.6.0</specification-version>
</run-dependency>
</dependency>
</module-dependencies>
Expand Down
217 changes: 65 additions & 152 deletions ide/libs.git/src/org/netbeans/libs/git/jgit/JGitSshSessionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,202 +18,115 @@
*/
package org.netbeans.libs.git.jgit;

import com.jcraft.jsch.AgentConnector;
import com.jcraft.jsch.AgentIdentityRepository;
import com.jcraft.jsch.IdentityRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig.Host;
import org.eclipse.jgit.transport.RemoteSession;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.sshd.JGitKeyCache;
import org.eclipse.jgit.transport.sshd.ProxyData;
import org.eclipse.jgit.transport.sshd.SshdSession;
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory;
import org.eclipse.jgit.util.FS;
import org.netbeans.libs.jsch.agentproxy.ConnectorFactory;

/**
*
* @author ondra
*/
public class JGitSshSessionFactory extends JschConfigSessionFactory {
static {
// jgit modifies the configuration and relies on the config keys
// signature.rsa and signature.dss to be present. In recent JSch
// versions, these entries are not all present, so this patches
// them in again
if(JSch.getConfig("ssh-rsa") != null && JSch.getConfig("signature.rsa") == null) {
JSch.setConfig("signature.rsa", JSch.getConfig("ssh-rsa"));
}
if (JSch.getConfig("ssh-dss") != null && JSch.getConfig("signature.dss") == null) {
JSch.setConfig("signature.dss", JSch.getConfig("ssh-dss"));
}
}

private OpenSshConfig sshConfig;
public class JGitSshSessionFactory extends SshdSessionFactory {
private static SshSessionFactory INSTANCE;
private static final Logger LOG = Logger.getLogger(JGitSshSessionFactory.class.getName());
private static final boolean USE_PROXY_TUNNELING = Boolean.getBoolean("git.lib.proxyHttpTunneling"); //NOI18N
private volatile boolean disableAgent;
private volatile Path identityFile;

public static synchronized SshSessionFactory getDefault () {
if (INSTANCE == null) {
INSTANCE = new JGitSshSessionFactory();
}
return INSTANCE;
}
private JSch defaultJSch;
private final Map<String, JSch> byHostName;

public JGitSshSessionFactory () {
byHostName = new HashMap<>();
}

@Override
protected void configure (Host host, Session sn) {
sn.setConfig("PreferredAuthentications", "publickey,password,keyboard-interactive"); //NOI18N
protected String getDefaultPreferredAuthentications() {
if(identityFile != null) {
return "publickey";
} else {
return "password,keyboard-interactive";
}
}

@Override
public synchronized RemoteSession getSession (URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws TransportException {
boolean agentUsed = false;
String host = uri.getHost();
CredentialItem.StringType identityFile = null;
if (credentialsProvider != null) {
identityFile = new JGitCredentialsProvider.IdentityFileItem("Identity file for " + host, false);
if (credentialsProvider.isInteractive() && credentialsProvider.get(uri, identityFile) && identityFile.getValue() != null) {
LOG.log(Level.FINE, "Identity file for {0}: {1}", new Object[] { host, identityFile.getValue() }); //NOI18N
agentUsed = setupJSch(fs, host, identityFile, uri, true);
LOG.log(Level.FINE, "Setting cert auth for {0}, agent={1}", new Object[] { host, agentUsed }); //NOI18N
}
}
try {
LOG.log(Level.FINE, "Trying to connect to {0}, agent={1}", new Object[] { host, agentUsed }); //NOI18N
return super.getSession(uri, credentialsProvider, fs, tms);
} catch (Exception ex) {
// catch rather all exceptions. In case jsch-agent-proxy is broken again we should
// at least fall back on key/pasphrase
if (agentUsed) {
LOG.log(ex instanceof TransportException ? Level.FINE : Level.INFO, null, ex);
setupJSch(fs, host, identityFile, uri, false);
LOG.log(Level.FINE, "Trying to connect to {0}, agent={1}", new Object[] { host, false }); //NOI18N
return super.getSession(uri, credentialsProvider, fs, tms);
} else {
LOG.log(Level.FINE, "Connection failed: {0}", host); //NOI18N
throw ex;
}
protected ConnectorFactory getConnectorFactory() {
if(disableAgent) {
return null;
} else {
return super.getConnectorFactory();
}
}

@Override
protected JSch getJSch (Host hc, FS fs) throws JSchException {
// default jsch to gain known hosts from
if (defaultJSch == null) {
defaultJSch = createDefaultJSch(fs);
final File home = fs.userHome();
if (home != null) {
File known_hosts = new File(new File(home, ".ssh"), "known_hosts"); //NOI18N
defaultJSch.setKnownHosts(known_hosts.getAbsolutePath());
}
defaultJSch.removeAllIdentity();
}
String hostName = hc.getHostName();
JSch jsch = byHostName.get(hostName);
if (jsch == null) {
jsch = new JSch();
jsch.setHostKeyRepository(defaultJSch.getHostKeyRepository());
byHostName.put(hostName, jsch);
}
return jsch;
protected List<Path> getDefaultIdentities(File sshDir) {
return identityFile == null ? List.of() : List.of(identityFile);
}

@Override
protected Session createSession (Host hc, String user, String host, int port, FS fs) throws JSchException {
Session session = super.createSession(hc, user, host, port, fs);
try {
List<Proxy> proxies = ProxySelector.getDefault().select(new URI("socket",
null,
host,
port == -1 ? 22 : port,
null, null, null));
if (!proxies.isEmpty()) {
Proxy p = proxies.iterator().next();
if (p.type() == Proxy.Type.DIRECT) {
session.setProxy(null);
} else {
SocketAddress addr = p.address();
if (addr instanceof InetSocketAddress) {
InetSocketAddress inetAddr = (InetSocketAddress) addr;
String proxyHost = inetAddr.getHostName();
int proxyPort = inetAddr.getPort();
session.setProxy(createProxy(proxyHost, proxyPort));
private JGitSshSessionFactory() {
super(new JGitKeyCache(), (InetSocketAddress isa) -> {
try {
List<Proxy> proxies = ProxySelector.getDefault().select(
new URI("socket",
null,
isa.getHostString(),
isa.getPort() == -1 ? 22 : isa.getPort(),
null, null, null));
if (!proxies.isEmpty()) {
Proxy p = proxies.iterator().next();
if (p.type() == Proxy.Type.DIRECT) {
return null;
} else if (USE_PROXY_TUNNELING) {
return new ProxyData(new Proxy(Proxy.Type.HTTP, p.address()));
} else {
return new ProxyData(new Proxy(Proxy.Type.SOCKS, p.address()));
}
}
return null;
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, "Failed to determine proxy for " + isa, ex);
return new ProxyData(Proxy.NO_PROXY);
}
} catch (URISyntaxException ex) {
Logger.getLogger(JGitSshSessionFactory.class.getName()).log(Level.INFO, "Invalid URI: " + host + ":" + port, ex);
}
return session;
});
}

private boolean setupJSchIdentityRepository (JSch jsch, String identityFile, boolean preferAgent) throws JSchException {

@Override
public synchronized SshdSession getSession (URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws TransportException {
// The call sequence assumes, that super#getSession will initialize
// the session immediately. This method is sychronized so that each
// client receives the correct configuration (see
// #getDefaultPreferredAuthentications, #getConnectorFactory,
// #getDefaultIdentities
boolean agentUsed = false;
if (preferAgent) {
AgentConnector agentConnector = ConnectorFactory.getInstance().createConnector(ConnectorFactory.ConnectorKind.ANY);
if (agentConnector != null) {
IdentityRepository irepo = new AgentIdentityRepository(agentConnector);
if (irepo.getStatus() == IdentityRepository.RUNNING) {
jsch.setIdentityRepository(irepo);
agentUsed = true;
}
String host = uri.getHost();
CredentialItem.StringType identityFile = null;
this.disableAgent = true;
this.identityFile = null;
if (credentialsProvider != null) {
identityFile = new JGitCredentialsProvider.IdentityFileItem("Identity file for " + host, false);
if (credentialsProvider.isInteractive() && credentialsProvider.get(uri, identityFile) && identityFile.getValue() != null) {
LOG.log(Level.FINE, "Identity file for {0}: {1}", new Object[] { host, identityFile.getValue() }); //NOI18N
this.disableAgent = false;
this.identityFile = Path.of(identityFile.getValue());
LOG.log(Level.FINE, "Setting cert auth for {0}, agent={1}", new Object[] { host, agentUsed }); //NOI18N
}
}
if (!agentUsed) {
jsch.setIdentityRepository(null);
// remove all identity files
jsch.removeAllIdentity();
// and add the one specified by CredentialsProvider
jsch.addIdentity(identityFile);
}
return agentUsed;
}

private boolean setupJSch (FS fs, String host, CredentialItem.StringType identityFile, URIish uri, boolean preferAgent) throws TransportException {
boolean agentUsed;
if (sshConfig == null) {
sshConfig = OpenSshConfig.get(fs);
}
final OpenSshConfig.Host hc = sshConfig.lookup(host);
try {
JSch jsch = getJSch(hc, fs);
agentUsed = setupJSchIdentityRepository(jsch, identityFile.getValue(), preferAgent);
} catch (JSchException ex) {
throw new TransportException(uri, ex.getMessage(), ex);
}
return agentUsed;
LOG.log(Level.FINE, "Trying to connect to {0}, agent={1}", new Object[] { host, agentUsed }); //NOI18N
return super.getSession(uri, credentialsProvider, fs, tms);
}

private com.jcraft.jsch.Proxy createProxy (String proxyHost, int proxyPort) {
return USE_PROXY_TUNNELING
? new ProxyHTTP(proxyHost, proxyPort)
: new ProxySOCKS5(proxyHost, proxyPort);
}

}
Loading
Loading