From 5eafd9b6f046a03eca0576ae14673be674b9ce01 Mon Sep 17 00:00:00 2001
From: David Ostrovsky <david@ostrovsky.org>
Date: Thu, 10 Apr 2014 18:58:08 -0400
Subject: [PATCH] Add set account SSH command

---
 src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java |  118 +++++++++++++++++++++++++++++++++++++++
 src/main/java/com/gitblit/transport/ssh/FileKeyManager.java             |    8 ++
 src/main/java/com/gitblit/transport/ssh/IKeyManager.java                |    2 
 src/main/java/com/gitblit/transport/ssh/SshDaemon.java                  |    7 ++
 src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java   |   10 +++
 src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java        |    9 +++
 src/main/java/com/gitblit/transport/ssh/NullKeyManager.java             |    5 +
 7 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
index 87912ca..f590ab2 100644
--- a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
@@ -28,6 +28,7 @@
 
 import com.gitblit.Keys;
 import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.utils.FileUtils;
 import com.google.common.base.Charsets;
 import com.google.common.io.Files;
 
@@ -144,7 +145,12 @@
 		}
 		return false;
 	}
-	
+
+	@Override
+	public boolean removeAllKey(String username) {
+		return FileUtils.delete(getKeystore(username));
+	}
+
 	protected File getKeystore(String username) {
 		File dir = runtimeManager.getFileOrFolder(Keys.git.sshKeysFolder, "${baseFolder}/ssh");
 		dir.mkdirs();
diff --git a/src/main/java/com/gitblit/transport/ssh/IKeyManager.java b/src/main/java/com/gitblit/transport/ssh/IKeyManager.java
index 8b94fd6..3528bf1 100644
--- a/src/main/java/com/gitblit/transport/ssh/IKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/IKeyManager.java
@@ -36,4 +36,6 @@
 	boolean addKey(String username, String data);
 	
 	boolean removeKey(String username, String data);
+
+	boolean removeAllKey(String username);
 }
diff --git a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
index 2a2ef36..6990d0d 100644
--- a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
@@ -63,4 +63,9 @@
 	public boolean removeKey(String username, String data) {
 		return false;
 	}
+
+	@Override
+	public boolean removeAllKey(String username) {
+		return false;
+	}
 }
diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
index f0429a7..f2e1db7 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -44,6 +44,7 @@
 import com.gitblit.transport.ssh.commands.CreateRepository;
 import com.gitblit.transport.ssh.commands.DispatchCommand;
 import com.gitblit.transport.ssh.commands.Receive;
+import com.gitblit.transport.ssh.commands.SetAccountCommand;
 import com.gitblit.transport.ssh.commands.Upload;
 import com.gitblit.transport.ssh.commands.VersionCommand;
 import com.gitblit.utils.IdGenerator;
@@ -116,12 +117,14 @@
 			addr = new InetSocketAddress(bindInterface, port);
 		}
 
+		SshKeyAuthenticator publickeyAuthenticator = new SshKeyAuthenticator(
+				keyManager, gitblit);
 		sshd = SshServer.setUpDefaultServer();
 		sshd.setPort(addr.getPort());
 		sshd.setHost(addr.getHostName());
 		sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(new File(
 				gitblit.getBaseFolder(), HOST_KEY_STORE).getPath()));
-		sshd.setPublickeyAuthenticator(new SshKeyAuthenticator(keyManager, gitblit));
+		sshd.setPublickeyAuthenticator(publickeyAuthenticator);
 		sshd.setPasswordAuthenticator(new SshPasswordAuthenticator(gitblit));
 		sshd.setSessionFactory(new SshSessionFactory(idGenerator));
 		sshd.setFileSystemFactory(new DisabledFilesystemFactory());
@@ -130,6 +133,7 @@
 		DispatchCommand gitblitCmd = new DispatchCommand();
 		gitblitCmd.registerCommand(CreateRepository.class);
 		gitblitCmd.registerCommand(VersionCommand.class);
+		gitblitCmd.registerCommand(SetAccountCommand.class);
 
 		DispatchCommand gitCmd = new DispatchCommand();
 		gitCmd.registerCommand(Upload.class);
@@ -142,6 +146,7 @@
 		root.setRepositoryResolver(new RepositoryResolver<SshSession>(gitblit));
 		root.setUploadPackFactory(new GitblitUploadPackFactory<SshSession>(gitblit));
 		root.setReceivePackFactory(new GitblitReceivePackFactory<SshSession>(gitblit));
+		root.setAuthenticator(publickeyAuthenticator);
 
 		SshCommandFactory commandFactory = new SshCommandFactory(
 				new WorkQueue(idGenerator),
diff --git a/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java
index d41afdd..f1bff4f 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java
@@ -26,6 +26,7 @@
 
 import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.models.UserModel;
+import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -91,4 +92,12 @@
 		sd.authenticationError(username, "user-not-found");
 		return false;
 	}
