Skip to content

Commit

Permalink
实现了权限精确到环境
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonywanted authored and nobodyiam committed Jul 23, 2018
1 parent a6563b8 commit cefdda6
Show file tree
Hide file tree
Showing 25 changed files with 752 additions and 215 deletions.
Expand Up @@ -27,7 +27,7 @@ public boolean hasModifyNamespacePermission(HttpServletRequest request, String a
}
return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request),
PermissionType.MODIFY_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
RoleUtils.buildNamespaceTargetId(appId, namespaceName, null));

}

Expand All @@ -38,7 +38,7 @@ public boolean hasReleaseNamespacePermission(HttpServletRequest request, String
}
return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request),
PermissionType.RELEASE_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
RoleUtils.buildNamespaceTargetId(appId, namespaceName, null));

}

Expand Down
Expand Up @@ -113,16 +113,16 @@ public Consumer getConsumerByConsumerId(long consumerId) {
}

@Transactional
public List<ConsumerRole> assignNamespaceRoleToConsumer(String token, String appId, String namespaceName) {
public List<ConsumerRole> assignNamespaceRoleToConsumer(String token, String appId, String namespaceName, String env) {
Long consumerId = getConsumerIdByToken(token);
if (consumerId == null) {
throw new BadRequestException("Token is Illegal");
}

Role namespaceModifyRole =
rolePermissionService.findRoleByRoleName(RoleUtils.buildModifyNamespaceRoleName(appId, namespaceName));
rolePermissionService.findRoleByRoleName(RoleUtils.buildModifyNamespaceRoleName(appId, namespaceName, env));
Role namespaceReleaseRole =
rolePermissionService.findRoleByRoleName(RoleUtils.buildReleaseNamespaceRoleName(appId, namespaceName));
rolePermissionService.findRoleByRoleName(RoleUtils.buildReleaseNamespaceRoleName(appId, namespaceName, env));

if (namespaceModifyRole == null || namespaceReleaseRole == null) {
throw new BadRequestException("Namespace's role does not exist. Please check whether namespace has created.");
Expand Down
Expand Up @@ -20,37 +20,37 @@ public class PermissionValidator {
@Autowired
private PortalConfig portalConfig;

public boolean hasModifyNamespacePermission(String appId, String namespaceName) {
public boolean hasModifyNamespacePermission(String appId, String namespaceName, String env) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.MODIFY_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
PermissionType.MODIFY_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName, env));
}

public boolean hasReleaseNamespacePermission(String appId, String namespaceName) {
public boolean hasReleaseNamespacePermission(String appId, String namespaceName, String env) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.RELEASE_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
PermissionType.RELEASE_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName, env));
}

public boolean hasDeleteNamespacePermission(String appId) {
return hasAssignRolePermission(appId) || isSuperAdmin();
}

public boolean hasOperateNamespacePermission(String appId, String namespaceName) {
return hasModifyNamespacePermission(appId, namespaceName) || hasReleaseNamespacePermission(appId, namespaceName);
public boolean hasOperateNamespacePermission(String appId, String namespaceName, String env) {
return hasModifyNamespacePermission(appId, namespaceName, env) || hasReleaseNamespacePermission(appId, namespaceName, env);
}

public boolean hasAssignRolePermission(String appId) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.ASSIGN_ROLE,
appId);
PermissionType.ASSIGN_ROLE,
appId);
}

public boolean hasCreateNamespacePermission(String appId) {

return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.CREATE_NAMESPACE,
appId);
PermissionType.CREATE_NAMESPACE,
appId);
}

public boolean hasCreateAppNamespacePermission(String appId, AppNamespace appNamespace) {
Expand All @@ -66,8 +66,8 @@ public boolean hasCreateAppNamespacePermission(String appId, AppNamespace appNam

public boolean hasCreateClusterPermission(String appId) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.CREATE_CLUSTER,
appId);
PermissionType.CREATE_CLUSTER,
appId);
}

