Merge "Introduce pull-replication user and internal group" into stable-3.4
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
index 93bbde0..1671410 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
@@ -44,6 +44,7 @@
import com.googlesource.gerrit.plugins.replication.StartReplicationCapability;
import com.googlesource.gerrit.plugins.replication.pull.api.FetchJob;
import com.googlesource.gerrit.plugins.replication.pull.api.PullReplicationApiModule;
+import com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupModule;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchApiClient;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchRestApiClient;
import com.googlesource.gerrit.plugins.replication.pull.client.HttpClient;
@@ -73,6 +74,7 @@
@Override
protected void configure() {
+ install(new PullReplicationGroupModule());
bind(BearerTokenProvider.class).in(Scopes.SINGLETON);
bind(RevisionReader.class).in(Scopes.SINGLETON);
bind(ApplyObject.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java
index cbe1ab8..f196dbe 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java
@@ -19,12 +19,12 @@
import com.google.gerrit.httpd.AllRequestFilter;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.AccessPath;
-import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.util.ManualRequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
+import com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationInternalUser;
import java.io.IOException;
import java.util.Optional;
import java.util.regex.Matcher;
@@ -46,7 +46,7 @@
private static final String BEARER_TOKEN = "BearerToken";
private final DynamicItem<WebSession> session;
private final String pluginName;
- private final Provider<PluginUser> pluginUserProvider;
+ private final PullReplicationInternalUser pluginUser;
private final Provider<ThreadLocalRequestContext> threadLocalRequestContext;
private final String bearerToken;
private final Pattern bearerTokenRegex = Pattern.compile("^Bearer\\s(.+)$");
@@ -55,12 +55,12 @@
BearerAuthenticationFilter(
DynamicItem<WebSession> session,
@PluginName String pluginName,
- Provider<PluginUser> pluginUserProvider,
+ PullReplicationInternalUser pluginUser,
Provider<ThreadLocalRequestContext> threadLocalRequestContext,
@Named(BEARER_TOKEN) String bearerToken) {
this.session = session;
this.pluginName = pluginName;
- this.pluginUserProvider = pluginUserProvider;
+ this.pluginUser = pluginUser;
this.threadLocalRequestContext = threadLocalRequestContext;
this.bearerToken = bearerToken;
}
@@ -88,7 +88,7 @@
if (isBearerTokenAuthenticated(authorizationHeader, bearerToken))
try (ManualRequestContext ctx =
- new ManualRequestContext(pluginUserProvider.get(), threadLocalRequestContext.get())) {
+ new ManualRequestContext(pluginUser, threadLocalRequestContext.get())) {
WebSession ws = session.get();
ws.setAccessPathOk(AccessPath.REST_API, true);
filterChain.doFilter(servletRequest, servletResponse);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackend.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackend.java
new file mode 100644
index 0000000..9521004
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackend.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2022 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.replication.pull.auth;
+
+import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.account.AbstractGroupBackend;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.Arrays;
+import java.util.Collection;
+
+/** Backend to expose the pull-replication internal user group membership. */
+@Singleton
+class PullReplicationGroupBackend extends AbstractGroupBackend {
+ public static final AccountGroup.UUID INTERNAL_GROUP_UUID =
+ AccountGroup.uuid("pullreplication:internal-user");
+ public static final String INTERNAL_GROUP_NAME = "Pull-replication Internal User";
+ public static final String NAME_PREFIX = "pullreplication/";
+ public static final GroupDescription.Basic INTERNAL_GROUP_DESCRIPTION =
+ new GroupDescription.Basic() {
+
+ @Override
+ public String getUrl() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return INTERNAL_GROUP_NAME;
+ }
+
+ @Override
+ public AccountGroup.UUID getGroupUUID() {
+ return INTERNAL_GROUP_UUID;
+ }
+
+ @Override
+ public String getEmailAddress() {
+ return null;
+ }
+ };
+ private final PullReplicationInternalUser internalUser;
+
+ static final ListGroupMembership INTERNAL_GROUP_MEMBERSHIP =
+ new ListGroupMembership(
+ Arrays.asList(INTERNAL_GROUP_UUID, SystemGroupBackend.ANONYMOUS_USERS));
+
+ @Inject
+ public PullReplicationGroupBackend(PullReplicationInternalUser internalUser) {
+ this.internalUser = internalUser;
+ }
+
+ @Override
+ public boolean handles(AccountGroup.UUID uuid) {
+ return INTERNAL_GROUP_UUID.equals(uuid);
+ }
+
+ @Override
+ public GroupDescription.Basic get(AccountGroup.UUID uuid) {
+ return handles(uuid) ? INTERNAL_GROUP_DESCRIPTION : null;
+ }
+
+ @Override
+ public Collection<GroupReference> suggest(String name, ProjectState project) {
+ return Arrays.asList(
+ NAME_PREFIX.contains(name.toLowerCase())
+ ? GroupReference.create(INTERNAL_GROUP_UUID, INTERNAL_GROUP_NAME)
+ : GroupReference.create(name));
+ }
+
+ @Override
+ public GroupMembership membershipsOf(CurrentUser user) {
+ if (user.equals(internalUser)) {
+ return INTERNAL_GROUP_MEMBERSHIP;
+ }
+
+ return ListGroupMembership.EMPTY;
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupModule.java
new file mode 100644
index 0000000..583ba8e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupModule.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 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.replication.pull.auth;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.inject.AbstractModule;
+
+public class PullReplicationGroupModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ DynamicSet.bind(binder(), GroupBackend.class).to(PullReplicationGroupBackend.class);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationInternalUser.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationInternalUser.java
new file mode 100644
index 0000000..e8b7666
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationInternalUser.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 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.replication.pull.auth;
+
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class PullReplicationInternalUser extends PluginUser {
+
+ @Inject
+ protected PullReplicationInternalUser(@PluginName String pluginName) {
+ super(pluginName);
+ }
+
+ @Override
+ public GroupMembership getEffectiveGroups() {
+ return PullReplicationGroupBackend.INTERNAL_GROUP_MEMBERSHIP;
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java
index bbbe66f..96c83a1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java
@@ -21,9 +21,9 @@
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.AccessPath;
-import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Provider;
+import com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationInternalUser;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -39,9 +39,8 @@
@Mock private DynamicItem<WebSession> session;
@Mock private WebSession webSession;
- @Mock private Provider<PluginUser> pluginUserProvider;
@Mock private Provider<ThreadLocalRequestContext> threadLocalRequestContextProvider;
- @Mock private PluginUser pluginUser;
+ @Mock private PullReplicationInternalUser pluginUser;
@Mock private ThreadLocalRequestContext threadLocalRequestContext;
@Mock private HttpServletRequest httpServletRequest;
@Mock private HttpServletResponse httpServletResponse;
@@ -53,21 +52,15 @@
when(httpServletRequest.getRequestURI()).thenReturn(uri);
when(httpServletRequest.getHeader("Authorization"))
.thenReturn(String.format("Bearer %s", bearerToken));
- when(pluginUserProvider.get()).thenReturn(pluginUser);
when(threadLocalRequestContextProvider.get()).thenReturn(threadLocalRequestContext);
when(session.get()).thenReturn(webSession);
final BearerAuthenticationFilter filter =
new BearerAuthenticationFilter(
- session,
- pluginName,
- pluginUserProvider,
- threadLocalRequestContextProvider,
- bearerToken);
+ session, pluginName, pluginUser, threadLocalRequestContextProvider, bearerToken);
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
verify(httpServletRequest).getRequestURI();
verify(httpServletRequest).getHeader("Authorization");
- verify(pluginUserProvider).get();
verify(threadLocalRequestContextProvider).get();
verify(session).get();
verify(webSession).setAccessPathOk(AccessPath.REST_API, true);
@@ -119,7 +112,7 @@
new BearerAuthenticationFilter(
session,
pluginName,
- pluginUserProvider,
+ pluginUser,
threadLocalRequestContextProvider,
"some-bearer-token");
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
@@ -138,7 +131,7 @@
new BearerAuthenticationFilter(
session,
pluginName,
- pluginUserProvider,
+ pluginUser,
threadLocalRequestContextProvider,
"some-bearer-token");
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
@@ -156,7 +149,7 @@
new BearerAuthenticationFilter(
session,
pluginName,
- pluginUserProvider,
+ pluginUser,
threadLocalRequestContextProvider,
"some-bearer-token");
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
@@ -173,7 +166,7 @@
new BearerAuthenticationFilter(
session,
pluginName,
- pluginUserProvider,
+ pluginUser,
threadLocalRequestContextProvider,
"some-bearer-token");
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
@@ -192,7 +185,7 @@
new BearerAuthenticationFilter(
session,
pluginName,
- pluginUserProvider,
+ pluginUser,
threadLocalRequestContextProvider,
"some-bearer-token");
filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackendIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackendIT.java
new file mode 100644
index 0000000..87738e3
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/auth/PullReplicationGroupBackendIT.java
@@ -0,0 +1,80 @@
+// Copyright (C) 2022 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.replication.pull.auth;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupBackend.INTERNAL_GROUP_DESCRIPTION;
+import static com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupBackend.INTERNAL_GROUP_NAME;
+import static com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupBackend.INTERNAL_GROUP_UUID;
+import static com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupBackend.NAME_PREFIX;
+
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.SkipProjectClone;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import java.util.Collection;
+import org.junit.Test;
+
+@SkipProjectClone
+@TestPlugin(
+ name = "pull-replication",
+ sysModule = "com.googlesource.gerrit.plugins.replication.pull.auth.PullReplicationGroupModule")
+public class PullReplicationGroupBackendIT extends LightweightPluginDaemonTest {
+
+ @Test
+ public void shouldResolvePullReplicationInternalGroup() {
+ GroupDescription.Basic group = groupBackend.get(INTERNAL_GROUP_UUID);
+
+ assertThat(group).isNotNull();
+ assertThat(group).isEqualTo(INTERNAL_GROUP_DESCRIPTION);
+ }
+
+ @Test
+ public void shouldSuggestPullReplicationInternalGroup() {
+ Collection<GroupReference> groups = groupBackend.suggest(NAME_PREFIX, null);
+
+ assertThat(groups).isNotNull();
+ assertThat(groups).hasSize(1);
+
+ GroupReference groupReference = groups.iterator().next();
+ assertThat(groupReference.getName()).isEqualTo(INTERNAL_GROUP_NAME);
+ assertThat(groupReference.getUUID()).isEqualTo(INTERNAL_GROUP_UUID);
+ }
+
+ @Test
+ public void pullReplicationInternalUserShouldHaveMembershipOfInternalGroupAndAnonymousUsers() {
+ assertMemberOfInternalAndAnonymousUsers(
+ groupBackend.membershipsOf(getPullReplicationInternalUser()));
+ }
+
+ @Test
+ public void pullReplicationInternalUserShouldHaveEffectiveGroups() {
+ assertMemberOfInternalAndAnonymousUsers(getPullReplicationInternalUser().getEffectiveGroups());
+ }
+
+ private CurrentUser getPullReplicationInternalUser() {
+ CurrentUser user = plugin.getSysInjector().getInstance(PullReplicationInternalUser.class);
+ return user;
+ }
+
+ private void assertMemberOfInternalAndAnonymousUsers(GroupMembership userMembership) {
+ assertThat(userMembership.contains(INTERNAL_GROUP_UUID)).isTrue();
+ assertThat(userMembership.contains(SystemGroupBackend.ANONYMOUS_USERS)).isTrue();
+ }
+}