Allow additional SSH-key formats
So far only RSA-type SSH-keys were allowed to be used for service users.
Since Gerrit and older versions of this plugin allowed other formats
as well, this could break existing installations.
This change adds a validator-class for SSH-keys that is able to validate
a wider range of SSH-key formats. The validation is far from perfect and
only meant to minimize the risk of creating unusable accounts, because
of an invalid SSH-key.
Change-Id: I3396ee449f6f88708514583a055a45c69abb4dd9
diff --git a/BUILD b/BUILD
index 36d967f..fcad0e5 100644
--- a/BUILD
+++ b/BUILD
@@ -1,8 +1,9 @@
-load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+load("//tools/bzl:junit.bzl", "junit_tests")
+load("//tools/bzl:plugin.bzl", "PLUGIN_DEPS", "PLUGIN_TEST_DEPS", "gerrit_plugin")
gerrit_plugin(
name = "serviceuser",
- srcs = glob(["src/main/java/com/googlesource/gerrit/plugins/serviceuser/**/*.java"]),
+ srcs = glob(["src/main/java/**/*.java"]),
manifest_entries = [
"Gerrit-PluginName: serviceuser",
"Gerrit-Module: com.googlesource.gerrit.plugins.serviceuser.Module",
@@ -11,3 +12,15 @@
],
resources = glob(["src/main/resources/**/*"]),
)
+
+junit_tests(
+ name = "serviceuser_tests",
+ testonly = 1,
+ srcs = glob([
+ "src/test/java/**/*Test.java",
+ ]),
+ tags = ["serviceuser"],
+ deps = PLUGIN_TEST_DEPS + PLUGIN_DEPS + [
+ ":serviceuser__plugin",
+ ],
+)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
index 713ab41..80ddf1b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
@@ -47,9 +47,7 @@
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.Input;
import com.googlesource.gerrit.plugins.serviceuser.GetServiceUser.ServiceUserInfo;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.StringReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -142,10 +140,7 @@
throw new BadRequestException("sshKey not set");
}
- final BufferedReader br = new BufferedReader(new StringReader(input.sshKey));
- String line = br.readLine();
- if (line == null
- || !(line.equals("---- BEGIN SSH2 PUBLIC KEY ----") || line.startsWith("ssh-rsa"))) {
+ if (!SshKeyValidator.validateFormat(input.sshKey)) {
throw new BadRequestException("sshKey invalid.");
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java
new file mode 100644
index 0000000..9a95db1
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 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.googlesource.gerrit.plugins.serviceuser;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SshKeyValidator {
+
+ private static final String OPENSSH_KEY_PREFIXES[] = {
+ "ssh-ed25519", "ssh-rsa", "ssh-dss", "ecdsa-sha2-"
+ };
+ private static final Pattern RFC_KEY_FORMAT_PATTERN =
+ Pattern.compile(
+ "(?s)^-{4,5}\\s?BEGIN.* PUBLIC KEY\\s?-{4,5}.+-{4,5}\\s?END.* PUBLIC KEY\\s?-{4,5}$");
+
+ static boolean validateFormat(String sshKey) {
+ if (validateRfcFormat(sshKey)) {
+ return true;
+ }
+
+ return validateOpenSshFormat(sshKey);
+ }
+
+ private static boolean validateOpenSshFormat(String sshKey) {
+ for (String prefix : OPENSSH_KEY_PREFIXES) {
+ if (sshKey.startsWith(prefix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean validateRfcFormat(String sshKey) {
+ Matcher matcher = RFC_KEY_FORMAT_PATTERN.matcher(sshKey);
+ return matcher.find();
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java
new file mode 100644
index 0000000..619ab98
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2019 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.googlesource.gerrit.plugins.serviceuser;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class SshKeyValidatorTest {
+
+ private final String[] VALID_PUBLIC_KEYS = {
+ "---- BEGIN SSH2 PUBLIC KEY ----\n"
+ + " Comment: comment\n"
+ + " AAAAB3NzaC1\n"
+ + " ---- END SSH2 PUBLIC KEY ----",
+ "---- BEGIN PUBLIC KEY ----\n"
+ + " Comment: comment\n"
+ + " AAAAB3NzaC1\n"
+ + " ---- END PUBLIC KEY ----",
+ "-----BEGIN RSA PUBLIC KEY-----\nMIIBC\n-----END RSA PUBLIC KEY-----",
+ "ssh-rsa AAAAB3NzaC1",
+ "ssh-dss AAAAB3NzaC1",
+ "ssh-ed25519 AAAAB3NzaC1",
+ "ecdsa-sha2-nistp256 AAAAB3NzaC1"
+ };
+
+ private final String[] INVALID_PUBLIC_KEYS = {
+ "---- BEGIN SSH2 PUBLIC KEY ----\n Comment: comment\n AAAAB3NzaC1\n",
+ "-----BEGIN PRIVATE KEY-----\nMIIBC\n-----END PRIVATE KEY-----",
+ "AAAAB3NzaC1\n ---- END SSH2 PUBLIC KEY ----",
+ "",
+ "invalid key"
+ };
+
+ @Test
+ public void testValidateSshKeyFormat_Valid() {
+ for (String keyToTest : VALID_PUBLIC_KEYS) {
+ assertThat(SshKeyValidator.validateFormat(keyToTest)).isTrue();
+ }
+ }
+
+ @Test
+ public void testValidateSshKeyFormat_Invalid() {
+ for (String keyToTest : INVALID_PUBLIC_KEYS) {
+ assertThat(SshKeyValidator.validateFormat(keyToTest)).isFalse();
+ }
+ }
+}
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
new file mode 100644
index 0000000..240c448
--- /dev/null
+++ b/tools/bzl/junit.bzl
@@ -0,0 +1,5 @@
+load(
+ "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
+ _junit_tests = "junit_tests",
+)
+junit_tests = _junit_tests
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index 89a1643..4d2dbdd 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -2,7 +2,9 @@
"@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
_gerrit_plugin = "gerrit_plugin",
_plugin_deps = "PLUGIN_DEPS",
+ _plugin_test_deps = "PLUGIN_TEST_DEPS",
)
gerrit_plugin = _gerrit_plugin
PLUGIN_DEPS = _plugin_deps
+PLUGIN_TEST_DEPS = _plugin_test_deps