public boolean isAppAdmin(String appId) {
Expand All @@ -77,4 +77,8 @@ public boolean isAppAdmin(String appId) {
public boolean isSuperAdmin() {
return rolePermissionService.isSuperAdmin(userInfoHolder.getUser().getUserId());
}

public boolean alwaysTrue() {
return true;
}
}
Expand Up @@ -104,7 +104,7 @@ public Email build(Env env, ReleaseHistoryBO releaseHistory) {

email.setSubject(subject());
email.setSenderEmailAddress(portalConfig.emailSender());
email.setRecipients(recipients(releaseHistory.getAppId(), releaseHistory.getNamespaceName()));
email.setRecipients(recipients(releaseHistory.getAppId(), releaseHistory.getNamespaceName(), env.toString()));

String emailBody = emailContent(env, releaseHistory);
//clear not used module
Expand Down Expand Up @@ -208,13 +208,19 @@ private ReleaseCompareResult getReleaseCompareResult(Env env, ReleaseHistoryBO r
return releaseService.compare(env, releaseHistory.getPreviousReleaseId(), releaseHistory.getReleaseId());
}

private List<String> recipients(String appId, String namespaceName) {
private List<String> recipients(String appId, String namespaceName, String env) {
Set<UserInfo> modifyRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.MODIFY_NAMESPACE));
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.MODIFY_NAMESPACE, null));
Set<UserInfo> envModifyRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.MODIFY_NAMESPACE, env));
Set<UserInfo> releaseRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE));
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE, null));
Set<UserInfo> envReleaseRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE, env));
Set<UserInfo> owners = rolePermissionService.queryUsersWithRole(RoleUtils.buildAppMasterRoleName(appId));

Set<String> userIds = new HashSet<>(modifyRoleUsers.size() + releaseRoleUsers.size() + owners.size());
Expand All @@ -223,10 +229,18 @@ private List<String> recipients(String appId, String namespaceName) {
userIds.add(userInfo.getUserId());
}

for (UserInfo userInfo : envModifyRoleUsers) {
userIds.add(userInfo.getUserId());
}

for (UserInfo userInfo : releaseRoleUsers) {
userIds.add(userInfo.getUserId());
}

for (UserInfo userInfo : envReleaseRoleUsers) {
userIds.add(userInfo.getUserId());
}

for (UserInfo userInfo : owners) {
userIds.add(userInfo.getUserId());
}
Expand Down
@@ -1,6 +1,9 @@
package com.ctrip.framework.apollo.portal.controller;


import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.portal.service.RoleInitializationService;

