diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt index c26d4f20a0..cecb258202 100644 --- a/Documentation/dev-plugins.txt +++ b/Documentation/dev-plugins.txt @@ -1731,6 +1731,34 @@ MyType(@PluginData java.io.File myDir) { } ---- +[[secure-store]] +== SecureStore + +SecureStore allows to change the way Gerrit stores sensitive data like +passwords. + +In order to replace the default SecureStore (no-op) implementation, +a class that extends `com.google.gerrit.server.securestore.SecureStore` +needs to be provided (with dependencies) in a separate jar file. Then +link:pgm-SwitchSecureStore.html[SwitchSecureStore] must be run to +switch implementations. + +The SecureStore implementation is instantiated using a Guice injector +which binds the `File` annotated with the `@SitePath` annotation. +This means that a SecureStore implementation class can get access to +the `site_path` like in the following example: + +[source,java] +---- +@Inject +MySecureStore(@SitePath java.io.File sitePath) { + // your code +} +---- + +No Guice bindings or modules are required. Gerrit will automatically +discover and bind the implementation. + [[download-commands]] == Download Commands diff --git a/Documentation/pgm-SwitchSecureStore.txt b/Documentation/pgm-SwitchSecureStore.txt new file mode 100644 index 0000000000..f9b2aa4dfb --- /dev/null +++ b/Documentation/pgm-SwitchSecureStore.txt @@ -0,0 +1,39 @@ += SwitchSecureStore + +== NAME +SwitchSecureStore - Changes the currently used SecureStore implementation + +== SYNOPSIS +-- +'java' -jar gerrit.war 'SwitchSecureStore' [] +-- + +== DESCRIPTION +Changes the SecureStore implementation used by Gerrit. It migrates all data +stored in the old implementation, removes the old implementation jar file +from `$site_path/lib` and puts the new one there. As a final step +the link:config-gerrit.html#gerrit.secureStoreClass[gerrit.secureStoreClass] +property of `gerrit.config` will be updated. + +All dependencies not provided by Gerrit should be put the in `$site_path/lib` +directory manually, before running the `SwitchSecureStore` program. + +After this operation there is no automatic way back the to standard Gerrit no-op +secure store implementation, however there is a manual procedure: +* stop Gerrit, +* remove SecureStore jar file from `$site_path/lib`, +* put plain text passwords into `$site_path/etc/secure.conf` file, +* start Gerrit. + +== OPTIONS + +--new-secure-store-lib:: + Path to jar file with new SecureStore implementation. Jar dependencies must be + put in `$site_path/lib` directory. + +GERRIT +------ +Part of link:index.html[Gerrit Code Review] + +SEARCHBOX +--------- diff --git a/Documentation/pgm-index.txt b/Documentation/pgm-index.txt index 3bb618232d..bf6dc572d5 100644 --- a/Documentation/pgm-index.txt +++ b/Documentation/pgm-index.txt @@ -24,6 +24,9 @@ link:pgm-prolog-shell.html[prolog-shell]:: link:pgm-reindex.html[reindex]:: Rebuild the secondary index. +link:pgm-SwitchSecureStore.html[SwitchSecureStore]:: + Change used SecureStore implementation. + link:pgm-rulec.html[rulec]:: Compile project-specific Prolog rules to JARs. diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStore.java index f3eeaf6f50..2a0086ec87 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStore.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStore.java @@ -18,12 +18,38 @@ import com.google.common.collect.Lists; import java.util.List; +/** + * 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; + /** + * Creates EntryKey. + * + * @param section + * @param subsection + * @param name + */ public EntryKey(String section, String subsection, String name) { this.name = name; this.section = section; @@ -31,6 +57,15 @@ public abstract class SecureStore { } } + /** + * 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) { @@ -39,15 +74,55 @@ public abstract class SecureStore { return null; } + /** + * 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); + /** + * 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)); } + /** + * 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 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 list(); }