From eecaad8b8e2c447429c31a01d49260ddd6b4ee03 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 16 Apr 2016 17:35:32 -0400 Subject: [PATCH] Proof of concept #1026 --- src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java | 148 +++++++++++++++++++++++++++++++++++------------- 1 files changed, 107 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java b/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java index ad37306..da58584 100644 --- a/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java +++ b/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.models.UserModel; +import com.gitblit.Constants.AccessPermission; import com.gitblit.transport.ssh.IPublicKeyManager; import com.gitblit.transport.ssh.SshKey; import com.gitblit.transport.ssh.commands.CommandMetaData; @@ -33,6 +33,7 @@ import com.gitblit.transport.ssh.commands.UsageExample; import com.gitblit.utils.FlipTable; import com.gitblit.utils.FlipTable.Borders; +import com.gitblit.utils.StringUtils; import com.google.common.base.Joiner; /** @@ -45,29 +46,64 @@ public class KeysDispatcher extends DispatchCommand { @Override - protected void setup(UserModel user) { - register(user, AddKey.class); - register(user, RemoveKey.class); - register(user, ListKeys.class); - register(user, WhichKey.class); - register(user, CommentKey.class); + protected void setup() { + register(AddKey.class); + register(RemoveKey.class); + register(ListKeys.class); + register(WhichKey.class); + register(CommentKey.class); + register(PermissionKey.class); } @CommandMetaData(name = "add", description = "Add an SSH public key to your account") - @UsageExample(syntax = "cat ~/.ssh/id_rsa.pub | ${ssh} ${cmd} -", description = "Upload your SSH public key and add it to your account") + @UsageExample(syntax = "cat ~/.ssh/id_rsa.pub | ${ssh} ${cmd}", description = "Upload your SSH public key and add it to your account") public static class AddKey extends BaseKeyCommand { protected final Logger log = LoggerFactory.getLogger(getClass()); - @Argument(metaVar = "<KEY>", usage = "the key(s) to add") + @Argument(metaVar = "<STDIN>", usage = "the key to add") private List<String> addKeys = new ArrayList<String>(); + @Option(name = "--permission", aliases = { "-p" }, metaVar = "PERMISSION", usage = "set the key access permission") + private String permission; + @Override - public void run() throws IOException, UnloggedFailure { + protected String getUsageText() { + String permissions = Joiner.on(", ").join(AccessPermission.SSHPERMISSIONS); + StringBuilder sb = new StringBuilder(); + sb.append("Valid SSH public key permissions are:\n ").append(permissions); + return sb.toString(); + } + + @Override + public void run() throws IOException, Failure { String username = getContext().getClient().getUsername(); List<String> keys = readKeys(addKeys); + if (keys.isEmpty()) { + throw new UnloggedFailure("No public keys were read from STDIN!"); + } for (String key : keys) { SshKey sshKey = parseKey(key); + try { + // this method parses the rawdata and produces a public key + // if it fails it will throw a Buffer.BufferException + // the null check is a QC verification on top of that + if (sshKey.getPublicKey() == null) { + throw new RuntimeException(); + } + } catch (RuntimeException e) { + throw new UnloggedFailure("The data read from SDTIN can not be parsed as an SSH public key!"); + } + if (!StringUtils.isEmpty(permission)) { + AccessPermission ap = AccessPermission.fromCode(permission); + if (ap.exceeds(AccessPermission.NONE)) { + try { + sshKey.setPermission(ap); + } catch (IllegalArgumentException e) { + throw new Failure(1, e.getMessage()); + } + } + } getKeyManager().addKey(username, sshKey); log.info("added SSH public key for {}", username); } @@ -82,22 +118,21 @@ private final String ALL = "ALL"; - @Argument(metaVar = "<INDEX>|<KEY>|ALL", usage = "the key to remove", required = true) - private List<String> removeKeys = new ArrayList<String>(); + @Argument(metaVar = "<INDEX>|ALL", usage = "the key to remove", required = true) + private List<String> keyParameters = new ArrayList<String>(); @Override - public void run() throws IOException, UnloggedFailure { + public void run() throws IOException, Failure { String username = getContext().getClient().getUsername(); // remove a key that has been piped to the command // or remove all keys - List<SshKey> currentKeys = getKeyManager().getKeys(username); - if (currentKeys == null || currentKeys.isEmpty()) { + List<SshKey> registeredKeys = new ArrayList<SshKey>(getKeyManager().getKeys(username)); + if (registeredKeys.isEmpty()) { throw new UnloggedFailure(1, "There are no registered keys!"); } - List<String> keys = readKeys(removeKeys); - if (keys.contains(ALL)) { + if (keyParameters.contains(ALL)) { if (getKeyManager().removeAllKeys(username)) { stdout.println("Removed all keys."); log.info("removed all SSH public keys from {}", username); @@ -105,32 +140,25 @@ log.warn("failed to remove all SSH public keys from {}", username); } } else { - for (String key : keys) { + for (String keyParameter : keyParameters) { try { // remove a key by it's index (1-based indexing) - int index = Integer.parseInt(key); - if (index > keys.size()) { - if (keys.size() == 1) { - throw new UnloggedFailure(1, "Invalid index specified. There is only 1 registered key."); + int index = Integer.parseInt(keyParameter); + if (index > registeredKeys.size()) { + if (keyParameters.size() == 1) { + throw new Failure(1, "Invalid index specified. There is only 1 registered key."); } - throw new UnloggedFailure(1, String.format("Invalid index specified. There are %d registered keys.", keys.size())); + throw new Failure(1, String.format("Invalid index specified. There are %d registered keys.", registeredKeys.size())); } - SshKey sshKey = currentKeys.get(index - 1); + SshKey sshKey = registeredKeys.get(index - 1); if (getKeyManager().removeKey(username, sshKey)) { stdout.println(String.format("Removed %s", sshKey.getFingerprint())); } else { - throw new UnloggedFailure(1, String.format("failed to remove #%s: %s", key, sshKey.getFingerprint())); + throw new Failure(1, String.format("failed to remove #%s: %s", keyParameter, sshKey.getFingerprint())); } - } catch (Exception e) { - // remove key by raw key data - SshKey sshKey = parseKey(key); - if (getKeyManager().removeKey(username, sshKey)) { - stdout.println(String.format("Removed %s", sshKey.getFingerprint())); - log.info("removed SSH public key {} from {}", sshKey.getFingerprint(), username); - } else { - log.warn("failed to remove SSH public key {} from {}", sshKey.getFingerprint(), username); - throw new UnloggedFailure(1, String.format("failed to remove %s", sshKey.getFingerprint())); - } + } catch (NumberFormatException e) { + log.warn("failed to remove SSH public key {} from {}", keyParameter, username); + throw new Failure(1, String.format("failed to remove key %s", keyParameter)); } } } @@ -167,14 +195,15 @@ } protected void asTable(List<SshKey> keys) { - String[] headers = { "#", "Fingerprint", "Comment", "Type" }; + String[] headers = { "#", "Fingerprint", "Comment", "Permission", "Type" }; int len = keys == null ? 0 : keys.size(); Object[][] data = new Object[len][]; for (int i = 0; i < len; i++) { // show 1-based index numbers with the fingerprint // this is useful for comparing with "ssh-add -l" SshKey k = keys.get(i); - data[i] = new Object[] { (i + 1), k.getFingerprint(), k.getComment(), k.getAlgorithm() }; + data[i] = new Object[] { (i + 1), k.getFingerprint(), k.getComment(), + k.getPermission(), k.getAlgorithm() }; } stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); @@ -211,9 +240,9 @@ } protected void asTable(int index, SshKey key) { - String[] headers = { "#", "Fingerprint", "Comment", "Type" }; + String[] headers = { "#", "Fingerprint", "Comment", "Permission", "Type" }; Object[][] data = new Object[1][]; - data[0] = new Object[] { index, key.getFingerprint(), key.getComment(), key.getAlgorithm() }; + data[0] = new Object[] { index, key.getFingerprint(), key.getComment(), key.getPermission(), key.getAlgorithm() }; stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); } @@ -230,7 +259,7 @@ private List<String> values = new ArrayList<String>(); @Override - public void run() throws UnloggedFailure { + public void run() throws Failure { final String username = getContext().getClient().getUsername(); IPublicKeyManager keyManager = getContext().getGitblit().getPublicKeyManager(); List<SshKey> keys = keyManager.getKeys(username); @@ -244,7 +273,44 @@ if (keyManager.addKey(username, key)) { stdout.println(String.format("Updated the comment for key #%d.", index)); } else { - throw new UnloggedFailure(1, String.format("Failed to update the comment for key #%d!", index)); + throw new Failure(1, String.format("Failed to update the comment for key #%d!", index)); + } + } + + } + + @CommandMetaData(name = "permission", description = "Set the permission of an SSH public key") + @UsageExample(syntax = "${cmd} 3 RW", description = "Set the permission for key #3 to PUSH (PW)") + public static class PermissionKey extends SshCommand { + + @Argument(index = 0, metaVar = "INDEX", usage = "the key index", required = true) + private int index; + + @Argument(index = 1, metaVar = "PERMISSION", usage = "the new permission", required = true) + private String value; + + @Override + public void run() throws Failure { + final String username = getContext().getClient().getUsername(); + IPublicKeyManager keyManager = getContext().getGitblit().getPublicKeyManager(); + List<SshKey> keys = keyManager.getKeys(username); + if (index > keys.size()) { + throw new UnloggedFailure(1, "Invalid key index!"); + } + + SshKey key = keys.get(index - 1); + AccessPermission permission = AccessPermission.fromCode(value); + if (permission.exceeds(AccessPermission.NONE)) { + try { + key.setPermission(permission); + } catch (IllegalArgumentException e) { + throw new Failure(1, e.getMessage()); + } + } + if (keyManager.addKey(username, key)) { + stdout.println(String.format("Updated the permission for key #%d.", index)); + } else { + throw new Failure(1, String.format("Failed to update the comment for key #%d!", index)); } } -- Gitblit v1.9.1