Merge "Support retrieving project access rights via REST"
This commit is contained in:
376
Documentation/rest-api-access.txt
Normal file
376
Documentation/rest-api-access.txt
Normal file
@@ -0,0 +1,376 @@
|
||||
Gerrit Code Review - /access/ REST API
|
||||
======================================
|
||||
|
||||
This page describes the access rights related REST endpoints.
|
||||
Please also take note of the general information on the
|
||||
link:rest-api.html[REST API].
|
||||
|
||||
[[access-endpoints]]
|
||||
Access Rights Endpoints
|
||||
-----------------------
|
||||
|
||||
[[list-access]]
|
||||
List Access Rights
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
[verse]
|
||||
'GET /access/?project=link:rest-api-projects.html#project-name[\{project-name\}]'
|
||||
|
||||
Lists the access rights for projects. The projects for which the access
|
||||
rights should be returned must be specified as `project` options. The
|
||||
`project` can be specified multiple times.
|
||||
|
||||
As result a map is returned that maps the project name to
|
||||
link:#project-access-info[ProjectAccessInfo] entities.
|
||||
|
||||
The entries in the map are sorted by project name.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /access/?project=MyProject&project=All-Projects HTTP/1.0
|
||||
----
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
)]}'
|
||||
{
|
||||
"All-Projects": {
|
||||
"revision": "edd453d18e08640e67a8c9a150cec998ed0ac9aa",
|
||||
"local": {
|
||||
"GLOBAL_CAPABILITIES": {
|
||||
"permissions": {
|
||||
"priority": {
|
||||
"rules": {
|
||||
"15bfcd8a6de1a69c50b30cedcdcc951c15703152": {
|
||||
"action": "BATCH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"streamEvents": {
|
||||
"rules": {
|
||||
"15bfcd8a6de1a69c50b30cedcdcc951c15703152": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"administrateServer": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"refs/meta/config": {
|
||||
"permissions": {
|
||||
"submit": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label-Code-Review": {
|
||||
"label": "Code-Review",
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW",
|
||||
"min": -2,
|
||||
"max": 2
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW",
|
||||
"min": -2,
|
||||
"max": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"read": {
|
||||
"exclusive": true,
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"push": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"refs/for/refs/*": {
|
||||
"permissions": {
|
||||
"pushMerge": {
|
||||
"rules": {
|
||||
"global:Registered-Users": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"push": {
|
||||
"rules": {
|
||||
"global:Registered-Users": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"refs/tags/*": {
|
||||
"permissions": {
|
||||
"pushSignedTag": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pushTag": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"refs/heads/*": {
|
||||
"permissions": {
|
||||
"forgeCommitter": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forgeAuthor": {
|
||||
"rules": {
|
||||
"global:Registered-Users": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"editTopicName": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW",
|
||||
"force": true
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW",
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"label-Code-Review": {
|
||||
"label": "Code-Review",
|
||||
"rules": {
|
||||
"global:Registered-Users": {
|
||||
"action": "ALLOW",
|
||||
"min": -1,
|
||||
"max": 1
|
||||
},
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW",
|
||||
"min": -2,
|
||||
"max": 2
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW",
|
||||
"min": -2,
|
||||
"max": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"create": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
},
|
||||
"push": {
|
||||
"rules": {
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"global:Project-Owners": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"refs/*": {
|
||||
"permissions": {
|
||||
"read": {
|
||||
"rules": {
|
||||
"global:Anonymous-Users": {
|
||||
"action": "ALLOW"
|
||||
},
|
||||
"53a4f647a89ea57992571187d8025f830625192a": {
|
||||
"action": "ALLOW"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"owner_of": [
|
||||
"GLOBAL_CAPABILITIES",
|
||||
"refs/meta/config",
|
||||
"refs/for/refs/*",
|
||||
"refs/tags/*",
|
||||
"refs/heads/*",
|
||||
"refs/*"
|
||||
],
|
||||
"can_upload": true,
|
||||
"can_add": true,
|
||||
"config_visible": true
|
||||
},
|
||||
"MyProject": {
|
||||
"revision": "61157ed63e14d261b6dca40650472a9b0bd88474",
|
||||
"inherits_from": {
|
||||
"kind": "gerritcodereview#project",
|
||||
"id": "All-Projects",
|
||||
"name": "All-Projects",
|
||||
"description": "Access inherited by all other projects."
|
||||
},
|
||||
"local": {},
|
||||
"owner_of": [
|
||||
"refs/*"
|
||||
],
|
||||
"can_upload": true,
|
||||
"can_add": true,
|
||||
"config_visible": true
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[access-section-info]]
|
||||
AccessSectionInfo
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The `AccessSectionInfo` describes the access rights that are assigned
|
||||
on a ref.
|
||||
|
||||
[options="header",width="50%",cols="1,^1,5"]
|
||||
|==================================
|
||||
|Field Name ||Description
|
||||
|`permissions` ||
|
||||
The permissions assigned on the ref of this access section as a map
|
||||
that maps the permission names to link:#permission-info[PermissionInfo]
|
||||
entities.
|
||||
|==================================
|
||||
|
||||
[[permission-info]]
|
||||
PermissionInfo
|
||||
~~~~~~~~~~~~~~
|
||||
The `PermissionInfo` entity contains information about an assigned
|
||||
permission.
|
||||
|
||||
[options="header",width="50%",cols="1,^1,5"]
|
||||
|==================================
|
||||
|Field Name ||Description
|
||||
|`label` |optional|
|
||||
The name of the label. Not set if it's not a label permission.
|
||||
|`exclusive` |not set if `false`|
|
||||
Whether this permission is assigned exclusively.
|
||||
|`rules` ||
|
||||
The rules assigned for this permission as a map that maps the UUIDs of
|
||||
the groups for which the permission are assigned to
|
||||
link:#permission-info[PermissionRuleInfo] entities.
|
||||
|==================================
|
||||
|
||||
[[permission-rule-info]]
|
||||
PermissionRuleInfo
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
The `PermissionRuleInfo` entity contains information about a permission
|
||||
rule that is assigned to group.
|
||||
|
||||
[options="header",width="50%",cols="1,^1,5"]
|
||||
|==================================
|
||||
|Field Name ||Description
|
||||
|`action` ||
|
||||
The action of this rule. For normal permissions this can be `ALLOW`,
|
||||
`DENY` or `BLOCK`. Special values for global capabilities are
|
||||
`INTERACTIVE` and `BATCH`.
|
||||
|`force` |not set if `false`|
|
||||
Whether the force flag is set.
|
||||
|`min` |
|
||||
not set if range if empty (from `0` to `0`) or not set|
|
||||
The min value of the permission range.
|
||||
|`max` |
|
||||
not set if range if empty (from `0` to `0`) or not set|
|
||||
The max value of the permission range.
|
||||
|==================================
|
||||
|
||||
[[project-access-info]]
|
||||
ProjectAccessInfo
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The `ProjectAccessInfo` entity contains information about the access
|
||||
rights for a project.
|
||||
|
||||
[options="header",width="50%",cols="1,^1,5"]
|
||||
|==================================
|
||||
|Field Name ||Description
|
||||
|`revision` ||
|
||||
The revision of the `refs/meta/config` branch from which the access
|
||||
rights were loaded.
|
||||
|`inherits_from` |not set for the `All-Project` project|
|
||||
The parent project from which permissions are inherited as a
|
||||
link:rest-api-projects.html#project-info[ProjectInfo] entity.
|
||||
|`local` ||
|
||||
The local access rights of the project as a map that maps the refs to
|
||||
link:#access-section-info[AccessSectionInfo] entities.
|
||||
|`owner_of` ||The list of refs owned by the calling user.
|
||||
|`can_upload` |not set if `false`|
|
||||
Whether the calling user can upload to any ref.
|
||||
|`can_add` |not set if `false`|
|
||||
Whether the calling user can add any ref.
|
||||
|`config_visible` |not set if `false`|
|
||||
Whether the calling user can see the `refs/meta/config` branch of the
|
||||
project.
|
||||
|==================================
|
||||
|
||||
|
||||
GERRIT
|
||||
------
|
||||
Part of link:index.html[Gerrit Code Review]
|
||||
@@ -9,6 +9,8 @@ See also: link:dev-rest-api.html[REST API Developers' Notes].
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
link:rest-api-access.html[/access/]::
|
||||
Access Right related REST endpoints
|
||||
link:rest-api-accounts.html[/accounts/]::
|
||||
Account related REST endpoints
|
||||
link:rest-api-changes.html[/changes/]::
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.gerrit.httpd.raw.LegacyGerritServlet;
|
||||
import com.google.gerrit.httpd.raw.SshInfoServlet;
|
||||
import com.google.gerrit.httpd.raw.StaticServlet;
|
||||
import com.google.gerrit.httpd.raw.ToolServlet;
|
||||
import com.google.gerrit.httpd.rpc.access.AccessRestApiServlet;
|
||||
import com.google.gerrit.httpd.rpc.account.AccountsRestApiServlet;
|
||||
import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet;
|
||||
import com.google.gerrit.httpd.rpc.change.DeprecatedChangeQueryServlet;
|
||||
@@ -101,6 +102,7 @@ class UrlModule extends ServletModule {
|
||||
|
||||
filter("/a/*").through(RequireIdentifiedUserFilter.class);
|
||||
serveRegex("^/(?:a/)?tools/(.*)$").with(ToolServlet.class);
|
||||
serveRegex("^/(?:a/)?access/(.*)$").with(AccessRestApiServlet.class);
|
||||
serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class);
|
||||
serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
|
||||
serveRegex("^/(?:a/)?config/(.*)$").with(ConfigRestApiServlet.class);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2013 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.httpd.rpc.access;
|
||||
|
||||
import com.google.gerrit.httpd.restapi.RestApiServlet;
|
||||
import com.google.gerrit.server.access.AccessCollection;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class AccessRestApiServlet extends RestApiServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Inject
|
||||
AccessRestApiServlet(RestApiServlet.Globals globals,
|
||||
Provider<AccessCollection> access) {
|
||||
super(globals, access);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2013 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.access;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.IdString;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestCollection;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
public class AccessCollection implements
|
||||
RestCollection<TopLevelResource, AccessResource> {
|
||||
private final Provider<ListAccess> list;
|
||||
private final DynamicMap<RestView<AccessResource>> views;
|
||||
|
||||
@Inject
|
||||
AccessCollection(Provider<ListAccess> list,
|
||||
DynamicMap<RestView<AccessResource>> views) {
|
||||
this.list = list;
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestView<TopLevelResource> list() {
|
||||
return list.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessResource parse(TopLevelResource parent, IdString id)
|
||||
throws ResourceNotFoundException {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMap<RestView<AccessResource>> views() {
|
||||
return views;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2013 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.access;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.RestResource;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
public class AccessResource implements RestResource {
|
||||
public static final TypeLiteral<RestView<AccessResource>> ACCESS_KIND =
|
||||
new TypeLiteral<RestView<AccessResource>>() {};
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
// Copyright (C) 2013 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.access;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.common.data.RefConfigSection;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupControl;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.group.GroupJson;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.ProjectJson;
|
||||
import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.project.RefControl;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ListAccess implements RestReadView<TopLevelResource> {
|
||||
|
||||
@Option(name = "--project", aliases = {"-p"}, metaVar = "PROJECT",
|
||||
usage = "projects for which the access rights should be returned")
|
||||
private List<String> projects = Lists.newArrayList();
|
||||
|
||||
private final Provider<CurrentUser> self;
|
||||
private final ProjectControl.GenericFactory projectControlFactory;
|
||||
private final ProjectCache projectCache;
|
||||
private final ProjectJson projectJson;
|
||||
private final MetaDataUpdate.Server metaDataUpdateFactory;
|
||||
private final GroupControl.Factory groupControlFactory;
|
||||
private final GroupBackend groupBackend;
|
||||
private final AllProjectsName allProjectsName;
|
||||
|
||||
@Inject
|
||||
public ListAccess(Provider<CurrentUser> self,
|
||||
ProjectControl.GenericFactory projectControlFactory,
|
||||
ProjectCache projectCache, ProjectJson projectJson,
|
||||
MetaDataUpdate.Server metaDataUpdateFactory,
|
||||
GroupControl.Factory groupControlFactory, GroupBackend groupBackend,
|
||||
GroupJson groupJson, AllProjectsName allProjectsName) {
|
||||
this.self = self;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.projectCache = projectCache;
|
||||
this.projectJson = projectJson;
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
this.groupControlFactory = groupControlFactory;
|
||||
this.groupBackend = groupBackend;
|
||||
this.allProjectsName = allProjectsName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ProjectAccessInfo> apply(TopLevelResource resource)
|
||||
throws ResourceNotFoundException, ResourceConflictException, IOException {
|
||||
Map<String, ProjectAccessInfo> access = Maps.newTreeMap();
|
||||
for (String p: projects) {
|
||||
Project.NameKey projectName = new Project.NameKey(p);
|
||||
ProjectControl pc = open(projectName);
|
||||
ProjectConfig config;
|
||||
|
||||
try {
|
||||
// Load the current configuration from the repository, ensuring it's the most
|
||||
// recent version available. If it differs from what was in the project
|
||||
// state, force a cache flush now.
|
||||
//
|
||||
MetaDataUpdate md = metaDataUpdateFactory.create(projectName);
|
||||
try {
|
||||
config = ProjectConfig.read(md);
|
||||
|
||||
if (config.updateGroupNames(groupBackend)) {
|
||||
md.setMessage("Update group names\n");
|
||||
config.commit(md);
|
||||
projectCache.evict(config.getProject());
|
||||
pc = open(projectName);
|
||||
} else if (config.getRevision() != null
|
||||
&& !config.getRevision().equals(
|
||||
pc.getProjectState().getConfig().getRevision())) {
|
||||
projectCache.evict(config.getProject());
|
||||
pc = open(projectName);
|
||||
}
|
||||
} catch (ConfigInvalidException e) {
|
||||
throw new ResourceConflictException(e.getMessage());
|
||||
} finally {
|
||||
md.close();
|
||||
}
|
||||
} catch (RepositoryNotFoundException e) {
|
||||
throw new ResourceNotFoundException(p);
|
||||
}
|
||||
|
||||
access.put(p, new ProjectAccessInfo(pc, config));
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
private ProjectControl open(Project.NameKey projectName)
|
||||
throws ResourceNotFoundException, IOException {
|
||||
try {
|
||||
return projectControlFactory.validateFor(projectName,
|
||||
ProjectControl.OWNER | ProjectControl.VISIBLE, self.get());
|
||||
} catch (NoSuchProjectException e) {
|
||||
throw new ResourceNotFoundException(projectName.get());
|
||||
}
|
||||
}
|
||||
|
||||
public class ProjectAccessInfo {
|
||||
public String revision;
|
||||
public ProjectInfo inheritsFrom;
|
||||
public Map<String, AccessSectionInfo> local;
|
||||
public Set<String> ownerOf;
|
||||
public Boolean canUpload;
|
||||
public Boolean canAdd;
|
||||
public Boolean configVisible;
|
||||
|
||||
public ProjectAccessInfo(ProjectControl pc, ProjectConfig config) {
|
||||
final RefControl metaConfigControl =
|
||||
pc.controlForRef(GitRepositoryManager.REF_CONFIG);
|
||||
local = Maps.newHashMap();
|
||||
ownerOf = Sets.newHashSet();
|
||||
Map<AccountGroup.UUID, Boolean> visibleGroups =
|
||||
new HashMap<AccountGroup.UUID, Boolean>();
|
||||
|
||||
for (AccessSection section : config.getAccessSections()) {
|
||||
String name = section.getName();
|
||||
if (AccessSection.GLOBAL_CAPABILITIES.equals(name)) {
|
||||
if (pc.isOwner()) {
|
||||
local.put(name, new AccessSectionInfo(section));
|
||||
ownerOf.add(name);
|
||||
|
||||
} else if (metaConfigControl.isVisible()) {
|
||||
local.put(section.getName(), new AccessSectionInfo(section));
|
||||
}
|
||||
|
||||
} else if (RefConfigSection.isValid(name)) {
|
||||
RefControl rc = pc.controlForRef(name);
|
||||
if (rc.isOwner()) {
|
||||
local.put(name, new AccessSectionInfo(section));
|
||||
ownerOf.add(name);
|
||||
|
||||
} else if (metaConfigControl.isVisible()) {
|
||||
local.put(name, new AccessSectionInfo(section));
|
||||
|
||||
} else if (rc.isVisible()) {
|
||||
// Filter the section to only add rules describing groups that
|
||||
// are visible to the current-user. This includes any group the
|
||||
// user is a member of, as well as groups they own or that
|
||||
// are visible to all users.
|
||||
|
||||
AccessSection dst = null;
|
||||
for (Permission srcPerm : section.getPermissions()) {
|
||||
Permission dstPerm = null;
|
||||
|
||||
for (PermissionRule srcRule : srcPerm.getRules()) {
|
||||
AccountGroup.UUID group = srcRule.getGroup().getUUID();
|
||||
if (group == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Boolean canSeeGroup = visibleGroups.get(group);
|
||||
if (canSeeGroup == null) {
|
||||
try {
|
||||
canSeeGroup = groupControlFactory.controlFor(group).isVisible();
|
||||
} catch (NoSuchGroupException e) {
|
||||
canSeeGroup = Boolean.FALSE;
|
||||
}
|
||||
visibleGroups.put(group, canSeeGroup);
|
||||
}
|
||||
|
||||
if (canSeeGroup) {
|
||||
if (dstPerm == null) {
|
||||
if (dst == null) {
|
||||
dst = new AccessSection(name);
|
||||
local.put(name, new AccessSectionInfo(dst));
|
||||
}
|
||||
dstPerm = dst.getPermission(srcPerm.getName(), true);
|
||||
}
|
||||
dstPerm.add(srcRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ownerOf.isEmpty() && pc.isOwnerAnyRef()) {
|
||||
// Special case: If the section list is empty, this project has no current
|
||||
// access control information. Rely on what ProjectControl determines
|
||||
// is ownership, which probably means falling back to site administrators.
|
||||
ownerOf.add(AccessSection.ALL);
|
||||
}
|
||||
|
||||
|
||||
if (config.getRevision() != null) {
|
||||
revision = config.getRevision().name();
|
||||
}
|
||||
|
||||
ProjectState parent =
|
||||
Iterables.getFirst(pc.getProjectState().parents(), null);
|
||||
if (parent != null) {
|
||||
inheritsFrom = projectJson.format(parent.getProject());
|
||||
}
|
||||
|
||||
if (pc.getProject().getNameKey().equals(allProjectsName)) {
|
||||
if (pc.isOwner()) {
|
||||
ownerOf.add(AccessSection.GLOBAL_CAPABILITIES);
|
||||
}
|
||||
}
|
||||
|
||||
canUpload = toBoolean(pc.isOwner()
|
||||
|| (metaConfigControl.isVisible() && metaConfigControl.canUpload()));
|
||||
canAdd = toBoolean(pc.canAddRefs());
|
||||
configVisible = pc.isOwner() || metaConfigControl.isVisible();
|
||||
}
|
||||
}
|
||||
|
||||
public class AccessSectionInfo {
|
||||
public Map<String, PermissionInfo> permissions;
|
||||
|
||||
public AccessSectionInfo(AccessSection section) {
|
||||
permissions = Maps.newHashMap();
|
||||
for (Permission p : section.getPermissions()) {
|
||||
permissions.put(p.getName(), new PermissionInfo(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionInfo {
|
||||
public String label;
|
||||
public Boolean exclusive;
|
||||
public Map<String, PermissionRuleInfo> rules;
|
||||
|
||||
public PermissionInfo(Permission permission) {
|
||||
label = permission.getLabel();
|
||||
exclusive = toBoolean(permission.getExclusiveGroup());
|
||||
rules = Maps.newHashMap();
|
||||
for (PermissionRule r : permission.getRules()) {
|
||||
rules.put(r.getGroup().getUUID().get(), new PermissionRuleInfo(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionRuleInfo {
|
||||
public PermissionRule.Action action;
|
||||
public Boolean force;
|
||||
public Integer min;
|
||||
public Integer max;
|
||||
|
||||
|
||||
public PermissionRuleInfo(PermissionRule rule) {
|
||||
action = rule.getAction();
|
||||
force = toBoolean(rule.getForce());
|
||||
if (hasRange(rule)) {
|
||||
min = rule.getMin();
|
||||
max = rule.getMax();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRange(PermissionRule rule) {
|
||||
return (!(rule.getMin() == null || rule.getMin() == 0))
|
||||
|| (!(rule.getMax() == null || rule.getMax() == 0));
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean toBoolean(boolean value) {
|
||||
return value ? true : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2013 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.access;
|
||||
|
||||
import static com.google.gerrit.server.access.AccessResource.ACCESS_KIND;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
|
||||
public class Module extends RestApiModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(AccessCollection.class);
|
||||
|
||||
DynamicMap.mapOf(binder(), ACCESS_KIND);
|
||||
}
|
||||
}
|
||||
@@ -238,6 +238,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
bind(AccountControl.Factory.class);
|
||||
|
||||
install(new AuditModule());
|
||||
install(new com.google.gerrit.server.access.Module());
|
||||
install(new com.google.gerrit.server.account.Module());
|
||||
install(new com.google.gerrit.server.change.Module());
|
||||
install(new com.google.gerrit.server.config.Module());
|
||||
|
||||
@@ -70,6 +70,18 @@ public class ProjectControl {
|
||||
}
|
||||
return p.controlFor(user);
|
||||
}
|
||||
|
||||
public ProjectControl validateFor(Project.NameKey nameKey, int need,
|
||||
CurrentUser user) throws NoSuchProjectException, IOException {
|
||||
final ProjectControl c = controlFor(nameKey, user);
|
||||
if ((need & VISIBLE) == VISIBLE && c.isVisible()) {
|
||||
return c;
|
||||
}
|
||||
if ((need & OWNER) == OWNER && c.isOwner()) {
|
||||
return c;
|
||||
}
|
||||
throw new NoSuchProjectException(nameKey);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
|
||||
Reference in New Issue
Block a user