| | |
| | | /* |
| | | * 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 |
| | | * 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 |
| | | * 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. |
| | | * 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; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.security.PublicKey; |
| | | import java.util.Locale; |
| | | import java.util.concurrent.ExecutionException; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.sshd.common.util.Buffer; |
| | | import org.apache.sshd.server.PublickeyAuthenticator; |
| | | import org.apache.sshd.server.session.ServerSession; |
| | | import org.eclipse.jgit.lib.Constants; |
| | | |
| | | import com.gitblit.manager.IGitblit; |
| | | 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; |
| | | |
| | | /** |
| | | * |
| | |
| | | */ |
| | | public class SshKeyAuthenticator implements PublickeyAuthenticator { |
| | | |
| | | protected final IGitblit gitblit; |
| | | protected final IGitblit gitblit; |
| | | |
| | | public SshKeyAuthenticator(IGitblit gitblit) { |
| | | this.gitblit = 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); |
| | | } |
| | | |
| | | @Override |
| | | public boolean authenticate(String username, PublicKey key, ServerSession session) { |
| | | // TODO actually authenticate |
| | | return true; |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | @Override |
| | | public boolean authenticate(String username, final PublicKey suppliedKey, |
| | | 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) { |
| | | 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(); |
| | | } |
| | | } |
| | | } |