/*
 * Copyright (C) 2018, 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.junit.ssh;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.apache.sshd.common.util.threads.CloseableExecutorService;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.sshd.server.ServerAuthenticationManager;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.UserAuth;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.auth.gss.UserAuthGSS;
import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
import org.apache.sshd.server.command.AbstractCommandSupport;
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.UnknownCommand;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.UploadPack;

/**
 * A simple ssh/sftp git <em>test</em> server based on Apache MINA sshd.
 * <p>
 * Supports only a single repository. Authenticates only the given test user
 * against his given test public key. Supports fetch and push.
 * </p>
 *
 * @since 5.2
 */
public class SshTestGitServer {

	@NonNull
	protected final String testUser;

	@NonNull
	protected final Repository repository;

	@NonNull
	protected final List<KeyPair> hostKeys = new ArrayList<>();

	protected final SshServer server;

	@NonNull
	protected PublicKey testKey;

	private final CloseableExecutorService executorService = ThreadUtils
			.newFixedThreadPool("SshTestGitServerPool", 2);

	/**
	 * Creates a ssh git <em>test</em> server. It serves one single repository,
	 * and accepts public-key authentication for exactly one test user.
	 *
	 * @param testUser
	 *            user name of the test user
	 * @param testKey
	 *            <em>private</em> key file of the test user; the server will
	 *            only user the public key from it
	 * @param repository
	 *            to serve
	 * @param hostKey
	 *            the unencrypted private key to use as host key
	 * @throws IOException
	 * @throws GeneralSecurityException
	 */
	public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
			@NonNull Repository repository, @NonNull byte[] hostKey)
			throws IOException, GeneralSecurityException {
		this.testUser = testUser;
		setTestUserPublicKey(testKey);
		this.repository = repository;
		server = SshServer.setUpDefaultServer();
		// Set host key
		try (ByteArrayInputStream in = new ByteArrayInputStream(hostKey)) {
			SecurityUtils.loadKeyPairIdentities(null, null, in, null)
					.forEach((k) -> hostKeys.add(k));
		} catch (IOException | GeneralSecurityException e) {
			// Ignore.
		}
		server.setKeyPairProvider((session) -> hostKeys);

		configureAuthentication();

		List<NamedFactory<Command>> subsystems = configureSubsystems();
		if (!subsystems.isEmpty()) {
			server.setSubsystemFactories(subsystems);
		}

		configureShell();

		server.setCommandFactory(command -> {
			if (command.startsWith(RemoteConfig.DEFAULT_UPLOAD_PACK)) {
				return new GitUploadPackCommand(command, executorService);
			} else if (command.startsWith(RemoteConfig.DEFAULT_RECEIVE_PACK)) {
				return new GitReceivePackCommand(command, executorService);
			}
			return new UnknownCommand(command);
		});
	}

	private static class FakeUserAuthGSS extends UserAuthGSS {
		@Override
		protected Boolean doAuth(Buffer buffer, boolean initial)
				throws Exception {
			// We always reply that we did do this, but then we fail at the
			// first token message. That way we can test that the client-side
			// sends the correct initial request and then is skipped correctly,
			// even if it causes a GSSException if Kerberos isn't configured at
			// all.
			if (initial) {
				ServerSession session = getServerSession();
				Buffer b = session.createBuffer(
						SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST);
				b.putBytes(KRB5_MECH.getDER());
				session.writePacket(b);
				return null;
			}
			return Boolean.FALSE;
		}
	}

	private List<NamedFactory<UserAuth>> getAuthFactories() {
		List<NamedFactory<UserAuth>> authentications = new ArrayList<>();
		authentications.add(new UserAuthGSSFactory() {
			@Override
			public UserAuth create() {
				return new FakeUserAuthGSS();
			}
		});
		authentications.add(
				ServerAuthenticationManager.DEFAULT_USER_AUTH_PUBLIC_KEY_FACTORY);
		authentications.add(
				ServerAuthenticationManager.DEFAULT_USER_AUTH_KB_INTERACTIVE_FACTORY);
		authentications.add(
				ServerAuthenticationManager.DEFAULT_USER_AUTH_PASSWORD_FACTORY);
		return authentications;
	}

	/**
	 * Configures the authentication mechanisms of this test server. Invoked
	 * from the constructor. The default sets up public key authentication for
	 * the test user, and a gssapi-with-mic authenticator that pretends to
	 * support this mechanism, but that then refuses to authenticate anyone.
	 */
	protected void configureAuthentication() {
		server.setUserAuthFactories(getAuthFactories());
		// Disable some authentications
		server.setPasswordAuthenticator(null);
		server.setKeyboardInteractiveAuthenticator(null);
		server.setHostBasedAuthenticator(null);
		// Pretend we did gssapi-with-mic.
		server.setGSSAuthenticator(new GSSAuthenticator() {
			@Override
			public boolean validateInitialUser(ServerSession session,
					String user) {
				return false;
			}
		});
		// Accept only the test user/public key
		server.setPublickeyAuthenticator((userName, publicKey, session) -> {
			return SshTestGitServer.this.testUser.equals(userName) && KeyUtils
					.compareKeys(SshTestGitServer.this.testKey, publicKey);
		});
	}

	/**
	 * Configures the test server's subsystems (sftp, scp). Invoked from the
	 * constructor. The default provides a simple SFTP setup with the root
	 * directory as the given repository's .git directory's parent. (I.e., at
	 * the directory containing the .git directory.)
	 *
	 * @return A possibly empty collection of subsystems.
	 */
	@NonNull
	protected List<NamedFactory<Command>> configureSubsystems() {
		// SFTP.
		server.setFileSystemFactory(new VirtualFileSystemFactory() {

			@Override
			protected Path computeRootDir(Session session) throws IOException {
				return SshTestGitServer.this.repository.getDirectory()
						.getParentFile().getAbsoluteFile().toPath();
			}
		});
		return Collections
				.singletonList((new SftpSubsystemFactory.Builder()).build());
	}

	/**
	 * Configures shell access for the test server. The default provides no
	 * shell at all.
	 */
	protected void configureShell() {
		// No shell
		server.setShellFactory(null);
	}

	/**
	 * Adds an additional host key to the server.
	 *
	 * @param key
	 *            path to the private key file; should not be encrypted
	 * @param inFront
	 *            whether to add the new key before other existing keys
	 * @throws IOException
	 *             if the file denoted by the {@link Path} {@code key} cannot be
	 *             read
	 * @throws GeneralSecurityException
	 *             if the key contained in the file cannot be read
	 */
	public void addHostKey(@NonNull Path key, boolean inFront)
			throws IOException, GeneralSecurityException {
		try (InputStream in = Files.newInputStream(key)) {
			KeyPair pair = SecurityUtils
					.loadKeyPairIdentities(null,
							NamedResource.ofName(key.toString()), in, null)
					.iterator().next();
			if (inFront) {
				hostKeys.add(0, pair);
			} else {
				hostKeys.add(pair);
			}
		}
	}

	/**
	 * Enable password authentication. The server will accept the test user's
	 * name, converted to all upper-case, as password.
	 */
	public void enablePasswordAuthentication() {
		server.setPasswordAuthenticator((user, pwd, session) -> {
			return testUser.equals(user)
					&& testUser.toUpperCase(Locale.ROOT).equals(pwd);
		});
	}

	/**
	 * Enable keyboard-interactive authentication. The server will accept the
	 * test user's name, converted to all upper-case, as password.
	 */
	public void enableKeyboardInteractiveAuthentication() {
		server.setPasswordAuthenticator((user, pwd, session) -> {
			return testUser.equals(user)
					&& testUser.toUpperCase(Locale.ROOT).equals(pwd);
		});
		server.setKeyboardInteractiveAuthenticator(
				DefaultKeyboardInteractiveAuthenticator.INSTANCE);
	}

	/**
	 * Starts the test server, listening on a random port.
	 *
	 * @return the port the server listens on; test clients should connect to
	 *         that port
	 * @throws IOException
	 */
	public int start() throws IOException {
		server.start();
		return server.getPort();
	}

	/**
	 * Stops the test server.
	 *
	 * @throws IOException
	 */
	public void stop() throws IOException {
		executorService.shutdownNow();
		server.stop(true);
	}

	/**
	 * Sets the test user's public key on the server.
	 *
	 * @param key
	 *            to set
	 * @throws IOException
	 *             if the file cannot be read
	 * @throws GeneralSecurityException
	 *             if the public key cannot be extracted from the file
	 */
	public void setTestUserPublicKey(Path key)
			throws IOException, GeneralSecurityException {
		this.testKey = AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
				.resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
	}

	/**
	 * Sets the lines the server sends before its server identification in the
	 * initial protocol version exchange.
	 *
	 * @param lines
	 *            to send
	 * @since 5.5
	 */
	public void setPreamble(String... lines) {
		if (lines != null && lines.length > 0) {
			PropertyResolverUtils.updateProperty(this.server,
					ServerFactoryManager.SERVER_EXTRA_IDENTIFICATION_LINES,
					String.join("|", lines));
		}
	}

	private class GitUploadPackCommand extends AbstractCommandSupport {

		protected GitUploadPackCommand(String command,
				CloseableExecutorService executorService) {
			super(command, ThreadUtils.noClose(executorService));
		}

		@Override
		public void run() {
			UploadPack uploadPack = new UploadPack(repository);
			String gitProtocol = getEnvironment().getEnv().get("GIT_PROTOCOL");
			if (gitProtocol != null) {
				uploadPack
						.setExtraParameters(Collections.singleton(gitProtocol));
			}
			try {
				uploadPack.upload(getInputStream(), getOutputStream(),
						getErrorStream());
				onExit(0);
			} catch (IOException e) {
				log.warn(
						MessageFormat.format("Could not run {0}", getCommand()),
						e);
				onExit(-1, e.toString());
			}
		}

	}

	private class GitReceivePackCommand extends AbstractCommandSupport {

		protected GitReceivePackCommand(String command,
				CloseableExecutorService executorService) {
			super(command, ThreadUtils.noClose(executorService));
		}

		@Override
		public void run() {
			try {
				new ReceivePack(repository).receive(getInputStream(),
						getOutputStream(), getErrorStream());
				onExit(0);
			} catch (IOException e) {
				log.warn(
						MessageFormat.format("Could not run {0}", getCommand()),
						e);
				onExit(-1, e.toString());
			}
		}

	}
}
