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