From 8982e6e0738c6991b9a4b864423bd4f75383c7f4 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 10 Apr 2014 18:58:08 -0400
Subject: [PATCH] Add add-key and rm-key commands that apply only to the current user

---
 src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java    |   58 ++++++++++++++
 src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java     |   54 +++++++++++++
 src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java |   35 --------
 src/main/java/com/gitblit/transport/ssh/SshDaemon.java                  |   18 ++-
 src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java  |   62 +++++++++++++++
 src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java   |    6 
 6 files changed, 191 insertions(+), 42 deletions(-)

diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
index 81d7878..c8c20f5 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -38,9 +38,11 @@
 import com.gitblit.git.GitblitUploadPackFactory;
 import com.gitblit.git.RepositoryResolver;
 import com.gitblit.manager.IGitblit;
+import com.gitblit.transport.ssh.commands.AddKeyCommand;
 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.RemoveKeyCommand;
 import com.gitblit.transport.ssh.commands.ReviewCommand;
 import com.gitblit.transport.ssh.commands.SetAccountCommand;
 import com.gitblit.transport.ssh.commands.Upload;
@@ -67,7 +69,7 @@
 	public static enum SshSessionBackend {
 		MINA, NIO2
 	}
-	
+
 	/**
 	 * 22: IANA assigned port number for ssh. Note that this is a distinct
 	 * concept from gitblit's default conf for ssh port -- this "default" is
@@ -92,7 +94,7 @@
 	public SshDaemon(IGitblit gitblit, IdGenerator idGenerator) {
 		this.gitblit = gitblit;
 		this.injector = ObjectGraph.create(new SshModule());
-		
+
 		IStoredSettings settings = gitblit.getSettings();
 		int port = settings.getInteger(Keys.git.sshPort, 0);
 		String bindInterface = settings.getString(Keys.git.sshBindInterface,
@@ -107,7 +109,7 @@
 		    backend == SshSessionBackend.MINA
 		    	? MinaServiceFactoryFactory.class.getName()
 		    	: Nio2ServiceFactoryFactory.class.getName());
-		
+
 		InetSocketAddress addr;
 		if (StringUtils.isEmpty(bindInterface)) {
 			addr = new InetSocketAddress(port);
@@ -131,6 +133,8 @@
 		DispatchCommand gitblitCmd = new DispatchCommand();
 		gitblitCmd.registerCommand(CreateRepository.class);
 		gitblitCmd.registerCommand(VersionCommand.class);
+		gitblitCmd.registerCommand(AddKeyCommand.class);
+		gitblitCmd.registerCommand(RemoveKeyCommand.class);
 		gitblitCmd.registerCommand(SetAccountCommand.class);
 		gitblitCmd.registerCommand(ReviewCommand.class);
 
@@ -210,14 +214,14 @@
 			}
 		}
 	}
-	
+
 	protected IKeyManager getKeyManager() {
 		IKeyManager keyManager = null;
 		IStoredSettings settings = gitblit.getSettings();
 		String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
 		if (StringUtils.isEmpty(clazz)) {
 			clazz = FileKeyManager.class.getName();
-		}		
+		}
 		try {
 			Class<? extends IKeyManager> managerClass = (Class<? extends IKeyManager>) Class.forName(clazz);
 			keyManager = injector.get(managerClass).start();
@@ -232,7 +236,7 @@
 		}
 		return keyManager;
 	}
-	
+
 	/**
 	 * A nested Dagger graph is used for constructor dependency injection of
 	 * complex classes.
@@ -252,7 +256,7 @@
 		@Provides @Singleton NullKeyManager provideNullKeyManager() {
 			return new NullKeyManager();
 		}
-		
+
 		@Provides @Singleton FileKeyManager provideFileKeyManager() {
 			return new FileKeyManager(SshDaemon.this.gitblit);
 		}
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java
new file mode 100644
index 0000000..69c4fec
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * 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.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.transport.ssh.CommandMetaData;
+import com.gitblit.transport.ssh.IKeyManager;
+
+/**
+ * Add a key to the current user's authorized keys list.
+ *
+ * @author James Moger
+ *
+ */
+@CommandMetaData(name = "add-key", description = "Add an SSH public key to your account")
+public class AddKeyCommand extends BaseKeyCommand {
+
+	protected final Logger log = LoggerFactory.getLogger(getClass());
+
+	@Argument(metaVar = "<stdin>|KEY", usage = "the key to add")
+	private List<String> addKeys = new ArrayList<String>();
+
+	@Override
+	public void run() throws IOException, UnloggedFailure {
+		String username = ctx.getClient().getUsername();
+		List<String> keys = readKeys(addKeys);
+		IKeyManager keyManager = authenticator.getKeyManager();
+		for (String key : keys) {
+			keyManager.addKey(username, key);
+			log.info("added SSH public key for {}", username);
+		}
+		authenticator.getKeyCache().invalidate(username);
+	}
+}
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java
new file mode 100644
index 0000000..50927cc
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * 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.List;
+
+import com.gitblit.transport.ssh.SshKeyAuthenticator;
+import com.google.common.base.Charsets;
+
+/**
+ *
+ * Base class for commands that read SSH keys from stdin or a parameter list.
+ *
+ */
+public abstract class BaseKeyCommand extends SshCommand {
+
+	protected List<String> readKeys(List<String> sshKeys)
+			throws UnsupportedEncodingException, IOException {
+		int idx = -1;
+		if (sshKeys.isEmpty() || ((idx = sshKeys.indexOf("-")) >= 0)) {
+			String sshKey = "";
+			BufferedReader br = new BufferedReader(new InputStreamReader(
+					in, Charsets.UTF_8));
+			String line;
+			while ((line = br.readLine()) != null) {
+				sshKey += line + "\n";
+			}
+			if (idx == -1) {
+				sshKeys.add(sshKey.trim());
+			} else {
+				sshKeys.set(idx, sshKey.trim());
+			}
+		}
+		return sshKeys;
+	}
+
+	protected SshKeyAuthenticator authenticator;
+	public void setAuthenticator(SshKeyAuthenticator authenticator) {
+		this.authenticator = authenticator;
+	}
+}
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 dc96330..672ecd6 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -198,9 +198,9 @@
 		d.setUploadPackFactory(gitblitUploadPackFactory);
 		d.setReceivePackFactory(gitblitReceivePackFactory);
 		d.setAuthenticator(authenticator);
