JGitPublicKeyAuthentication.java
/*
* Copyright (C) 2018, 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.internal.transport.sshd;
import static java.text.MessageFormat.format;
import static org.eclipse.jgit.transport.SshConstants.PUBKEY_ACCEPTED_ALGORITHMS;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity;
import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity;
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.signature.Signature;
import org.eclipse.jgit.util.StringUtils;
/**
* Custom {@link UserAuthPublicKey} implementation for handling SSH config
* PubkeyAcceptedAlgorithms.
*/
public class JGitPublicKeyAuthentication extends UserAuthPublicKey {
JGitPublicKeyAuthentication(List<NamedFactory<Signature>> factories) {
super(factories);
}
@Override
public void init(ClientSession rawSession, String service)
throws Exception {
if (!(rawSession instanceof JGitClientSession)) {
throw new IllegalStateException("Wrong session type: " //$NON-NLS-1$
+ rawSession.getClass().getCanonicalName());
}
JGitClientSession session = (JGitClientSession) rawSession;
HostConfigEntry hostConfig = session.getHostConfigEntry();
// Set signature algorithms for public key authentication
String pubkeyAlgos = hostConfig.getProperty(PUBKEY_ACCEPTED_ALGORITHMS);
if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) {
List<String> signatures = session.getSignatureFactoriesNames();
signatures = session.modifyAlgorithmList(signatures,
session.getAllAvailableSignatureAlgorithms(), pubkeyAlgos,
PUBKEY_ACCEPTED_ALGORITHMS);
if (!signatures.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug(PUBKEY_ACCEPTED_ALGORITHMS + ' ' + signatures);
}
setSignatureFactoriesNames(signatures);
} else {
log.warn(format(SshdText.get().configNoKnownAlgorithms,
PUBKEY_ACCEPTED_ALGORITHMS, pubkeyAlgos));
}
}
// If we don't set signature factories here, the default ones from the
// session will be used.
super.init(session, service);
// In sshd 2.7.0, we end up now with a key iterator that uses keys
// provided by an ssh-agent even if IdentitiesOnly is true. So if
// needed, filter out any KeyAgentIdentity.
if (hostConfig.isIdentitiesOnly()) {
Iterator<PublicKeyIdentity> original = keys;
// The original iterator will already have gotten the identities
// from the agent. Unfortunately there's nothing we can do about
// that; it'll have to be fixed upstream. (As will, ultimately,
// respecting isIdentitiesOnly().) At least we can simply not
// use the keys the agent provided.
//
// See https://issues.apache.org/jira/browse/SSHD-1218
keys = new Iterator<>() {
private PublicKeyIdentity value;
@Override
public boolean hasNext() {
if (value != null) {
return true;
}
PublicKeyIdentity next = null;
while (original.hasNext()) {
next = original.next();
if (!(next instanceof KeyAgentIdentity)) {
value = next;
return true;
}
}
return false;
}
@Override
public PublicKeyIdentity next() {
if (hasNext()) {
PublicKeyIdentity result = value;
value = null;
return result;
}
throw new NoSuchElementException();
}
};
}
}
}