// Copyright (C) 2009 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.google.gerrit.sshd; import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME; import com.google.gerrit.common.errors.InvalidSshKeyException; import com.google.gerrit.reviewdb.AccountExternalId; import com.google.gerrit.reviewdb.AccountSshKey; import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.server.cache.Cache; import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.EntryCreator; import com.google.gerrit.server.ssh.SshKeyCache; import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.SchemaFactory; import com.google.inject.Inject; import com.google.inject.Module; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** Provides the {@link SshKeyCacheEntry}. */ @Singleton public class SshKeyCacheImpl implements SshKeyCache { private static final Logger log = LoggerFactory.getLogger(SshKeyCacheImpl.class); private static final String CACHE_NAME = "sshkeys"; static final Iterable<SshKeyCacheEntry> NO_SUCH_USER = none(); static final Iterable<SshKeyCacheEntry> NO_KEYS = none(); public static Module module() { return new CacheModule() { @Override protected void configure() { final TypeLiteral<Cache<String, Iterable<SshKeyCacheEntry>>> type = new TypeLiteral<Cache<String, Iterable<SshKeyCacheEntry>>>() {}; core(type, CACHE_NAME).populateWith(Loader.class); bind(SshKeyCacheImpl.class); bind(SshKeyCache.class).to(SshKeyCacheImpl.class); } }; } private static Iterable<SshKeyCacheEntry> none() { return Collections.unmodifiableCollection(Arrays .asList(new SshKeyCacheEntry[0])); } private final Cache<String, Iterable<SshKeyCacheEntry>> cache; @Inject SshKeyCacheImpl( @Named(CACHE_NAME) final Cache<String, Iterable<SshKeyCacheEntry>> cache) { this.cache = cache; } public Iterable<SshKeyCacheEntry> get(String username) { return cache.get(username); } public void evict(String username) { cache.remove(username); } @Override public AccountSshKey create(AccountSshKey.Id id, String encoded) throws InvalidSshKeyException { try { final AccountSshKey key = new AccountSshKey(id, SshUtil.toOpenSshPublicKey(encoded)); SshUtil.parse(key); return key; } catch (NoSuchAlgorithmException e) { throw new InvalidSshKeyException(); } catch (InvalidKeySpecException e) { throw new InvalidSshKeyException(); } catch (NoSuchProviderException e) { log.error("Cannot parse SSH key", e); throw new InvalidSshKeyException(); } } static class Loader extends EntryCreator<String, Iterable<SshKeyCacheEntry>> { @Override public Iterable<SshKeyCacheEntry> createEntry(String username) throws Exception { return NO_KEYS; } @Override public Iterable<SshKeyCacheEntry> missing(String username) { return Collections.emptyList(); } private void add(ReviewDb db, List<SshKeyCacheEntry> kl, AccountSshKey k) { try { kl.add(new SshKeyCacheEntry(k.getKey(), SshUtil.parse(k))); } catch (OutOfMemoryError e) { // This is the only case where we assume the problem has nothing // to do with the key object, and instead we must abort this load. // throw e; } catch (Throwable e) { //markInvalid(db, k); } } } }