-	  } else if (cmd instanceof SetAccountCommand) {
-		  SetAccountCommand setAccountCommand = (SetAccountCommand)cmd;
-		  setAccountCommand.setAuthenticator(authenticator);
+	  } else if (cmd instanceof BaseKeyCommand) {
+		  BaseKeyCommand k = (BaseKeyCommand)cmd;
+		  k.setAuthenticator(authenticator);
 	  }
   }
 
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java
new file mode 100644
index 0000000..0d49164
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * 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.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.transport.ssh.CommandMetaData;
+import com.gitblit.transport.ssh.IKeyManager;
+
+
+/**
+ * Remove an SSH public key from the current user's authorized key list.
+ *
+ * @author James Moger
+ *
+ */
+@CommandMetaData(name = "rm-key", description = "Remove an SSH public key from your account")
+public class RemoveKeyCommand extends BaseKeyCommand {
+
+	protected final Logger log = LoggerFactory.getLogger(getClass());
+
+	private static final String ALL = "ALL";
+
+	@Argument(metaVar = "<stdin>|<KEY>|ALL", usage = "the key to remove")
+	private List<String> removeKeys = new ArrayList<String>();
+
+	@Override
+	public void run() throws IOException, UnloggedFailure {
+		String username = ctx.getClient().getUsername();
+		List<String> keys = readKeys(removeKeys);
+		IKeyManager keyManager = authenticator.getKeyManager();
+		if (keys.contains(ALL)) {
+			keyManager.removeAllKeys(username);
+			log.info("removed all SSH public keys from {}", username);
+		} else {
+			for (String key : keys) {
+				keyManager.removeKey(username, key);
+				log.info("removed SSH public key from {}", username);
+			}
+		}
+		authenticator.getKeyCache().invalidate(username);
+	}
+}
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java
index 767f3cb..0eabdce 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java
@@ -14,10 +14,7 @@
 
 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;
@@ -27,12 +24,10 @@
 
 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 {
+public class SetAccountCommand extends BaseKeyCommand {
 
 	private static final String ALL = "ALL";
 
@@ -61,12 +56,12 @@
 	}
 
 	private void setAccount() throws IOException, UnloggedFailure {
-		addSshKeys = readSshKey(addSshKeys);
+		addSshKeys = readKeys(addSshKeys);
 		if (!addSshKeys.isEmpty()) {
 			addSshKeys(addSshKeys);
 		}
 
-		deleteSshKeys = readSshKey(deleteSshKeys);
+		deleteSshKeys = readKeys(deleteSshKeys);
 		if (!deleteSshKeys.isEmpty()) {
 			deleteSshKeys(deleteSshKeys);
 		}
@@ -90,29 +85,5 @@
 				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