import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.http.MultiResponseEntity;
Expand Down Expand Up @@ -53,6 +56,8 @@ public class AppController {
private ApplicationEventPublisher publisher;
@Autowired
private RolePermissionService rolePermissionService;
@Autowired
private RoleInitializationService roleInitializationService;

@RequestMapping(value = "", method = RequestMethod.GET)
public List<App> findApps(@RequestParam(value = "appIds", required = false) String appIds) {
Expand Down Expand Up @@ -132,6 +137,8 @@ public ResponseEntity<Void> create(@PathVariable String env, @RequestBody App ap

appService.createAppInRemote(Env.valueOf(env), app);

roleInitializationService.initNamespaceSpecificEnvRoles(app.getAppId(), ConfigConsts.NAMESPACE_APPLICATION, env, userInfoHolder.getUser().getUserId());

return ResponseEntity.ok().build();
}

Expand Down
Expand Up @@ -2,6 +2,7 @@

import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.core.enums.EnvUtils;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.openapi.entity.Consumer;
import com.ctrip.framework.apollo.openapi.entity.ConsumerRole;
Expand All @@ -19,12 +20,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Objects;
import java.util.*;

/**
* @author Jason Song(song_s@ctrip.com)
Expand Down Expand Up @@ -69,6 +65,7 @@ public ConsumerToken getConsumerTokenByAppId(@RequestParam String appId) {
@RequestMapping(value = "/consumers/{token}/assign-role", method = RequestMethod.POST)
public List<ConsumerRole> assignNamespaceRoleToConsumer(@PathVariable String token,
@RequestParam String type,
@RequestParam(required = false) String envs,
@RequestBody NamespaceDTO namespace) {

String appId = namespace.getAppId();
Expand All @@ -77,14 +74,29 @@ public List<ConsumerRole> assignNamespaceRoleToConsumer(@PathVariable String tok
if (StringUtils.isEmpty(appId)) {
throw new BadRequestException("Params(AppId) can not be empty.");
}

if (Objects.equals("AppRole", type)) {
return Collections.singletonList(consumerService.assignAppRoleToConsumer(token, appId));
} else {
if (StringUtils.isEmpty(namespaceName)) {
throw new BadRequestException("Params(NamespaceName) can not be empty.");
}
return consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName);
if (null != envs){
String[] envList = envs.split(",");
// validate env parameter
for (String env : envList) {
if (null != env && !"".equals(env) && null == EnvUtils.transformEnv(env)) {
throw new BadRequestException(String.format("env: %s is illegal", env));
}
}

List<ConsumerRole> consumeRoles = new ArrayList<>();
for (String env : envList) {
consumeRoles.addAll(consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName, env));
}
return consumeRoles;
}

return consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName, null);
}
}

Expand Down
Expand Up @@ -4,15 +4,18 @@
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceSyncModel;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceTextModel;
import com.ctrip.framework.apollo.portal.entity.vo.ItemDiffs;
import com.ctrip.framework.apollo.portal.entity.vo.NamespaceIdentifier;
import com.ctrip.framework.apollo.portal.service.ItemService;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -34,8 +37,10 @@ public class ItemController {
private ItemService configService;
@Autowired
private UserInfoHolder userInfoHolder;
@Autowired
private PermissionValidator permissionValidator;

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, null) || @permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"})
public void modifyItemsByText(@PathVariable String appId, @PathVariable String env,
Expand All @@ -52,7 +57,7 @@ public void modifyItemsByText(@PathVariable String appId, @PathVariable String e
configService.updateConfigItemByText(model);
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, null) || @permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.POST)
public ItemDTO createItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand All @@ -71,7 +76,7 @@ public ItemDTO createItem(@PathVariable String appId, @PathVariable String env,
return configService.createItem(appId, Env.valueOf(env), clusterName, namespaceName, item);
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, null) || @permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item", method = RequestMethod.PUT)
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand All @@ -85,7 +90,7 @@ public void updateItem(@PathVariable String appId, @PathVariable String env,
}


@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, null) || @permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env) ")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}", method = RequestMethod.DELETE)
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand Down Expand Up @@ -134,15 +139,34 @@ public List<ItemDiffs> diff(@RequestBody NamespaceSyncModel model) {
return configService.compare(model.getSyncToNamespaces(), model.getSyncItems());
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
//@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName)")
@PreAuthorize(value="@permissionValidator.alwaysTrue()")
@RequestMapping(value = "/apps/{appId}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"})
public ResponseEntity<Void> update(@PathVariable String appId, @PathVariable String namespaceName,
public ResponseEntity update(@PathVariable String appId, @PathVariable String namespaceName,
@RequestBody NamespaceSyncModel model) {
checkModel(Objects.nonNull(model) && !model.isInvalid());

configService.syncItems(model.getSyncToNamespaces(), model.getSyncItems());
return ResponseEntity.status(HttpStatus.OK).build();
boolean hasPermission = permissionValidator.hasModifyNamespacePermission(appId, namespaceName, null);
Env envNoPermission = null;
// if uses has ModifyNamespace permission then he has permission
if (!hasPermission) {
// else check if user has every env's ModifyNamespace permission
hasPermission = true;
for (NamespaceIdentifier namespaceIdentifier : model.getSyncToNamespaces()) {
// once user has not one of the env's ModifyNamespace permission, then break the loop
hasPermission &= permissionValidator.hasModifyNamespacePermission(namespaceIdentifier.getAppId(), namespaceIdentifier.getNamespaceName(), namespaceIdentifier.getEnv().toString());
if (!hasPermission) {
envNoPermission = namespaceIdentifier.getEnv();
break;
}
}
}
if (hasPermission) {
configService.syncItems(model.getSyncToNamespaces(), model.getSyncItems());
return ResponseEntity.status(HttpStatus.OK).build();
}
else
throw new AccessDeniedException(String.format("您没有修改环境%s的权限", envNoPermission));
}

private boolean isValidItem(ItemDTO item) {
Expand Down

0 comments on commit cefdda6

Please sign in to comment.