Block off commands on a server for certain user groups.

This feature adds two new options to gerrit.config file: upload and
receive with the allowGroup attribute, that restrict to some specific
groups the ability to run upload/receive commands on the server.

[sp: All bugs are mine, I refactored the code a bit from the original]

Change-Id: Ibd31bd11234e429f8b0201bbb03099f737281f21
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
lincoln
2010-07-05 10:53:25 -03:00
committed by Shawn O. Pearce
parent cfe5c6b49c
commit 2be1160f05
18 changed files with 416 additions and 78 deletions

View File

@@ -1341,6 +1341,27 @@ auto-detected and one thread per CPU is used, per client request.
By default, 1.
[[receive]]Section receive
~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the group of users allowed to execute 'receive-pack' on the
server, 'receive-pack' is what runs on the server during a user's
push or repo upload command.
----
[receive]
allowGroup = GROUP_ALLOWED_TO_EXECUTE
allowGroup = YET_ANOTHER_GROUP_ALLOWED_TO_EXECUTE
----
[[receive.allowGroup]]receive.allowGroup::
+
Name of the groups of users that are allowed to execute
'receive-pack' on the server. One or more groups can be set.
+
If no groups are added, any user will be allowed to execute
'receive-pack' on the server.
[[repository]]Section repository
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Repositories in this sense are the same as projects.
@@ -1676,6 +1697,28 @@ reasonable timeout value.
+
Defaults to 0 seconds, wait indefinitely.
[[upload]]Section upload
~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the group of users allowed to execute 'upload-pack' on the
server, 'upload-pack' is what runs on the server during a user's
fetch, clone or repo sync command.
----
[upload]
allowGroup = GROUP_ALLOWED_TO_EXECUTE
allowGroup = YET_ANOTHER_GROUP_ALLOWED_TO_EXECUTE
----
[[upload.allowGroup]]upload.allowGroup::
+
Name of the groups of users that are allowed to execute 'upload-pack'
on the server. One or more groups can be set.
+
If no groups are added, any user will be allowed to execute
'upload-pack' on the server.
[[user]] Section user
~~~~~~~~~~~~~~~~~~~~~

View File

