| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | |
| | | 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()); |
| | | } |
| | | |
| | | 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()); |
| | | if (list.isEmpty()) { |
| | | return null; |
| | | } |
| | | return list; |
| | | } |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("Canot read public key", e); |
| | | } |
| | | return null; |
| | | } |
| | | }); |
| | | |
| | |
| | | final ServerSession session) { |
| | | final SshSession sd = session.getAttribute(SshSession.KEY); |
| | | |
| | | // 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) { |
| | | List<PublicKey> keys = sshKeyCache.get(username); |
| | | if (keys == null || keys.isEmpty()) { |
| | | sd.authenticationError(username, "no-matching-key"); |
| | | return false; |
| | | } |
| | | |
| | | if (key.match(suppliedKey)) { |
| | | return success(username, session, sd); |
| | | for (PublicKey key : keys) { |
| | | if (key.equals(suppliedKey)) { |
| | | return validate(username, sd); |
| | | } |
| | | } |
| | | return false; |
| | | } catch (ExecutionException e) { |
| | |
| | | } |
| | | } |
| | | |
| | | boolean success(String username, ServerSession session, SshSession sd) { |
| | | 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); |
| | | /* |
| | | * 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); } } }); } |
| | | */ |
| | | UserModel user = gitblit.authenticate(sd); |
| | | if (user != null) { |
| | | return true; |
| | | } |
| | | |
| | | private static class SshKeyCacheWeigher implements |
| | | Weigher<String, SshKeyCacheEntry> { |
| | | @Override |
| | | public int weigh(String key, SshKeyCacheEntry value) { |
| | | return key.length() + value.weigh(); |
| | | } |
| | | sd.authenticationError(username, "user-not-found"); |
| | | return false; |
| | | } |
| | | } |