From 241f57365649ffbbcc1923a1712ab86f6a443bc6 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 03 Jul 2014 17:00:40 -0400
Subject: [PATCH] Implement custom IPublicKeyManager provider

---
 src/main/java/com/gitblit/transport/ssh/FileKeyManager.java    |    2 
 src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java  |    3 
 src/main/java/com/gitblit/FederationClient.java                |  378 ++++++++++++++++++------------------
 src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java |   72 +++++++
 src/main/java/com/gitblit/manager/GitblitManager.java          |   33 ++-
 src/main/java/com/gitblit/wicket/GitBlitWebApp.java            |   11 
 src/main/java/com/gitblit/GitBlit.java                         |   26 --
 src/main/java/com/gitblit/guice/CoreModule.java                |   34 ---
 src/main/java/com/gitblit/transport/ssh/NullKeyManager.java    |    3 
 9 files changed, 304 insertions(+), 258 deletions(-)

diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java
index 29cdefe..af92b5f 100644
--- a/src/main/java/com/gitblit/FederationClient.java
+++ b/src/main/java/com/gitblit/FederationClient.java
@@ -1,189 +1,189 @@
-/*
- * Copyright 2011 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;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.Option;
-
-import com.gitblit.manager.FederationManager;
-import com.gitblit.manager.GitblitManager;
-import com.gitblit.manager.IGitblit;
-import com.gitblit.manager.INotificationManager;
-import com.gitblit.manager.RepositoryManager;
-import com.gitblit.manager.RuntimeManager;
-import com.gitblit.manager.UserManager;
-import com.gitblit.models.FederationModel;
-import com.gitblit.models.Mailing;
-import com.gitblit.service.FederationPullService;
-import com.gitblit.utils.FederationUtils;
-import com.gitblit.utils.StringUtils;
-
-/**
- * Command-line client to pull federated Gitblit repositories.
- *
- * @author James Moger
- *
- */
-public class FederationClient {
-
-	public static void main(String[] args) {
-		Params params = new Params();
-		CmdLineParser parser = new CmdLineParser(params);
-		try {
-			parser.parseArgument(args);
-		} catch (CmdLineException t) {
-			usage(parser, t);
-		}
-
-		System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")");
-
-		// command-line specified base folder
-		File baseFolder = new File(System.getProperty("user.dir"));
-		if (!StringUtils.isEmpty(params.baseFolder)) {
-			baseFolder = new File(params.baseFolder);
-		}
-
-		File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile);
-		FileSettings settings = new FileSettings(regFile.getAbsolutePath());
-		List<FederationModel> registrations = new ArrayList<FederationModel>();
-		if (StringUtils.isEmpty(params.url)) {
-			registrations.addAll(FederationUtils.getFederationRegistrations(settings));
-		} else {
-			if (StringUtils.isEmpty(params.token)) {
-				System.out.println("Must specify --token parameter!");
-				System.exit(0);
-			}
-			FederationModel model = new FederationModel("Gitblit");
-			model.url = params.url;
-			model.token = params.token;
-			model.mirror = params.mirror;
-			model.bare = params.bare;
-			model.folder = "";
-			registrations.add(model);
-		}
-		if (registrations.size() == 0) {
-			System.out.println("No Federation Registrations!  Nothing to do.");
-			System.exit(0);
-		}
-
-		// command-line specified repositories folder
-		if (!StringUtils.isEmpty(params.repositoriesFolder)) {
-			settings.overrideSetting(Keys.git.repositoriesFolder, new File(
-					params.repositoriesFolder).getAbsolutePath());
-		}
-
-		// configure the Gitblit singleton for minimal, non-server operation
-		RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start();
-		NoopNotificationManager notifications = new NoopNotificationManager().start();
-		UserManager users = new UserManager(runtime, null).start();
-		RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
-		FederationManager federation = new FederationManager(runtime, notifications, repositories).start();
-		IGitblit gitblit = new GitblitManager(runtime, null, notifications, users, null, null, repositories, null, federation);
-
-		FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) {
-			@Override
-			public void reschedule(FederationModel registration) {
-				// NOOP
-			}
-		};
-		puller.run();
-
-		System.out.println("Finished.");
-		System.exit(0);
-	}
-
-	private static void usage(CmdLineParser parser, CmdLineException t) {
-		System.out.println(Constants.getGitBlitVersion());
-		System.out.println();
-		if (t != null) {
-			System.out.println(t.getMessage());
-			System.out.println();
-		}
-
-		if (parser != null) {
-			parser.printUsage(System.out);
-		}
-		System.exit(0);
-	}
-
-	/**
-	 * Parameters class for FederationClient.
-	 */
-	private static class Params {
-
-		@Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE")
-		public String registrationsFile = "${baseFolder}/federation.properties";
-
-		@Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL")
-		public String url;
-
-		@Option(name = "--mirror", usage = "Mirror repositories")
-		public boolean mirror;
-
-		@Option(name = "--bare", usage = "Create bare repositories")
-		public boolean bare;
-
-		@Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN")
-		public String token;
-
-		@Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH")
-		public String baseFolder;
-
-		@Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH")
-		public String repositoriesFolder;
-
-	}
-
-	private static class NoopNotificationManager implements INotificationManager {
-
-		@Override
-		public NoopNotificationManager start() {
-			return this;
-		}
-
-		@Override
-		public NoopNotificationManager stop() {
-			return this;
-		}
-
-		@Override
-		public boolean isSendingMail() {
-			return false;
-		}
-
-		@Override
-		public void sendMailToAdministrators(String subject, String message) {
-		}
-
-		@Override
-		public void sendMail(String subject, String message, Collection<String> toAddresses) {
-		}
-
-		@Override
-		public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
-		}
-
-		@Override
-		public void send(Mailing mailing) {
-		}
-	}
-}
+/*
+ * Copyright 2011 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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+
+import com.gitblit.manager.FederationManager;
+import com.gitblit.manager.GitblitManager;
+import com.gitblit.manager.IGitblit;
+import com.gitblit.manager.INotificationManager;
+import com.gitblit.manager.RepositoryManager;
+import com.gitblit.manager.RuntimeManager;
+import com.gitblit.manager.UserManager;
+import com.gitblit.models.FederationModel;
+import com.gitblit.models.Mailing;
+import com.gitblit.service.FederationPullService;
+import com.gitblit.utils.FederationUtils;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Command-line client to pull federated Gitblit repositories.
+ *
+ * @author James Moger
+ *
+ */
+public class FederationClient {
+
+	public static void main(String[] args) {
+		Params params = new Params();
+		CmdLineParser parser = new CmdLineParser(params);
+		try {
+			parser.parseArgument(args);
+		} catch (CmdLineException t) {
+			usage(parser, t);
+		}
+
+		System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")");
+
+		// command-line specified base folder
+		File baseFolder = new File(System.getProperty("user.dir"));
+		if (!StringUtils.isEmpty(params.baseFolder)) {
+			baseFolder = new File(params.baseFolder);
+		}
+
+		File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile);
+		FileSettings settings = new FileSettings(regFile.getAbsolutePath());
+		List<FederationModel> registrations = new ArrayList<FederationModel>();
+		if (StringUtils.isEmpty(params.url)) {
+			registrations.addAll(FederationUtils.getFederationRegistrations(settings));
+		} else {
+			if (StringUtils.isEmpty(params.token)) {
+				System.out.println("Must specify --token parameter!");
+				System.exit(0);
+			}
+			FederationModel model = new FederationModel("Gitblit");
+			model.url = params.url;
+			model.token = params.token;
+			model.mirror = params.mirror;
+			model.bare = params.bare;
+			model.folder = "";
+			registrations.add(model);
+		}
+		if (registrations.size() == 0) {
+			System.out.println("No Federation Registrations!  Nothing to do.");
+			System.exit(0);
+		}
+
+		// command-line specified repositories folder
+		if (!StringUtils.isEmpty(params.repositoriesFolder)) {
+			settings.overrideSetting(Keys.git.repositoriesFolder, new File(
+					params.repositoriesFolder).getAbsolutePath());
+		}
+
+		// configure the Gitblit singleton for minimal, non-server operation
+		RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start();
+		NoopNotificationManager notifications = new NoopNotificationManager().start();
+		UserManager users = new UserManager(runtime, null).start();
+		RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
+		FederationManager federation = new FederationManager(runtime, notifications, repositories).start();
+		IGitblit gitblit = new GitblitManager(null, runtime, null, notifications, users, null, repositories, null, federation);
+
+		FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) {
+			@Override
+			public void reschedule(FederationModel registration) {
+				// NOOP
+			}
+		};
+		puller.run();
+
+		System.out.println("Finished.");
+		System.exit(0);
+	}
+
+	private static void usage(CmdLineParser parser, CmdLineException t) {
+		System.out.println(Constants.getGitBlitVersion());
+		System.out.println();
+		if (t != null) {
+			System.out.println(t.getMessage());
+			System.out.println();
+		}
+
+		if (parser != null) {
+			parser.printUsage(System.out);
+		}
+		System.exit(0);
+	}
+
+	/**
+	 * Parameters class for FederationClient.
+	 */
+	private static class Params {
+
+		@Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE")
+		public String registrationsFile = "${baseFolder}/federation.properties";
+
+		@Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL")
+		public String url;
+
+		@Option(name = "--mirror", usage = "Mirror repositories")
+		public boolean mirror;
+
+		@Option(name = "--bare", usage = "Create bare repositories")
+		public boolean bare;
+
+		@Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN")
+		public String token;
+
+		@Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH")
+		public String baseFolder;
+
+		@Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH")
+		public String repositoriesFolder;
+
+	}
+
+	private static class NoopNotificationManager implements INotificationManager {
+
+		@Override
+		public NoopNotificationManager start() {
+			return this;
+		}
+
+		@Override
+		public NoopNotificationManager stop() {
+			return this;
+		}
+
+		@Override
+		public boolean isSendingMail() {
+			return false;
+		}
+
+		@Override
+		public void sendMailToAdministrators(String subject, String message) {
+		}
+
+		@Override
+		public void sendMail(String subject, String message, Collection<String> toAddresses) {
+		}
+
+		@Override
+		public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
+		}
+
+		@Override
+		public void send(Mailing mailing) {
+		}
+	}
+}
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index 7b9b904..9a01d3c 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -44,6 +44,7 @@
 import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 /**
@@ -62,22 +63,23 @@
 
 	@Inject
 	public GitBlit(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager) {
 
-		super(runtimeManager,
+		super(
+				publicKeyManagerProvider,
+				runtimeManager,
 				pluginManager,
 				notificationManager,
 				userManager,
 				authenticationManager,
-				publicKeyManager,
 				repositoryManager,
 				projectManager,
 				federationManager);
@@ -120,24 +122,6 @@
 		if (isRename && ticketService != null) {
 			ticketService.rename(oldModel, repository);
 		}
-	}
-
-	/**
-	 * Delete the user and all associated public ssh keys.
-	 */
-	@Override
-	public boolean deleteUser(String username) {
-		UserModel user = userManager.getUserModel(username);
-		return deleteUserModel(user);
-	}
-
-	@Override
-	public boolean deleteUserModel(UserModel model) {
-		boolean success = userManager.deleteUserModel(model);
-		if (success) {
-			getPublicKeyManager().removeAllKeys(model.username);
-		}
-		return success;
 	}
 
 	/**
diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java
index cc73f09..6dbe615 100644
--- a/src/main/java/com/gitblit/guice/CoreModule.java
+++ b/src/main/java/com/gitblit/guice/CoreModule.java
@@ -18,7 +18,6 @@
 import com.gitblit.FileSettings;
 import com.gitblit.GitBlit;
 import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
 import com.gitblit.manager.AuthenticationManager;
 import com.gitblit.manager.FederationManager;
 import com.gitblit.manager.IAuthenticationManager;
@@ -38,14 +37,9 @@
 import com.gitblit.manager.RuntimeManager;
 import com.gitblit.manager.ServicesManager;
 import com.gitblit.manager.UserManager;
-import com.gitblit.transport.ssh.FileKeyManager;
 import com.gitblit.transport.ssh.IPublicKeyManager;
-import com.gitblit.transport.ssh.MemoryKeyManager;
-import com.gitblit.transport.ssh.NullKeyManager;
-import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.WorkQueue;
 import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
 
 /**
  * CoreModule references all the core business objects.
@@ -61,8 +55,9 @@
 		bind(IStoredSettings.class).toInstance(new FileSettings());
 
 		// bind complex providers
+		bind(IPublicKeyManager.class).toProvider(IPublicKeyManagerProvider.class);
 		bind(WorkQueue.class).toProvider(WorkQueueProvider.class);
-		
+
 		// core managers
 		bind(IRuntimeManager.class).to(RuntimeManager.class);
 		bind(IPluginManager.class).to(PluginManager.class);
@@ -78,30 +73,5 @@
 
 		// manager for long-running daemons and services
 		bind(IServicesManager.class).to(ServicesManager.class);
-	}
-
-	@Provides
-	@Singleton
-	IPublicKeyManager providePublicKeyManager(IStoredSettings settings, IRuntimeManager runtimeManager) {
-
-		String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
-		if (StringUtils.isEmpty(clazz)) {
-			clazz = FileKeyManager.class.getName();
-		}
-		if (FileKeyManager.class.getName().equals(clazz)) {
-			return new FileKeyManager(runtimeManager);
-		} else if (NullKeyManager.class.getName().equals(clazz)) {
-			return new NullKeyManager();
-		} else if (MemoryKeyManager.class.getName().equals(clazz)) {
-			return new MemoryKeyManager();
-		} else {
-			try {
-				Class<?> mgrClass = Class.forName(clazz);
-				return (IPublicKeyManager) mgrClass.newInstance();
-			} catch (Exception e) {
-
-			}
-			return null;
-		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
new file mode 100644
index 0000000..8075aa9
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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.guice;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.transport.ssh.FileKeyManager;
+import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.transport.ssh.NullKeyManager;
+import com.gitblit.utils.StringUtils;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Provides a lazily-instantiated IPublicKeyManager configured from IStoredSettings.
+ *
+ * @author James Moger
+ *
+ */
+@Singleton
+public class IPublicKeyManagerProvider implements Provider<IPublicKeyManager> {
+
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+
+	private final IRuntimeManager runtimeManager;
+
+	private volatile IPublicKeyManager manager;
+
+	@Inject
+	public IPublicKeyManagerProvider(IRuntimeManager runtimeManager) {
+		this.runtimeManager = runtimeManager;
+	}
+
+	@Override
+	public synchronized IPublicKeyManager get() {
+		if (manager != null) {
+			return manager;
+		}
+
+		IStoredSettings settings = runtimeManager.getSettings();
+		String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
+		if (StringUtils.isEmpty(clazz)) {
+			clazz = FileKeyManager.class.getName();
+		}
+		try {
+			Class<? extends IPublicKeyManager> mgrClass = (Class<? extends IPublicKeyManager>) Class.forName(clazz);
+			manager = runtimeManager.getInjector().getInstance(mgrClass);
+		} catch (Exception e) {
+			logger.error("failed to create public key manager", e);
+			manager = new NullKeyManager();
+		}
+		return manager;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 5c2eccf..fbbafac 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -86,6 +86,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Singleton;
+import com.google.inject.Provider;
 
 /**
  * GitblitManager is an aggregate interface delegate.  It implements all the manager
@@ -106,6 +107,8 @@
 
 	protected final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>();
 
+	protected final Provider<IPublicKeyManager> publicKeyManagerProvider;
+
 	protected final IStoredSettings settings;
 
 	protected final IRuntimeManager runtimeManager;
@@ -118,8 +121,6 @@
 
 	protected final IAuthenticationManager authenticationManager;
 
-	protected final IPublicKeyManager publicKeyManager;
-
 	protected final IRepositoryManager repositoryManager;
 
 	protected final IProjectManager projectManager;
@@ -128,15 +129,17 @@
 
 	@Inject
 	public GitblitManager(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager) {
+
+		this.publicKeyManagerProvider = publicKeyManagerProvider;
 
 		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
@@ -144,7 +147,6 @@
 		this.notificationManager = notificationManager;
 		this.userManager = userManager;
 		this.authenticationManager = authenticationManager;
-		this.publicKeyManager = publicKeyManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
 		this.federationManager = federationManager;
@@ -487,7 +489,7 @@
 
 	@Override
 	public IPublicKeyManager getPublicKeyManager() {
-		return publicKeyManager;
+		return publicKeyManagerProvider.get();
 	}
 
 	/*
@@ -707,11 +709,6 @@
 	}
 
 	@Override
-	public boolean deleteUser(String username) {
-		return userManager.deleteUser(username);
-	}
-
-	@Override
 	public UserModel getUserModel(String username) {
 		return userManager.getUserModel(username);
 	}
@@ -752,8 +749,22 @@
 	}
 
 	@Override
+	public boolean deleteUser(String username) {
+		// delegate to deleteUserModel() to delete public ssh keys
+		UserModel user = userManager.getUserModel(username);
+		return deleteUserModel(user);
+	}
+
+	/**
+	 * Delete the user and all associated public ssh keys.
+	 */
+	@Override
 	public boolean deleteUserModel(UserModel model) {
-		return userManager.deleteUserModel(model);
+		boolean success = userManager.deleteUserModel(model);
+		if (success) {
+			getPublicKeyManager().removeAllKeys(model.username);
+		}
+		return success;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
index a063dc7..1a2cd68 100644
--- a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
@@ -29,6 +29,7 @@
 import com.google.common.base.Charsets;
 import com.google.common.base.Joiner;
 import com.google.common.io.Files;
+import com.google.inject.Inject;
 
 /**
  * Manages public keys on the filesystem.
@@ -42,6 +43,7 @@
 
 	protected final Map<File, Long> lastModifieds;
 
+	@Inject
 	public FileKeyManager(IRuntimeManager runtimeManager) {
 		this.runtimeManager = runtimeManager;
 		this.lastModifieds = new ConcurrentHashMap<File, Long>();
diff --git a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
index 357b34a..bf78378 100644
--- a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
@@ -20,6 +20,8 @@
 import java.util.List;
 import java.util.Map;
 
+import com.google.inject.Inject;
+
 /**
  * Memory public key manager.
  *
@@ -30,6 +32,7 @@
 
 	final Map<String, List<SshKey>> keys;
 
+	@Inject
 	public MemoryKeyManager() {
 		keys = new HashMap<String, List<SshKey>>();
 	}
diff --git a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
index 0761d84..fcd3e19 100644
--- a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
@@ -17,6 +17,8 @@
 
 import java.util.List;
 
+import com.google.inject.Inject;
+
 /**
  * Rejects all public key management requests.
  *
@@ -25,6 +27,7 @@
  */
 public class NullKeyManager extends IPublicKeyManager {
 
+	@Inject
 	public NullKeyManager() {
 	}
 
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index 24468c0..e09799d 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -91,6 +91,7 @@
 import com.gitblit.wicket.pages.UserPage;
 import com.gitblit.wicket.pages.UsersPage;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 @Singleton
@@ -101,6 +102,8 @@
 	private final Class<? extends WebPage> newRepositoryPageClass = NewRepositoryPage.class;
 
 	private final Map<String, CacheControl> cacheablePages = new HashMap<String, CacheControl>();
+
+	private final Provider<IPublicKeyManager> publicKeyManagerProvider;
 
 	private final IStoredSettings settings;
 
@@ -114,8 +117,6 @@
 
 	private final IAuthenticationManager authenticationManager;
 
-	private final IPublicKeyManager publicKeyManager;
-
 	private final IRepositoryManager repositoryManager;
 
 	private final IProjectManager projectManager;
@@ -128,12 +129,12 @@
 
 	@Inject
 	public GitBlitWebApp(
+			Provider<IPublicKeyManager> publicKeyManagerProvider,
 			IRuntimeManager runtimeManager,
 			IPluginManager pluginManager,
 			INotificationManager notificationManager,
 			IUserManager userManager,
 			IAuthenticationManager authenticationManager,
-			IPublicKeyManager publicKeyManager,
 			IRepositoryManager repositoryManager,
 			IProjectManager projectManager,
 			IFederationManager federationManager,
@@ -141,13 +142,13 @@
 			IServicesManager services) {
 
 		super();
+		this.publicKeyManagerProvider = publicKeyManagerProvider;
 		this.settings = runtimeManager.getSettings();
 		this.runtimeManager = runtimeManager;
 		this.pluginManager = pluginManager;
 		this.notificationManager = notificationManager;
 		this.userManager = userManager;
 		this.authenticationManager = authenticationManager;
-		this.publicKeyManager = publicKeyManager;
 		this.repositoryManager = repositoryManager;
 		this.projectManager = projectManager;
 		this.federationManager = federationManager;
@@ -389,7 +390,7 @@
 	 */
 	@Override
 	public IPublicKeyManager keys() {
-		return publicKeyManager;
+		return publicKeyManagerProvider.get();
 	}
 
 	/* (non-Javadoc)

--
Gitblit v1.9.1