Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closes #1180 - The configuration server does not use custom private keys for authenticating Git fetches #1190

Merged
merged 3 commits into from
Aug 16, 2021
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.*;
Expand Down Expand Up @@ -133,12 +132,7 @@ private RemoteRefUpdate.Status push(Branch localBranch, RemoteRepositorySettings
.setRemote(targetRepository.getRemoteName())
.setRefSpecs(refSpec)
.setForce(useForcePush);

if (targetRepository.getAuthenticationType() == AuthenticationType.PASSWORD) {
authenticatePassword(pushCommand, targetRepository);
} else if (targetRepository.getAuthenticationType() == AuthenticationType.PPK) {
authenticatePpk(pushCommand, targetRepository);
}
authenticateCommand(pushCommand, targetRepository);

Iterable<PushResult> pushResults = pushCommand.call();
PushResult pushResult = pushResults.iterator().next();
Expand All @@ -159,29 +153,71 @@ private RemoteRefUpdate.Status push(Branch localBranch, RemoteRepositorySettings
}
}

/**
* Fetches the branch represented by the given {@link RemoteRepositorySettings}.
*
* @param sourceRepository the definition of the remote repository and branch
*/
public void fetchSourceBranch(RemoteRepositorySettings sourceRepository) throws GitAPIException {
log.info("Fetching branch '{}' from configuration remote '{}'.", sourceRepository.getBranchName(), sourceRepository
.getRemoteName());

LsRemoteCommand lsRemoteCommand = git.lsRemote().setRemote(sourceRepository.getRemoteName());
authenticateCommand(lsRemoteCommand, sourceRepository);

Collection<Ref> refs = lsRemoteCommand.call();

Optional<Ref> sourceBranch = refs.stream()
.filter(ref -> ref.getName().equals("refs/heads/" + sourceRepository.getBranchName()))
.findAny();

if (!sourceBranch.isPresent()) {
throw new IllegalStateException(String.format("Specified configuration source branch '%s' does not exists on remote '%s'.", sourceRepository
.getBranchName(), sourceRepository.getRemoteName()));
}

FetchCommand fetchCommand = git.fetch()
.setRemote(sourceRepository.getRemoteName())
.setRefSpecs("refs/heads/" + sourceRepository.getBranchName() + ":refs/heads/" + sourceRepository.getBranchName());
authenticateCommand(fetchCommand, sourceRepository);

FetchResult fetchResult = fetchCommand.call();

if (fetchResult.getTrackingRefUpdates().isEmpty()) {
log.info("No change has been fetched.");
} else {
for (TrackingRefUpdate refUpdate : fetchResult.getTrackingRefUpdates()) {
log.info("Fetching from '{}' ended with result: {}", refUpdate.getRemoteName(), refUpdate.getResult());
}
}
}

/**
* Injects a {@link CredentialsProvider} for executing a user-password authentication. This is used for HTTP(s)-remotes.
*
* @param command the command to authenticate
* @param remoteRepository the settings for the repository
*/
private void authenticatePassword(PushCommand pushCommand, RemoteRepositorySettings targetRepository) {
String username = targetRepository.getUsername();
String password = targetRepository.getPassword();
private void authenticatePassword(TransportCommand<?, ?> command, RemoteRepositorySettings remoteRepository) {
String username = remoteRepository.getUsername();
String password = remoteRepository.getPassword();
UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(username, password);
pushCommand.setCredentialsProvider(credentialsProvider);
command.setCredentialsProvider(credentialsProvider);
}

/**
* Injects a session factory for creating SSH sessions. This allows the usage of private keys for connection authentication.
*
* @param pushCommand the push command to authenticate
* @param targetRepository the settings for the repository to push to
* @param command the command to authenticate
* @param remoteRepository the settings for the repository
*/
private void authenticatePpk(PushCommand pushCommand, RemoteRepositorySettings targetRepository) {
private void authenticatePpk(TransportCommand<?, ?> command, RemoteRepositorySettings remoteRepository) {
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
@Override
protected JSch createDefaultJSch(FS fs) throws JSchException {
JSch defaultJSch = super.createDefaultJSch(fs);

String privateKeyFile = targetRepository.getPrivateKeyFile();
String privateKeyFile = remoteRepository.getPrivateKeyFile();
if (StringUtils.isNotBlank(privateKeyFile)) {
defaultJSch.addIdentity(privateKeyFile);
}
Expand All @@ -194,42 +230,23 @@ protected void configure(OpenSshConfig.Host hc, Session session) {
}
};

pushCommand.setTransportConfigCallback(transport -> {
command.setTransportConfigCallback(transport -> {
SshTransport sshTransport = (SshTransport) transport;
sshTransport.setSshSessionFactory(sshSessionFactory);
});
}

/**
* Fetches the branch represented by the given {@link RemoteRepositorySettings}.
* Authenticates the given command with a password or PPK authentication, depending on the given {@link RemoteRepositorySettings}.
*
* @param sourceRepository the definition of the remote repository and branch
* @param command the command to authenticate
* @param remoteRepository the settings for the repository
*/
public void fetchSourceBranch(RemoteRepositorySettings sourceRepository) throws GitAPIException {
log.info("Fetching branch '{}' from configuration remote '{}'.", sourceRepository.getBranchName(), sourceRepository
.getRemoteName());

Collection<Ref> refs = git.lsRemote().setRemote(sourceRepository.getRemoteName()).call();
Optional<Ref> sourceBanch = refs.stream()
.filter(ref -> ref.getName().equals("refs/heads/" + sourceRepository.getBranchName()))
.findAny();

if (!sourceBanch.isPresent()) {
throw new IllegalStateException(String.format("Specified configuration source branch '%s' does not exists on remote '%s'.", sourceRepository
.getBranchName(), sourceRepository.getRemoteName()));
}

FetchResult fetchResult = git.fetch()
.setRemote(sourceRepository.getRemoteName())
.setRefSpecs("refs/heads/" + sourceRepository.getBranchName() + ":refs/heads/" + sourceRepository.getBranchName())
.call();

if (fetchResult.getTrackingRefUpdates().isEmpty()) {
log.info("No change has been fetched.");
} else {
for (TrackingRefUpdate refUpdate : fetchResult.getTrackingRefUpdates()) {
log.info("Fetching from '{}' ended with result: {}", refUpdate.getRemoteName(), refUpdate.getResult());
}
private void authenticateCommand(TransportCommand<?, ?> command, RemoteRepositorySettings remoteRepository) {
if (remoteRepository.getAuthenticationType() == AuthenticationType.PASSWORD) {
authenticatePassword(command, remoteRepository);
} else if (remoteRepository.getAuthenticationType() == AuthenticationType.PPK) {
authenticatePpk(command, remoteRepository);
}
}
}