@@ -187,10 +187,14 @@ public class ProjectServlet extends GitServlet {
@Override
public UploadPack create(HttpServletRequest req, Repository repo)
throws ServiceNotEnabledException {
throws ServiceNotEnabledException, ServiceNotAuthorizedException {
ProjectControl pc = getProjectControl(req);
if (!pc.canRunUploadPack()) {
throw new ServiceNotAuthorizedException();
}
// The Resolver above already checked READ access for us.
//
ProjectControl pc = getProjectControl(req);
UploadPack up = new UploadPack(repo);
up.setPackConfig(packConfig);
if (!pc.allRefsAreVisible()) {
@@ -212,6 +216,10 @@ public class ProjectServlet extends GitServlet {
public ReceivePack create(HttpServletRequest req, Repository db)
throws ServiceNotEnabledException, ServiceNotAuthorizedException {
final ProjectControl pc = getProjectControl(req);
if (!pc.canRunReceivePack()) {
throw new ServiceNotAuthorizedException();
}
if (pc.getCurrentUser() instanceof IdentifiedUser) {
final IdentifiedUser user = (IdentifiedUser) pc.getCurrentUser();
final ReceiveCommits rc = factory.create(pc, db);

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2010 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.common;
import java.util.Collection;
/** Utilities for manipulating Collections . */
public class CollectionsUtil {
/**
* Checks if any of the elements in the first collection can be found in the
* second collection.
*
* @param findAnyOfThese which elements to look for.
* @param inThisCollection where to look for them.
* @param <E> type of the elements in question.
* @return {@code true} if any of the elements in {@code findAnyOfThese} can
* be found in {@code inThisCollection}, {@code false} otherwise.
*/
public static <E> boolean isAnyIncludedIn(Collection<E> findAnyOfThese,
Collection<E> inThisCollection) {
for (E findThisItem : findAnyOfThese) {
if (inThisCollection.contains(findThisItem)) {
return true;
}
}
return false;
}
private CollectionsUtil() {
}
}

View File

@@ -56,6 +56,7 @@ import com.google.gerrit.server.mail.FromAddressGeneratorProvider;
import com.google.gerrit.server.mail.SmtpEmailSender;
import com.google.gerrit.server.patch.PatchListCacheImpl;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.AccessControlModule;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCacheImpl;
import com.google.gerrit.server.project.ProjectControl;
@@ -136,10 +137,6 @@ public class GerritGlobalModule extends FactoryModule {
bind(Project.NameKey.class).annotatedWith(WildProjectName.class)
.toProvider(WildProjectNameProvider.class).in(SINGLETON);
bind(new TypeLiteral<Set<AccountGroup.Id>>(){}).annotatedWith(ProjectCreatorGroups.class)
.toProvider(ProjectCreatorGroupsProvider.class).in(SINGLETON);
bind(new TypeLiteral<Set<AccountGroup.Id>>(){}).annotatedWith(ProjectOwnerGroups.class)
.toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
bind(ApprovalTypes.class).toProvider(ApprovalTypesProvider.class).in(
SINGLETON);
bind(EmailExpander.class).toProvider(EmailExpanderProvider.class).in(
@@ -156,6 +153,7 @@ public class GerritGlobalModule extends FactoryModule {
install(GroupCacheImpl.module());
install(PatchListCacheImpl.module());
install(ProjectCacheImpl.module());
install(new AccessControlModule());
factory(AccountInfoCacheFactory.Factory.class);
factory(ProjectState.Factory.class);

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2010 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.server.config;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
/**
* Used to populate the groups of users that are allowed to run
* receive-pack on the server.
*
* Gerrit.config example:
*
* <pre>
* [receive]
* allowGroup = RECEIVE_GROUP_ALLOWED
* </pre>
*/
@Retention(RUNTIME)
@BindingAnnotation
public @interface GitReceivePackGroups {
}

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2010 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.server.config;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
import java.util.Collections;
import java.util.HashSet;
public class GitReceivePackGroupsProvider extends GroupSetProvider {
@Inject
public GitReceivePackGroupsProvider(@GerritServerConfig Config config,
AuthConfig authConfig, SchemaFactory<ReviewDb> db) {
super(config, db, "receive", null, "allowGroup");
// If no group was set, default to "registered users"
//
if (groupIds.isEmpty()) {
HashSet<AccountGroup.Id> all = new HashSet<AccountGroup.Id>();
all.addAll(authConfig.getRegisteredGroups());
all.removeAll(authConfig.getAnonymousGroups());
groupIds = Collections.unmodifiableSet(all);
}
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2010 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.server.config;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
/**
* Used to populate the groups of users that are allowed to run
* upload-pack on the server.
*
* Gerrit.config example:
*
* <pre>
* [upload]
* allowGroup = UPLOAD_GROUP_ALLOWED
* </pre>
*/
@Retention(RUNTIME)
@BindingAnnotation
public @interface GitUploadPackGroups {
}

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2010 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.server.config;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
import java.util.Collections;
import java.util.HashSet;
public class GitUploadPackGroupsProvider extends GroupSetProvider {
@Inject
public GitUploadPackGroupsProvider(@GerritServerConfig Config config,
AuthConfig authConfig, SchemaFactory<ReviewDb> db) {
super(config, db, "upload", null, "allowGroup");
// If no group was set, default to "registered users" and "anonymous"
//
if (groupIds.isEmpty()) {
HashSet<AccountGroup.Id> all = new HashSet<AccountGroup.Id>();
all.addAll(authConfig.getRegisteredGroups());
all.addAll(authConfig.getAnonymousGroups());
groupIds = Collections.unmodifiableSet(all);
}
}
}

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2010 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.server.config;
import static com.google.gerrit.server.config.ConfigUtil.groupsFor;
import static java.util.Collections.unmodifiableSet;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
public abstract class GroupSetProvider implements
Provider<Set<AccountGroup.Id>> {
private static final Logger log =
LoggerFactory.getLogger(GroupSetProvider.class);
protected Set<AccountGroup.Id> groupIds;
@Inject
protected GroupSetProvider(@GerritServerConfig Config config,
SchemaFactory<ReviewDb> db, String section, String subsection, String name) {
String[] groupNames = config.getStringList(section, subsection, name);
groupIds = unmodifiableSet(groupsFor(db, groupNames, log));
}
@Override
public Set<AccountGroup.Id> get() {
return groupIds;
}
}

View File

@@ -14,19 +14,14 @@
package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Set;
/**
* Provider of the group(s) which are allowed to create new projects. Currently
@@ -39,27 +34,14 @@ import java.util.Set;
* createGroup = Administrators
* </pre>
*/
public class ProjectCreatorGroupsProvider implements
Provider<Set<AccountGroup.Id>> {
private static final Logger log =
LoggerFactory.getLogger(ProjectCreatorGroupsProvider.class);
private final Set<AccountGroup.Id> groupIds;
public class ProjectCreatorGroupsProvider extends GroupSetProvider {
@Inject
ProjectCreatorGroupsProvider(@GerritServerConfig final Config config,
SchemaFactory<ReviewDb> db, final SystemConfig systemConfig) {
String[] names = config.getStringList("repository", "*", "createGroup");
Set<AccountGroup.Id> createGroups = ConfigUtil.groupsFor(db, names, log);
public ProjectCreatorGroupsProvider(@GerritServerConfig final Config config,
final SystemConfig systemConfig, final SchemaFactory<ReviewDb> db) {
super(config, db, "repository", "*", "createGroup");
if (createGroups.isEmpty()) {
if (groupIds.isEmpty()) {
groupIds = Collections.singleton(systemConfig.adminGroupId);
} else {
groupIds = createGroups;
}
}
public Set<AccountGroup.Id> get() {
return groupIds;
}
}

View File

@@ -18,11 +18,8 @@ import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
@@ -37,28 +34,15 @@ import java.util.Set;
* ownerGroup = Administrators
* </pre>
*/
public class ProjectOwnerGroupsProvider implements
Provider<Set<AccountGroup.Id>> {
private static final Logger log =
LoggerFactory.getLogger(ProjectOwnerGroupsProvider.class);
private final Set<AccountGroup.Id> groupIds;
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
@Inject
ProjectOwnerGroupsProvider(@GerritServerConfig final Config config,
SchemaFactory<ReviewDb> db,
@ProjectCreatorGroups Set<AccountGroup.Id> creatorGroups) {
String[] names = config.getStringList("repository", "*", "ownerGroup");
Set<AccountGroup.Id> ownerGroups = ConfigUtil.groupsFor(db, names, log);
public ProjectOwnerGroupsProvider(
@ProjectCreatorGroups final Set<AccountGroup.Id> creatorGroups,
@GerritServerConfig final Config config, final SchemaFactory<ReviewDb> db) {
super(config, db, "repository", "*", "ownerGroup");
if (ownerGroups.isEmpty()) {
if (groupIds.isEmpty()) {
groupIds = creatorGroups;
} else {
groupIds = ownerGroups;
}
}
public Set<AccountGroup.Id> get() {
return groupIds;
}
}

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2010 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.server.project;
import static com.google.inject.Scopes.SINGLETON;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GitReceivePackGroups;
import com.google.gerrit.server.config.GitReceivePackGroupsProvider;
import com.google.gerrit.server.config.GitUploadPackGroups;
import com.google.gerrit.server.config.GitUploadPackGroupsProvider;
import com.google.gerrit.server.config.ProjectCreatorGroups;
import com.google.gerrit.server.config.ProjectCreatorGroupsProvider;
import com.google.gerrit.server.config.ProjectOwnerGroups;
import com.google.gerrit.server.config.ProjectOwnerGroupsProvider;
import com.google.inject.TypeLiteral;
import java.util.Set;
public class AccessControlModule extends FactoryModule {
@Override
protected void configure() {
bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
.annotatedWith(ProjectCreatorGroups.class) //
.toProvider(ProjectCreatorGroupsProvider.class).in(SINGLETON);
bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
.annotatedWith(ProjectOwnerGroups.class) //
.toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
.annotatedWith(GitUploadPackGroups.class) //
.toProvider(GitUploadPackGroupsProvider.class).in(SINGLETON);
bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
.annotatedWith(GitReceivePackGroups.class) //
.toProvider(GitReceivePackGroupsProvider.class).in(SINGLETON);
factory(ProjectControl.AssistedFactory.class);
}
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.project;
import static com.google.gerrit.common.CollectionsUtil.*;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.Branch;
@@ -22,8 +23,11 @@ import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.ReplicationUser;
import com.google.gerrit.server.config.GitReceivePackGroups;
import com.google.gerrit.server.config.GitUploadPackGroups;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.util.HashSet;
import java.util.Set;
@@ -93,10 +97,22 @@ public class ProjectControl {
}
}
interface AssistedFactory {
ProjectControl create(CurrentUser who, ProjectState ps);
}
private final Set<AccountGroup.Id> uploadGroups;
private final Set<AccountGroup.Id> receiveGroups;
private final CurrentUser user;
private final ProjectState state;
ProjectControl(final CurrentUser who, final ProjectState ps) {
@Inject
ProjectControl(@GitUploadPackGroups Set<AccountGroup.Id> uploadGroups,
@GitReceivePackGroups Set<AccountGroup.Id> receiveGroups,
@Assisted CurrentUser who, @Assisted ProjectState ps) {
this.uploadGroups = uploadGroups;
this.receiveGroups = receiveGroups;
user = who;
state = ps;
}
@@ -230,4 +246,12 @@ public class ProjectControl {
}
return all;
}
public boolean canRunUploadPack() {
return isAnyIncludedIn(uploadGroups, user.getEffectiveGroups());
}
public boolean canRunReceivePack() {
return isAnyIncludedIn(receiveGroups, user.getEffectiveGroups());
}
}

View File

@@ -40,6 +40,7 @@ public class ProjectState {
private final AnonymousUser anonymousUser;
private final Project.NameKey wildProject;
private final ProjectCache projectCache;
private final ProjectControl.AssistedFactory projectControlFactory;
private final Project project;
private final Collection<RefRight> localRights;
@@ -51,11 +52,13 @@ public class ProjectState {
protected ProjectState(final AnonymousUser anonymousUser,
final ProjectCache projectCache,
@WildProjectName final Project.NameKey wildProject,
final ProjectControl.AssistedFactory projectControlFactory,
@Assisted final Project project,
@Assisted final Collection<RefRight> rights) {
this.anonymousUser = anonymousUser;
this.projectCache = projectCache;
this.wildProject = wildProject;
this.projectControlFactory = projectControlFactory;
this.project = project;
this.localRights = rights;
@@ -160,7 +163,7 @@ public class ProjectState {
}
public ProjectControl controlFor(final CurrentUser user) {
return new ProjectControl(user, this);
return projectControlFactory.create(user, this);
}
private static Collection<RefRight> filter(Collection<RefRight> all,

View File

@@ -217,15 +217,18 @@ public class RefControlTest extends TestCase {
}
private ProjectControl user(AccountGroup.Id... memberOf) {
return new ProjectControl(new MockUser(memberOf), newProjectState());
return new ProjectControl(Collections.<AccountGroup.Id> emptySet(),
Collections.<AccountGroup.Id> emptySet(), new MockUser(memberOf),
newProjectState());
}
private ProjectState newProjectState() {
ProjectCache projectCache = null;
Project.NameKey wildProject = null;
ProjectControl.AssistedFactory projectControlFactory = null;
ProjectState ps =
new ProjectState(anonymousUser, projectCache, wildProject, new Project(
projectNameKey), local);
new ProjectState(anonymousUser, projectCache, wildProject,
projectControlFactory, new Project(projectNameKey), local);
ps.setInheritedRights(inherited);
return ps;
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.CollectionsUtil;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.Project;
@@ -38,7 +39,6 @@ import org.kohsuke.args4j.Option;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -126,26 +126,6 @@ final class CreateProject extends BaseCommand {
});
}
/**
* Checks if any of the elements in the first collection can be found in the
* second collection.
*
* @param findAnyOfThese which elements to look for.
* @param inThisCollection where to look for them.
* @param <E> type of the elements in question.
* @return {@code true} if any of the elements in {@code findAnyOfThese} can
* be found in {@code inThisCollection}, {@code false} otherwise.
*/
private static <E> boolean isAnyIncludedIn(Collection<E> findAnyOfThese,
Collection<E> inThisCollection) {
for (E findThisItem : findAnyOfThese) {
if (inThisCollection.contains(findThisItem)) {
return true;
}
}
return false;
}
private void createProject() throws OrmException {
final Project.NameKey newProjectNameKey = new Project.NameKey(projectName);
@@ -179,7 +159,7 @@ final class CreateProject extends BaseCommand {
projectName.substring(0, projectName.length() - ".git".length());
}
if (!isAnyIncludedIn(currentUser.getEffectiveGroups(), projectCreatorGroups)) {
if (!CollectionsUtil.isAnyIncludedIn(currentUser.getEffectiveGroups(), projectCreatorGroups)) {
throw new Failure(1, "fatal: Not permitted to create " + projectName);
}

View File

@@ -58,6 +58,10 @@ final class Receive extends AbstractGitCommand {
@Override
protected void runImpl() throws IOException, Failure {
if (!projectControl.canRunReceivePack()) {
throw new Failure(1, "fatal: receive-pack not permitted on this server");
}
final ReceiveCommits receive = factory.create(projectControl, repo);
ReceiveCommits.Capable r = receive.canUpload();

View File

@@ -36,6 +36,10 @@ final class Upload extends AbstractGitCommand {
@Override
protected void runImpl() throws IOException, Failure {
if (!projectControl.canRunUploadPack()) {
throw new Failure(1, "fatal: upload-pack not permitted on this server");
}
final UploadPack up = new UploadPack(repo);
if (!projectControl.allRefsAreVisible()) {
up.setRefFilter(new VisibleRefFilter(repo, projectControl, db.get()));