Add /config/check.access endpoint
The check.access endpoint is for administrative users. It can be supplied with a (project, account) or (project, account, ref) tuple to check that ACLs are behaving as expected. Change-Id: Icf74b0fc4036312eef9f222aaff8e1769a051eec
This commit is contained in:
@@ -183,6 +183,48 @@ is returned that contains detected consistency problems.
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[[check-access]]
|
||||||
|
=== Check Access
|
||||||
|
--
|
||||||
|
'POST /config/server/check.access'
|
||||||
|
--
|
||||||
|
|
||||||
|
Runs access checks for other users.
|
||||||
|
|
||||||
|
Input for the access checks that should be run must be provided in
|
||||||
|
the request body inside a
|
||||||
|
link:#access-check-input[AccessCheckInput] entity.
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
POST /config/server/check HTTP/1.0
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
{
|
||||||
|
"project": "medium",
|
||||||
|
"account": "Kristen.Burns@gerritcodereview.com",
|
||||||
|
"ref": "refs/heads/secret/bla"
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
The result is a link:#access-check-info[AccessCheckInfo] entity
|
||||||
|
detailing the read access of the given user for the given project (or
|
||||||
|
project-ref combination).
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"message": "user Kristen Burns \u003cKristen.Burns@gerritcodereview.com\u003e (1000098) cannot see ref refs/heads/secret/master in project medium",
|
||||||
|
"status": 403
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
[[confirm-email]]
|
[[confirm-email]]
|
||||||
=== Confirm Email
|
=== Confirm Email
|
||||||
--
|
--
|
||||||
@@ -1266,6 +1308,34 @@ The ID of the task (hex string).
|
|||||||
[[json-entities]]
|
[[json-entities]]
|
||||||
== JSON Entities
|
== JSON Entities
|
||||||
|
|
||||||
|
[[access-check-info]]
|
||||||
|
=== AccessCheckInfo
|
||||||
|
The `AccessCheckInfo` entity is the result of a
|
||||||
|
an access check.
|
||||||
|
|
||||||
|
[options="header",cols="1,^1,5"]
|
||||||
|
|=========================================
|
||||||
|
|Field Name |Description
|
||||||
|
|`status`|The HTTP status code for the access.
|
||||||
|
200 means success, 403 means denied and 404 means the project does not
|
||||||
|
exist.
|
||||||
|
|`message`|A clarifying message.
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
[[access-check-input]]
|
||||||
|
=== AccessCheckInput
|
||||||
|
The `AccessCheckInput` entity is a tuple of (account, project) or
|
||||||
|
(account, project, ref) for which we want to check access.
|
||||||
|
|
||||||
|
[options="header",cols="1,^1,5"]
|
||||||
|
|=========================================
|
||||||
|
|Field Name ||Description
|
||||||
|
|`account`||The account for which to check access
|
||||||
|
|`project`||The project for which to check access
|
||||||
|
|`ref`|optional|The refname for which to check access
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
[[auth-info]]
|
[[auth-info]]
|
||||||
=== AuthInfo
|
=== AuthInfo
|
||||||
The `AuthInfo` entity contains information about the authentication
|
The `AuthInfo` entity contains information about the authentication
|
||||||
|
@@ -0,0 +1,140 @@
|
|||||||
|
// 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.acceptance.rest.account;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.TestAccount;
|
||||||
|
import com.google.gerrit.common.data.Permission;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInfo;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.server.group.SystemGroupBackend;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CheckAccessIT extends AbstractDaemonTest {
|
||||||
|
|
||||||
|
private Project.NameKey normalProject;
|
||||||
|
private Project.NameKey secretProject;
|
||||||
|
private Project.NameKey secretRefProject;
|
||||||
|
private TestAccount privilegedUser;
|
||||||
|
private AccountGroup privilegedGroup;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
normalProject = createProject("normal");
|
||||||
|
secretProject = createProject("secret");
|
||||||
|
secretRefProject = createProject("secretRef");
|
||||||
|
privilegedGroup = groupCache.get(new AccountGroup.NameKey(createGroup("privilegedGroup")));
|
||||||
|
|
||||||
|
privilegedUser = accounts.create("privilegedUser", "snowden@nsa.gov", "Ed Snowden");
|
||||||
|
gApi.groups().id(privilegedGroup.getGroupUUID().get()).addMembers(privilegedUser.username);
|
||||||
|
|
||||||
|
assertThat(gApi.groups().id(privilegedGroup.getGroupUUID().get()).members().get(0).email)
|
||||||
|
.contains("snowden");
|
||||||
|
|
||||||
|
// deny(secretProject, Permission.READ, SystemGroupBackend.REGISTERED_USERS, "refs/*");
|
||||||
|
grant(Permission.READ, secretProject, "refs/*", false, privilegedGroup.getGroupUUID());
|
||||||
|
block(Permission.READ, SystemGroupBackend.REGISTERED_USERS, "refs/*", secretProject);
|
||||||
|
|
||||||
|
// deny/grant/block arg ordering is screwy.
|
||||||
|
deny(secretRefProject, Permission.READ, SystemGroupBackend.ANONYMOUS_USERS, "refs/*");
|
||||||
|
grant(
|
||||||
|
Permission.READ,
|
||||||
|
secretRefProject,
|
||||||
|
"refs/heads/secret/*",
|
||||||
|
false,
|
||||||
|
privilegedGroup.getGroupUUID());
|
||||||
|
block(
|
||||||
|
Permission.READ,
|
||||||
|
SystemGroupBackend.REGISTERED_USERS,
|
||||||
|
"refs/heads/secret/*",
|
||||||
|
secretRefProject);
|
||||||
|
grant(
|
||||||
|
Permission.READ,
|
||||||
|
secretRefProject,
|
||||||
|
"refs/heads/*",
|
||||||
|
false,
|
||||||
|
SystemGroupBackend.REGISTERED_USERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidInputs() {
|
||||||
|
List<AccessCheckInput> inputs =
|
||||||
|
ImmutableList.of(
|
||||||
|
new AccessCheckInput(),
|
||||||
|
new AccessCheckInput(user.email, null, null),
|
||||||
|
new AccessCheckInput(null, normalProject.toString(), null),
|
||||||
|
new AccessCheckInput("doesnotexist@invalid.com", normalProject.toString(), null));
|
||||||
|
for (AccessCheckInput input : inputs) {
|
||||||
|
try {
|
||||||
|
gApi.config().server().checkAccess(input);
|
||||||
|
fail(String.format("want RestApiException for %s", newGson().toJson(input)));
|
||||||
|
} catch (RestApiException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void accessible() {
|
||||||
|
Map<AccessCheckInput, Integer> inputs =
|
||||||
|
ImmutableMap.of(
|
||||||
|
new AccessCheckInput(user.email, normalProject.get(), null), 200,
|
||||||
|
new AccessCheckInput(user.email, secretProject.get(), null), 403,
|
||||||
|
new AccessCheckInput(user.email, "nonexistent", null), 404,
|
||||||
|
new AccessCheckInput(privilegedUser.email, normalProject.get(), null), 200,
|
||||||
|
new AccessCheckInput(privilegedUser.email, secretProject.get(), null), 200);
|
||||||
|
|
||||||
|
for (Map.Entry<AccessCheckInput, Integer> entry : inputs.entrySet()) {
|
||||||
|
String in = newGson().toJson(entry.getKey());
|
||||||
|
AccessCheckInfo info = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
info = gApi.config().server().checkAccess(entry.getKey());
|
||||||
|
} catch (RestApiException e) {
|
||||||
|
fail(String.format("check.check(%s): exception %s", in, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
int want = entry.getValue();
|
||||||
|
if (want != info.result.status) {
|
||||||
|
fail(String.format("check.access(%s) = %d, want %d", in, info.result.status, want));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (want) {
|
||||||
|
case 403:
|
||||||
|
assertThat(info.result.message).contains("cannot see");
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
assertThat(info.result.message).contains("does not exist");
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
assertThat(info.result.message).isNull();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail(String.format("unknown code %d", want));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
// 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.extensions.api.config;
|
||||||
|
|
||||||
|
public class AccessCheckInfo {
|
||||||
|
public static class Result {
|
||||||
|
public String message;
|
||||||
|
|
||||||
|
// HTTP status code.
|
||||||
|
public int status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result result;
|
||||||
|
// for future extension, we may add inputs / results for bulk checks.
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
// 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.extensions.api.config;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.Nullable;
|
||||||
|
|
||||||
|
public class AccessCheckInput {
|
||||||
|
public String account;
|
||||||
|
public String project;
|
||||||
|
|
||||||
|
@Nullable public String ref;
|
||||||
|
|
||||||
|
public AccessCheckInput(String account, String project, @Nullable String ref) {
|
||||||
|
this.account = account;
|
||||||
|
this.project = project;
|
||||||
|
this.ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessCheckInput() {
|
||||||
|
}
|
||||||
|
}
|
@@ -36,6 +36,8 @@ public interface Server {
|
|||||||
|
|
||||||
ConsistencyCheckInfo checkConsistency(ConsistencyCheckInput in) throws RestApiException;
|
ConsistencyCheckInfo checkConsistency(ConsistencyCheckInput in) throws RestApiException;
|
||||||
|
|
||||||
|
AccessCheckInfo checkAccess(AccessCheckInput in) throws RestApiException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default implementation which allows source compatibility when adding new methods to the
|
* A default implementation which allows source compatibility when adding new methods to the
|
||||||
* interface.
|
* interface.
|
||||||
@@ -75,5 +77,10 @@ public interface Server {
|
|||||||
public ConsistencyCheckInfo checkConsistency(ConsistencyCheckInput in) {
|
public ConsistencyCheckInfo checkConsistency(ConsistencyCheckInput in) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessCheckInfo checkAccess(AccessCheckInput in) throws RestApiException {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,8 @@
|
|||||||
package com.google.gerrit.server.api.config;
|
package com.google.gerrit.server.api.config;
|
||||||
|
|
||||||
import com.google.gerrit.common.Version;
|
import com.google.gerrit.common.Version;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInfo;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInput;
|
||||||
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
|
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
|
||||||
import com.google.gerrit.extensions.api.config.ConsistencyCheckInput;
|
import com.google.gerrit.extensions.api.config.ConsistencyCheckInput;
|
||||||
import com.google.gerrit.extensions.api.config.Server;
|
import com.google.gerrit.extensions.api.config.Server;
|
||||||
@@ -22,6 +24,7 @@ import com.google.gerrit.extensions.client.DiffPreferencesInfo;
|
|||||||
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
||||||
import com.google.gerrit.extensions.common.ServerInfo;
|
import com.google.gerrit.extensions.common.ServerInfo;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.server.config.CheckAccess;
|
||||||
import com.google.gerrit.server.config.CheckConsistency;
|
import com.google.gerrit.server.config.CheckConsistency;
|
||||||
import com.google.gerrit.server.config.ConfigResource;
|
import com.google.gerrit.server.config.ConfigResource;
|
||||||
import com.google.gerrit.server.config.GetDiffPreferences;
|
import com.google.gerrit.server.config.GetDiffPreferences;
|
||||||
@@ -29,6 +32,8 @@ import com.google.gerrit.server.config.GetPreferences;
|
|||||||
import com.google.gerrit.server.config.GetServerInfo;
|
import com.google.gerrit.server.config.GetServerInfo;
|
||||||
import com.google.gerrit.server.config.SetDiffPreferences;
|
import com.google.gerrit.server.config.SetDiffPreferences;
|
||||||
import com.google.gerrit.server.config.SetPreferences;
|
import com.google.gerrit.server.config.SetPreferences;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gwtorm.server.Access;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
@@ -43,6 +48,7 @@ public class ServerImpl implements Server {
|
|||||||
private final SetDiffPreferences setDiffPreferences;
|
private final SetDiffPreferences setDiffPreferences;
|
||||||
private final GetServerInfo getServerInfo;
|
private final GetServerInfo getServerInfo;
|
||||||
private final Provider<CheckConsistency> checkConsistency;
|
private final Provider<CheckConsistency> checkConsistency;
|
||||||
|
private final Provider<CheckAccess> checkAccess;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ServerImpl(
|
ServerImpl(
|
||||||
@@ -51,13 +57,15 @@ public class ServerImpl implements Server {
|
|||||||
GetDiffPreferences getDiffPreferences,
|
GetDiffPreferences getDiffPreferences,
|
||||||
SetDiffPreferences setDiffPreferences,
|
SetDiffPreferences setDiffPreferences,
|
||||||
GetServerInfo getServerInfo,
|
GetServerInfo getServerInfo,
|
||||||
Provider<CheckConsistency> checkConsistency) {
|
Provider<CheckConsistency> checkConsistency,
|
||||||
|
Provider<CheckAccess> checkAccess) {
|
||||||
this.getPreferences = getPreferences;
|
this.getPreferences = getPreferences;
|
||||||
this.setPreferences = setPreferences;
|
this.setPreferences = setPreferences;
|
||||||
this.getDiffPreferences = getDiffPreferences;
|
this.getDiffPreferences = getDiffPreferences;
|
||||||
this.setDiffPreferences = setDiffPreferences;
|
this.setDiffPreferences = setDiffPreferences;
|
||||||
this.getServerInfo = getServerInfo;
|
this.getServerInfo = getServerInfo;
|
||||||
this.checkConsistency = checkConsistency;
|
this.checkConsistency = checkConsistency;
|
||||||
|
this.checkAccess = checkAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -120,4 +128,13 @@ public class ServerImpl implements Server {
|
|||||||
throw new RestApiException("Cannot check consistency", e);
|
throw new RestApiException("Cannot check consistency", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessCheckInfo checkAccess(AccessCheckInput in) throws RestApiException {
|
||||||
|
try {
|
||||||
|
return checkAccess.get().apply(new ConfigResource(), in);
|
||||||
|
} catch (IOException | PermissionBackendException e) {
|
||||||
|
throw new RestApiException("Cannot check access", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,137 @@
|
|||||||
|
// 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.server.config;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInfo;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInfo.Result;
|
||||||
|
import com.google.gerrit.extensions.api.config.AccessCheckInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project.NameKey;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.account.AccountResolver;
|
||||||
|
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||||
|
import com.google.gerrit.server.permissions.RefPermission;
|
||||||
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class CheckAccess implements RestModifyView<ConfigResource, AccessCheckInput> {
|
||||||
|
private final Provider<IdentifiedUser> currentUser;
|
||||||
|
private final AccountResolver resolver;
|
||||||
|
private final Provider<ReviewDb> db;
|
||||||
|
private final IdentifiedUser.GenericFactory userFactory;
|
||||||
|
private final ProjectCache projectCache;
|
||||||
|
private final PermissionBackend permissionBackend;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
CheckAccess(
|
||||||
|
Provider<IdentifiedUser> currentUser,
|
||||||
|
AccountResolver resolver,
|
||||||
|
Provider<ReviewDb> db,
|
||||||
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
|
ProjectCache projectCache,
|
||||||
|
PermissionBackend permissionBackend) {
|
||||||
|
this.currentUser = currentUser;
|
||||||
|
this.resolver = resolver;
|
||||||
|
this.db = db;
|
||||||
|
this.userFactory = userFactory;
|
||||||
|
this.projectCache = projectCache;
|
||||||
|
this.permissionBackend = permissionBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessCheckInfo apply(ConfigResource unused, AccessCheckInput input)
|
||||||
|
throws PermissionBackendException, RestApiException, IOException {
|
||||||
|
permissionBackend.user(currentUser.get()).check(GlobalPermission.ADMINISTRATE_SERVER);
|
||||||
|
|
||||||
|
if (input == null) {
|
||||||
|
throw new BadRequestException("input is required");
|
||||||
|
}
|
||||||
|
if (input.account == null) {
|
||||||
|
throw new BadRequestException("must set account in input");
|
||||||
|
}
|
||||||
|
if (input.project == null) {
|
||||||
|
throw new BadRequestException("must set project in input");
|
||||||
|
}
|
||||||
|
|
||||||
|
Account match;
|
||||||
|
try {
|
||||||
|
match = resolver.find(db.get(), input.account);
|
||||||
|
} catch (OrmException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
if (match == null) {
|
||||||
|
throw new BadRequestException(String.format("cannot find account %s", input.account));
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentifiedUser user = userFactory.create(match.getId());
|
||||||
|
AccessCheckInfo info = new AccessCheckInfo();
|
||||||
|
info.result = new Result();
|
||||||
|
|
||||||
|
Project.NameKey key = new Project.NameKey(input.project);
|
||||||
|
if (projectCache.get(key) == null) {
|
||||||
|
info.result.message = String.format("project %s does not exist", key);
|
||||||
|
info.result.status = HttpServletResponse.SC_NOT_FOUND;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
permissionBackend.user(user).project(key).check(ProjectPermission.ACCESS);
|
||||||
|
} catch (AuthException | PermissionBackendException e) {
|
||||||
|
info.result.message =
|
||||||
|
String.format(
|
||||||
|
"user %s (%s) cannot see project %s",
|
||||||
|
user.getNameEmail(), user.getAccount().getId(), key);
|
||||||
|
info.result.status = HttpServletResponse.SC_FORBIDDEN;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(input.ref)) {
|
||||||
|
try {
|
||||||
|
permissionBackend
|
||||||
|
.user(user)
|
||||||
|
.ref(new Branch.NameKey(key, input.ref))
|
||||||
|
.check(RefPermission.READ);
|
||||||
|
} catch (AuthException | PermissionBackendException e) {
|
||||||
|
info.result.status = HttpServletResponse.SC_FORBIDDEN;
|
||||||
|
info.result.message =
|
||||||
|
String.format(
|
||||||
|
"user %s (%s) cannot see ref %s in project %s",
|
||||||
|
user.getNameEmail(), user.getAccount().getId(), input.ref, key);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.result.status = HttpServletResponse.SC_OK;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
@@ -37,6 +37,7 @@ public class Module extends RestApiModule {
|
|||||||
get(CONFIG_KIND, "version").to(GetVersion.class);
|
get(CONFIG_KIND, "version").to(GetVersion.class);
|
||||||
get(CONFIG_KIND, "info").to(GetServerInfo.class);
|
get(CONFIG_KIND, "info").to(GetServerInfo.class);
|
||||||
post(CONFIG_KIND, "check.consistency").to(CheckConsistency.class);
|
post(CONFIG_KIND, "check.consistency").to(CheckConsistency.class);
|
||||||
|
post(CONFIG_KIND, "check.access").to(CheckAccess.class);
|
||||||
get(CONFIG_KIND, "preferences").to(GetPreferences.class);
|
get(CONFIG_KIND, "preferences").to(GetPreferences.class);
|
||||||
put(CONFIG_KIND, "preferences").to(SetPreferences.class);
|
put(CONFIG_KIND, "preferences").to(SetPreferences.class);
|
||||||
get(CONFIG_KIND, "preferences.diff").to(GetDiffPreferences.class);
|
get(CONFIG_KIND, "preferences.diff").to(GetDiffPreferences.class);
|
||||||
|
Reference in New Issue
Block a user