+
+	public IKeyManager getKeyManager() {
+		return keyManager;
+	}
+	
+	public Cache<String, List<PublicKey>> getKeyCache() {
+		return sshKeyCache;
+	}
 }
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
index 597b9ea..31b718e 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -32,6 +32,7 @@
 import com.gitblit.git.RepositoryResolver;
 import com.gitblit.transport.ssh.AbstractGitCommand;
 import com.gitblit.transport.ssh.CommandMetaData;
+import com.gitblit.transport.ssh.SshKeyAuthenticator;
 import com.gitblit.transport.ssh.SshSession;
 import com.gitblit.utils.cli.SubcommandHandler;
 import com.google.common.base.Charsets;
@@ -196,6 +197,10 @@
 		d.setRepositoryResolver(repositoryResolver);
 		d.setUploadPackFactory(gitblitUploadPackFactory);
 		d.setReceivePackFactory(gitblitReceivePackFactory);
+		d.setAuthenticator(authenticator);
+	  } else if (cmd instanceof SetAccountCommand) {
+		  SetAccountCommand setAccountCommand = (SetAccountCommand)cmd;
+		  setAccountCommand.setAuthenticator(authenticator);
 	  }
   }
 
@@ -213,4 +218,9 @@
   public void setReceivePackFactory(GitblitReceivePackFactory<SshSession> gitblitReceivePackFactory) {
 	  this.gitblitReceivePackFactory = gitblitReceivePackFactory;
   }
+
+  private SshKeyAuthenticator authenticator;
+  public void setAuthenticator(SshKeyAuthenticator authenticator) {
+	this.authenticator = authenticator;
+  }
 }
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java
new file mode 100644
index 0000000..98d9aba
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java
@@ -0,0 +1,118 @@
+//Copyright (C) 2012 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+package com.gitblit.transport.ssh.commands;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import com.gitblit.transport.ssh.CommandMetaData;
+import com.gitblit.transport.ssh.IKeyManager;
+import com.gitblit.transport.ssh.SshKeyAuthenticator;
+import com.google.common.base.Charsets;
+
+/** Set a user's account settings. **/
+@CommandMetaData(name = "set-account", description = "Change an account's settings")
+public class SetAccountCommand extends SshCommand {
+
+	private static final String ALL = "ALL";
+
+	@Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id")
+	private String user;
+
+	@Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account")
+	private List<String> addSshKeys = new ArrayList<String>();
+
+	@Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account")
+	private List<String> deleteSshKeys = new ArrayList<String>();
+
+	@Override
+	public void run() throws IOException, UnloggedFailure {
+		validate();
+		setAccount();
+	}
+
+	private void validate() throws UnloggedFailure {
+		if (addSshKeys.contains("-") && deleteSshKeys.contains("-")) {
+			throw new UnloggedFailure(1, "Only one option may use the stdin");
+		}
+		if (deleteSshKeys.contains(ALL)) {
+			deleteSshKeys = Collections.singletonList(ALL);
+		}
+	}
+
+	private void setAccount() throws IOException, UnloggedFailure {
+		addSshKeys = readSshKey(addSshKeys);
+		if (!addSshKeys.isEmpty()) {
+			addSshKeys(addSshKeys);
+		}
+
+		deleteSshKeys = readSshKey(deleteSshKeys);
+		if (!deleteSshKeys.isEmpty()) {
+			deleteSshKeys(deleteSshKeys);
+		}
+		authenticator.getKeyCache().invalidate(user);
+	}
+
+	private void addSshKeys(List<String> sshKeys) throws UnloggedFailure,
+			IOException {
+		IKeyManager keyManager = authenticator.getKeyManager();
+		for (String sshKey : sshKeys) {
+			keyManager.addKey(user, sshKey);
+		}
+	}
+
+	private void deleteSshKeys(List<String> sshKeys) {
+		IKeyManager keyManager = authenticator.getKeyManager();
+		if (sshKeys.contains(ALL)) {
+			keyManager.removeAllKey(user);
+		} else {
+			for (String sshKey : sshKeys) {
+				keyManager.removeKey(user, sshKey);
+			}
+		}
+	}
+
+	private List<String> readSshKey(List<String> sshKeys)
+			throws UnsupportedEncodingException, IOException {
+		if (!sshKeys.isEmpty()) {
+			String sshKey;
+			int idx = sshKeys.indexOf("-");
+			if (idx >= 0) {
+				sshKey = "";
+				BufferedReader br = new BufferedReader(new InputStreamReader(
+						in, Charsets.UTF_8));
+				String line;
+				while ((line = br.readLine()) != null) {
+					sshKey += line + "\n";
+				}
+				sshKeys.set(idx, sshKey);
+			}
+		}
+		return sshKeys;
+	}
+
+	private SshKeyAuthenticator authenticator;
+	public void setAuthenticator(SshKeyAuthenticator authenticator) {
+		this.authenticator = authenticator;
+	}
+}

--
Gitblit v1.9.1