Merge branch 'stable-2.11'

* stable-2.11:
  Add documentation for SecureStore
  Add SwitchSecureStore site program
  Make SecureStore an abstract class
  Add API to make SecureStore switching possible

Change-Id: I60f6e58f590a94004329bf663506923a95c3a500
This commit is contained in:
David Pursehouse
2015-02-24 14:54:20 +09:00
10 changed files with 447 additions and 53 deletions

View File

@@ -43,7 +43,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
@@ -134,11 +134,14 @@ public class JarScanner implements PluginContentScanner {
return result.build();
}
public List<String> findImplementationsOf(Class<?> requestedInterface)
throws IOException {
List<String> result = Lists.newArrayList();
String name = requestedInterface.getName().replace('.', '/');
public List<String> findSubClassesOf(Class<?> superClass) throws IOException {
return findSubClassesOf(superClass.getName());
}
private List<String> findSubClassesOf(String superClass) throws IOException {
String name = superClass.replace('.', '/');
List<String> classes = new ArrayList<>();
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
JarEntry entry = e.nextElement();
@@ -155,13 +158,15 @@ public class JarScanner implements PluginContentScanner {
continue;
}
if (def.isConcrete() && def.interfaces != null
&& Iterables.contains(Arrays.asList(def.interfaces), name)) {
result.add(def.className);
if (name.equals(def.superName)) {
classes.addAll(findSubClassesOf(def.className));
if (def.isConcrete()) {
classes.add(def.className);
}
}
}
return result;
return classes;
}
private static boolean skip(JarEntry entry) {
@@ -192,6 +197,7 @@ public class JarScanner implements PluginContentScanner {
public static class ClassData extends ClassVisitor {
int access;
String className;
String superName;
String annotationName;
String annotationValue;
String[] interfaces;
@@ -212,7 +218,7 @@ public class JarScanner implements PluginContentScanner {
String superName, String[] interfaces) {
this.className = Type.getObjectType(name).getClassName();
this.access = access;
this.interfaces = interfaces;
this.superName = superName;
}
@Override

View File

@@ -26,10 +26,11 @@ import org.eclipse.jgit.util.FS;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class DefaultSecureStore implements SecureStore {
public class DefaultSecureStore extends SecureStore {
private final FileBasedConfig sec;
@Inject
@@ -43,26 +44,11 @@ public class DefaultSecureStore implements SecureStore {
}
}
@Override
public String get(String section, String subsection, String name) {
return sec.getString(section, subsection, name);
}
@Override
public String[] getList(String section, String subsection, String name) {
return sec.getStringList(section, subsection, name);
}
@Override
public void set(String section, String subsection, String name, String value) {
if (value != null) {
sec.setString(section, subsection, name, value);
} else {
sec.unset(section, subsection, name);
}
save();
}
@Override
public void setList(String section, String subsection, String name,
List<String> values) {
@@ -80,6 +66,22 @@ public class DefaultSecureStore implements SecureStore {
save();
}
@Override
public Iterable<EntryKey> list() {
List<EntryKey> result = new ArrayList<>();
for (String section : sec.getSections()) {
for (String subsection : sec.getSubsections(section)) {
for (String name : sec.getNames(section, subsection)) {
result.add(new EntryKey(section, subsection, name));
}
}
for (String name : sec.getNames(section)) {
result.add(new EntryKey(section, null, name));
}
}
return result;
}
private void save() {
try {
saveSecure(sec);

View File

@@ -14,17 +14,115 @@
package com.google.gerrit.server.securestore;
import com.google.common.collect.Lists;
import java.util.List;
public interface SecureStore {
/**
* Abstract class for providing new SecureStore implementation for Gerrit.
*
* SecureStore is responsible for storing sensitive data like passwords in a
* secure manner.
*
* It is implementator's responsibility to encrypt and store values.
*
* To deploy new SecureStore one needs to provide a jar file with explicitly one
* class that extends {@code SecureStore} and put it in Gerrit server. Then run:
*
* `java -jar gerrit.war SwitchSecureStore -d $gerrit_site --new-secure-store-lib
* $path_to_new_secure_store.jar`
*
* on stopped Gerrit instance.
*/
public abstract class SecureStore {
/**
* Describes {@link SecureStore} entry
*/
public static class EntryKey {
public final String name;
public final String section;
public final String subsection;
String get(String section, String subsection, String name);
/**
* Creates EntryKey.
*
* @param section
* @param subsection
* @param name
*/
public EntryKey(String section, String subsection, String name) {
this.name = name;
this.section = section;
this.subsection = subsection;
}
}
String[] getList(String section, String subsection, String name);
/**
* Extract decrypted value of stored property from SecureStore or {@code null}
* when property was not found.
*
* @param section
* @param subsection
* @param name
* @return decrypted String value or {@code null} if not found
*/
public final String get(String section, String subsection, String name) {
String[] values = getList(section, subsection, name);
if (values != null && values.length > 0) {
return values[0];
}
return null;
}
void set(String section, String subsection, String name, String value);
/**
* Extract list of values from SecureStore and decrypt every value in that
* list or {@code null} when property was not found.
*
* @param section
* @param subsection
* @param name
* @return decrypted list of string values or {@code null}
*/
public abstract String[] getList(String section, String subsection, String name);
void setList(String section, String subsection, String name, List<String> values);
/**
* Store single value in SecureStore.
*
* This method is responsible for encrypting value and storing it.
*
* @param section
* @param subsection
* @param name
* @param value plain text value
*/
public final void set(String section, String subsection, String name, String value) {
setList(section, subsection, name, Lists.newArrayList(value));
}
void unset(String section, String subsection, String name);
/**
* Store list of values in SecureStore.
*
* This method is responsible for encrypting all values in the list and storing them.
*
* @param section
* @param subsection
* @param name
* @param values list of plain text values
*/
public abstract void setList(String section, String subsection, String name, List<String> values);
/**
* Remove value for given {@code section}, {@code subsection} and {@code name}
* from SecureStore.
*
* @param section
* @param subsection
* @param name
*/
public abstract void unset(String section, String subsection, String name);
/**
* @return list of stored entries.
*/
public abstract Iterable<EntryKey> list();
}