diff options
author | James Moger <james.moger@gitblit.com> | 2014-03-08 19:43:15 -0500 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2014-04-10 18:58:08 -0400 |
commit | 860d2ca577520850a705298a2b19a0de0459b82e (patch) | |
tree | 59c3dc48938c0c30e4e66b979007452c71c05d49 /src | |
parent | 4ccdfe90b73c140b330b9f7838d6cb580c98229a (diff) | |
download | gitblit-860d2ca577520850a705298a2b19a0de0459b82e.tar.gz gitblit-860d2ca577520850a705298a2b19a0de0459b82e.zip |
Establish ssh keys folder, support multiple keys, revise key authenticator
Diffstat (limited to 'src')
4 files changed, 82 insertions, 103 deletions
diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 5bc28fd6..fbde84a7 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -110,6 +110,11 @@ git.sshPort = 29418 # RESTART REQUIRED
git.sshBindInterface = localhost
+# Directory for storing user SSH keys.
+#
+# SINCE 1.5.0
+git.sshKeysFolder= ${baseFolder}/ssh
+
# Allow push/pull over http/https with JGit servlet.
# If you do NOT want to allow Git clients to clone/push to Gitblit set this
# to false. You might want to do this if you are only using ssh:// or git://.
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java index 47425ce7..658c2890 100644 --- a/src/main/java/com/gitblit/manager/AuthenticationManager.java +++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java @@ -304,7 +304,7 @@ public class AuthenticationManager implements IAuthenticationManager { UserModel user = userManager.getUserModel(username); if (user != null) { // existing user - logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}", + logger.debug(MessageFormat.format("{0} authenticated by SSH key from {1}", user.username, sshSession.getRemoteAddress())); return validateAuthentication(user, AuthenticationType.SSH); } diff --git a/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java index 4ab20f33..4cda268e 100644 --- a/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java +++ b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java @@ -18,8 +18,11 @@ package com.gitblit.transport.ssh; import java.io.File; import java.io.IOException; import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.apache.commons.codec.binary.Base64; import org.apache.sshd.common.util.Buffer; @@ -27,12 +30,13 @@ import org.apache.sshd.server.PublickeyAuthenticator; import org.apache.sshd.server.session.ServerSession; import org.eclipse.jgit.lib.Constants; +import com.gitblit.Keys; import com.gitblit.manager.IGitblit; +import com.gitblit.models.UserModel; import com.google.common.base.Charsets; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.google.common.cache.Weigher; import com.google.common.io.Files; /** @@ -42,84 +46,80 @@ import com.google.common.io.Files; */ public class SshKeyAuthenticator implements PublickeyAuthenticator { - protected final IGitblit gitblit; + protected final IGitblit gitblit; - LoadingCache<String, SshKeyCacheEntry> sshKeyCache = CacheBuilder - .newBuilder().maximumWeight(2 << 20).weigher(new SshKeyCacheWeigher()) - .build(new CacheLoader<String, SshKeyCacheEntry>() { - public SshKeyCacheEntry load(String key) throws Exception { - return loadKey(key); - } + LoadingCache<String, List<PublicKey>> sshKeyCache = CacheBuilder + .newBuilder(). + expireAfterAccess(15, TimeUnit.MINUTES). + maximumSize(100) + .build(new CacheLoader<String, List<PublicKey>>() { + public List<PublicKey> load(String username) { + try { + File dir = gitblit.getFileOrFolder(Keys.git.sshKeysFolder, "${baseFolder}/ssh"); + dir.mkdirs(); + File keys = new File(dir, username + ".keys"); + if (!keys.exists()) { + return null; + } + if (keys.exists()) { + String str = Files.toString(keys, Charsets.ISO_8859_1); + String [] entries = str.split("\n"); + List<PublicKey> list = new ArrayList<PublicKey>(); + for (String entry : entries) { + final String[] parts = entry.split(" "); + final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1])); + list.add(new Buffer(bin).getRawPublicKey()); + } + + if (list.isEmpty()) { + return null; + } + return list; + } + } catch (IOException e) { + throw new RuntimeException("Canot read public key", e); + } + return null; + } + }); - private SshKeyCacheEntry loadKey(String key) { - try { - // TODO(davido): retrieve absolute path to public key directory: - //String dir = gitblit.getSettings().getString("public_key_dir", "data/ssh"); - String dir = "/tmp/"; - // Expect public key file name in form: <username.pub> in - File file = new File(dir + key + ".pub"); - String str = Files.toString(file, Charsets.ISO_8859_1); - final String[] parts = str.split(" "); - final byte[] bin = - Base64.decodeBase64(Constants.encodeASCII(parts[1])); - return new SshKeyCacheEntry(key, new Buffer(bin).getRawPublicKey()); - } catch (IOException e) { - throw new RuntimeException("Canot read public key", e); - } - } - }); + public SshKeyAuthenticator(IGitblit gitblit) { + this.gitblit = gitblit; + } - public SshKeyAuthenticator(IGitblit gitblit) { - this.gitblit = gitblit; - } + @Override + public boolean authenticate(String username, final PublicKey suppliedKey, + final ServerSession session) { + final SshSession sd = session.getAttribute(SshSession.KEY); - @Override - public boolean authenticate(String username, final PublicKey suppliedKey, - final ServerSession session) { - final SshSession sd = session.getAttribute(SshSession.KEY); + username = username.toLowerCase(Locale.US); + try { + List<PublicKey> keys = sshKeyCache.get(username); + if (keys == null || keys.isEmpty()) { + sd.authenticationError(username, "no-matching-key"); + return false; + } + for (PublicKey key : keys) { + if (key.equals(suppliedKey)) { + return validate(username, sd); + } + } + return false; + } catch (ExecutionException e) { + sd.authenticationError(username, "user-not-found"); + return false; + } + } - // if (config.getBoolean("auth", "userNameToLowerCase", false)) { - username = username.toLowerCase(Locale.US); - // } - try { - // TODO: allow multiple public keys per user - SshKeyCacheEntry key = sshKeyCache.get(username); - if (key == null) { - sd.authenticationError(username, "no-matching-key"); - return false; - } - - if (key.match(suppliedKey)) { - return success(username, session, sd); - } - return false; - } catch (ExecutionException e) { - sd.authenticationError(username, "user-not-found"); - return false; - } - } - - boolean success(String username, ServerSession session, SshSession sd) { - sd.authenticationSuccess(username); - /* - * sshLog.onLogin(); - * - * GerritServerSession s = (GerritServerSession) session; - * s.addCloseSessionListener( new SshFutureListener<CloseFuture>() { - * - * @Override public void operationComplete(CloseFuture future) { final - * Context ctx = sshScope.newContext(null, sd, null); final Context old = - * sshScope.set(ctx); try { sshLog.onLogout(); } finally { - * sshScope.set(old); } } }); } - */ - return true; - } - - private static class SshKeyCacheWeigher implements - Weigher<String, SshKeyCacheEntry> { - @Override - public int weigh(String key, SshKeyCacheEntry value) { - return key.length() + value.weigh(); - } - } + boolean validate(String username, SshSession sd) { + // now that the key has been validated, check with the authentication + // manager to ensure that this user exists and can authenticate + sd.authenticationSuccess(username); + UserModel user = gitblit.authenticate(sd); + if (user != null) { + return true; + } + sd.authenticationError(username, "user-not-found"); + return false; + } } diff --git a/src/main/java/com/gitblit/transport/ssh/SshKeyCacheEntry.java b/src/main/java/com/gitblit/transport/ssh/SshKeyCacheEntry.java deleted file mode 100644 index ddc48b35..00000000 --- a/src/main/java/com/gitblit/transport/ssh/SshKeyCacheEntry.java +++ /dev/null @@ -1,26 +0,0 @@ - -package com.gitblit.transport.ssh; - -import java.security.PublicKey; - -class SshKeyCacheEntry { - private final String user; - private final PublicKey publicKey; - - SshKeyCacheEntry(String user, PublicKey publicKey) { - this.user = user; - this.publicKey = publicKey; - } - - String getUser() { - return user; - } - - boolean match(PublicKey inkey) { - return publicKey.equals(inkey); - } - - int weigh() { - return publicKey.getEncoded().length; - } -} |