Gerrit command line utility to set/update secure.config
When using a secure store for encrypting the secure.config
values, an utility or tool is needed to edit the values
using the same encryption key used by Gerrit at runtime.
Change-Id: Iacb017b010f7efd8217255796e571c5291499c0e
diff --git a/Documentation/pgm-index.txt b/Documentation/pgm-index.txt
index bf6dc57..0c347f4 100644
--- a/Documentation/pgm-index.txt
+++ b/Documentation/pgm-index.txt
@@ -33,6 +33,9 @@
version::
Display the release version of Gerrit Code Review.
+link:pgm-passwd.html[passwd]::
+ Set or reset password in secure.config.
+
=== Transition Utilities
link:pgm-LocalUsernamesToLowerCase.html[LocalUsernamesToLowerCase]::
diff --git a/Documentation/pgm-passwd.txt b/Documentation/pgm-passwd.txt
new file mode 100644
index 0000000..133fb03
--- /dev/null
+++ b/Documentation/pgm-passwd.txt
@@ -0,0 +1,49 @@
+= passwd
+
+== NAME
+passwd - Set or reset password in secure.config.
+
+== SYNOPSIS
+[verse]
+--
+_java_ -jar gerrit.war _passwd_
+ -d <SITE_PATH>
+ <SECTION.KEY>
+ [PASSWORD]
+
+--
+
+== DESCRIPTION
+Set or reset password in an existing Gerrit server installation,
+interactively prompting for a new password or using the one
+provided in the command line argument.
+
+== OPTIONS
+
+-d::
+--site-path::
+ Location of the `gerrit.config` file, and all other per-site
+ configuration data, supporting libraries and log files.
+
+== ARGUMENTS
+
+SECTION.KEY::
+ Section and key in the `secure.config` file for setting or editing the
+ password value.
+
+PASSWORD::
+ New password to set in `secure.config` associated to the section and key.
+ When specified as argument, automatically implies batch mode and the command
+ would not ask anything interactively.
+
+== CONTEXT
+
+This utility is typically useful when a secure store is configured
+to encrypt password values and thus editing the file manually is not an option.
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
index bef57d0..7954146 100644
--- a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -78,6 +78,8 @@
System.err.println(" daemon Run the Gerrit network daemons");
System.err.println(" gsql Run the interactive query console");
System.err.println(" version Display the build version number");
+ System.err.println(" passwd Set or change password in secure.config");
+
System.err.println();
System.err.println(" ls List files available for cat");
System.err.println(" cat FILE Display a file from the archive");
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Passwd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Passwd.java
new file mode 100644
index 0000000..643323f
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Passwd.java
@@ -0,0 +1,89 @@
+// Copyright (C) 2017 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.pgm;
+
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.InstallAllPlugins;
+import com.google.gerrit.pgm.init.api.InstallPlugins;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.pgm.util.SiteProgram;
+import com.google.gerrit.server.config.GerritServerConfigModule;
+import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.securestore.SecureStoreClassName;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+import com.google.inject.util.Providers;
+
+import org.kohsuke.args4j.Argument;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Passwd extends SiteProgram {
+ private String section;
+ private String key;
+
+ @Argument(metaVar = "SECTION.KEY", index = 0, required = true,
+ usage = "Section and key separated by a dot of the password to set")
+ private String sectionAndKey;
+
+ @Argument(metaVar = "PASSWORD", index = 1, required = false,
+ usage = "Password to set")
+ private String password;
+
+ private void init() {
+ String[] varParts = sectionAndKey.split("\\.");
+ if (varParts.length != 2) {
+ throw new IllegalArgumentException("Invalid name '" + sectionAndKey
+ + "': expected section.key format");
+ }
+ section = varParts[0];
+ key = varParts[1];
+ }
+
+ @Override
+ public int run() throws Exception {
+ init();
+ SetPasswd setPasswd = getSysInjector().getInstance(SetPasswd.class);
+ setPasswd.run(section, key, password);
+ return 0;
+ }
+
+ private Injector getSysInjector() {
+ List<Module> modules = new ArrayList<>();
+ modules.add(new FactoryModule() {
+ @Override
+ protected void configure() {
+ bind(Path.class).annotatedWith(SitePath.class)
+ .toInstance(getSitePath());
+ bind(ConsoleUI.class).toInstance(
+ ConsoleUI.getInstance(password != null));
+ factory(Section.Factory.class);
+ bind(Boolean.class).annotatedWith(InstallAllPlugins.class).toInstance(
+ Boolean.FALSE);
+ bind(new TypeLiteral<List<String>>() {}).annotatedWith(
+ InstallPlugins.class).toInstance(new ArrayList<String>());
+ bind(String.class).annotatedWith(SecureStoreClassName.class)
+ .toProvider(Providers.of(getConfiguredSecureStoreClass()));
+ }
+ });
+ modules.add(new GerritServerConfigModule());
+ return Guice.createInjector(modules);
+ }
+}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SetPasswd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SetPasswd.java
new file mode 100644
index 0000000..c6ece21
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SetPasswd.java
@@ -0,0 +1,43 @@
+// Copyright (C) 2017 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.pgm;
+
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.pgm.init.api.Section.Factory;
+import com.google.inject.Inject;
+
+public class SetPasswd {
+
+ private ConsoleUI ui;
+ private Factory sections;
+
+ @Inject
+ public SetPasswd(ConsoleUI ui, Section.Factory sections) {
+ this.ui = ui;
+ this.sections = sections;
+ }
+
+ public void run(String section, String key, String password) throws Exception {
+ Section passwordSection = sections.get(section, null);
+
+ if (ui.isBatch()) {
+ passwordSection.setSecure(key, password);
+ } else {
+ ui.header("Set password for [%s]", section);
+ passwordSection.passwordForKey("Enter password", key);
+ }
+ }
+}