Skip to content

Commit

Permalink
Merge pull request #1531 from nobodyiam/config-view-member-only
Browse files Browse the repository at this point in the history
Support displaying configs only to team members
  • Loading branch information
nobodyiam authored Oct 4, 2018
2 parents b3fb3fa + 1794d3d commit 5c16097
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.ctrip.framework.apollo.portal.constant.PermissionType;
import com.ctrip.framework.apollo.portal.service.AppNamespaceService;
import com.ctrip.framework.apollo.portal.service.RolePermissionService;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.util.RoleUtils;
Expand All @@ -18,6 +19,8 @@ public class PermissionValidator {
private RolePermissionService rolePermissionService;
@Autowired
private PortalConfig portalConfig;
@Autowired
private AppNamespaceService appNamespaceService;

public boolean hasModifyNamespacePermission(String appId, String namespaceName) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
Expand Down Expand Up @@ -94,4 +97,20 @@ public boolean isAppAdmin(String appId) {
public boolean isSuperAdmin() {
return rolePermissionService.isSuperAdmin(userInfoHolder.getUser().getUserId());
}

public boolean shouldHideConfigToCurrentUser(String appId, String env, String namespaceName) {
// 1. check whether the current environment enables member only function
if (!portalConfig.isConfigViewMemberOnly(env)) {
return false;
}

// 2. public namespace is open to every one
AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName);
if (appNamespace != null && appNamespace.isPublic()) {
return false;
}

// 3. check app admin and operate permissions
return !isAppAdmin(appId) && !hasOperateNamespacePermission(appId, namespaceName, env);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ public Set<Env> emailSupportedEnvs() {
return result;
}

public boolean isConfigViewMemberOnly(String env) {
String[] configViewMemberOnlyEnvs = getArrayProperty("configView.memberOnly.envs", new String[0]);

for (String memberOnlyEnv : configViewMemberOnlyEnvs) {
if (memberOnlyEnv.equalsIgnoreCase(env)) {
return true;
}
}

return false;
}

/***
* Level: normal
**/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.ctrip.framework.apollo.common.dto.CommitDTO;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.service.CommitService;

import java.util.Collections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -21,10 +23,16 @@ public class CommitController {
@Autowired
private CommitService commitService;

@Autowired
private PermissionValidator permissionValidator;

@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/commits", method = RequestMethod.GET)
public List<CommitDTO> find(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
return Collections.emptyList();
}

RequestPrecondition.checkNumberPositive(size);
RequestPrecondition.checkNumberNotNegative(page);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ctrip.framework.apollo.portal.controller;

import com.ctrip.framework.apollo.common.dto.ItemChangeSets;
import com.ctrip.framework.apollo.common.dto.ItemDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.core.enums.Env;
Expand Down Expand Up @@ -107,6 +108,10 @@ public List<ItemDTO> findItems(@PathVariable String appId, @PathVariable String
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestParam(defaultValue = "lineNum") String orderBy) {

if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
return Collections.emptyList();
}

List<ItemDTO> items = configService.findItems(appId, Env.valueOf(env), clusterName, namespaceName);
if ("lastModifiedTime".equals(orderBy)) {
Collections.sort(items, (o1, o2) -> {
Expand Down Expand Up @@ -136,7 +141,22 @@ public List<ItemDTO> findBranchItems(@PathVariable("appId") String appId, @PathV
public List<ItemDiffs> diff(@RequestBody NamespaceSyncModel model) {
checkModel(Objects.nonNull(model) && !model.isInvalid());

return configService.compare(model.getSyncToNamespaces(), model.getSyncItems());
List<ItemDiffs> itemDiffs = configService.compare(model.getSyncToNamespaces(), model.getSyncItems());

for (ItemDiffs diff : itemDiffs) {
NamespaceIdentifier namespace = diff.getNamespace();
if (namespace == null) {
continue;
}

if (permissionValidator
.shouldHideConfigToCurrentUser(namespace.getAppId(), namespace.getEnv().name(), namespace.getNamespaceName())) {
diff.setDiffs(new ItemChangeSets());
diff.setExtInfo("您不是该项目的管理员,也没有该Namespace在 " + namespace.getEnv() + " 环境的编辑或发布权限");
}
}

return itemDiffs;
}

@RequestMapping(value = "/apps/{appId}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ public NamespaceBO findBranch(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName) {
return namespaceBranchService.findBranch(appId, Env.valueOf(env), clusterName, namespaceName);
NamespaceBO namespaceBO = namespaceBranchService.findBranch(appId, Env.valueOf(env), clusterName, namespaceName);

if (namespaceBO != null && permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
namespaceBO.hideItems();
}

return namespaceBO;
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.listener.AppNamespaceDeletionEvent;
import com.google.common.collect.Sets;

Expand Down Expand Up @@ -62,6 +63,8 @@ public class NamespaceController {
private RolePermissionService rolePermissionService;
@Autowired
private PortalConfig portalConfig;
@Autowired
private PermissionValidator permissionValidator;


@RequestMapping(value = "/appnamespaces/public", method = RequestMethod.GET)
Expand All @@ -73,14 +76,28 @@ public List<AppNamespace> findPublicAppNamespaces() {
public List<NamespaceBO> findNamespaces(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName) {

return namespaceService.findNamespaceBOs(appId, Env.valueOf(env), clusterName);
List<NamespaceBO> namespaceBOs = namespaceService.findNamespaceBOs(appId, Env.valueOf(env), clusterName);

for (NamespaceBO namespaceBO : namespaceBOs) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceBO.getBaseInfo().getNamespaceName())) {
namespaceBO.hideItems();
}
}

return namespaceBOs;
}

@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName:.+}", method = RequestMethod.GET)
public NamespaceBO findNamespace(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName) {

return namespaceService.loadNamespaceBO(appId, Env.valueOf(env), clusterName, namespaceName);
NamespaceBO namespaceBO = namespaceService.loadNamespaceBO(appId, Env.valueOf(env), clusterName, namespaceName);

if (namespaceBO != null && permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
namespaceBO.hideItems();
}

return namespaceBO;
}

@RequestMapping(value = "/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/associated-public-namespace",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.ctrip.framework.apollo.portal.listener.ConfigPublishEvent;
import com.ctrip.framework.apollo.portal.service.ReleaseService;

import java.util.Collections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.AccessDeniedException;
Expand Down Expand Up @@ -113,6 +114,9 @@ public List<ReleaseBO> findAllReleases(@PathVariable String appId,
@PathVariable String namespaceName,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "5") int size) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
return Collections.emptyList();
}

RequestPrecondition.checkNumberPositive(size);
RequestPrecondition.checkNumberNotNegative(page);
Expand All @@ -128,6 +132,10 @@ public List<ReleaseDTO> findActiveReleases(@PathVariable String appId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "5") int size) {

if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
return Collections.emptyList();
}

RequestPrecondition.checkNumberPositive(size);
RequestPrecondition.checkNumberNotNegative(page);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@


import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import com.ctrip.framework.apollo.portal.service.ReleaseHistoryService;

import java.util.Collections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -19,6 +21,8 @@ public class ReleaseHistoryController {

@Autowired
private ReleaseHistoryService releaseHistoryService;
@Autowired
private PermissionValidator permissionValidator;

@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases/histories",
method = RequestMethod.GET)
Expand All @@ -29,6 +33,10 @@ public List<ReleaseHistoryBO> findReleaseHistoriesByNamespace(@PathVariable Stri
@RequestParam(value = "page", defaultValue = "0") int page,
@RequestParam(value = "size", defaultValue = "10") int size) {

if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
return Collections.emptyList();
}

return releaseHistoryService.findNamespaceReleaseHistory(appId, Env.valueOf(env), clusterName ,namespaceName, page, size);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public class NamespaceBO {
private boolean isPublic;
private String parentAppId;
private String comment;

// is the configs hidden to current user?
private boolean isConfigHidden;

public NamespaceDTO getBaseInfo() {
return baseInfo;
Expand Down Expand Up @@ -70,4 +71,17 @@ public void setComment(String comment) {
this.comment = comment;
}

public boolean isConfigHidden() {
return isConfigHidden;
}

public void setConfigHidden(boolean hidden) {
isConfigHidden = hidden;
}

public void hideItems() {
setConfigHidden(true);
items.clear();
setItemModifiedCnt(0);
}
}
7 changes: 4 additions & 3 deletions apollo-portal/src/main/resources/static/config/history.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ <h4>发布历史</h4>

</div>

<div class="release-history-container panel-body row" ng-show="releaseHistories && releaseHistories.length > 0">
<div class="release-history-container panel-body row" ng-show="!isConfigHidden && releaseHistories && releaseHistories.length > 0">
<div class="release-history-list col-md-3">

<div class="media hover" ng-class="{'active': releaseHistory.id == selectedReleaseHistory}"
Expand Down Expand Up @@ -232,8 +232,9 @@ <h5 class="text-center empty-container" ng-show="!history.operationContext.rules

</div>

<div class="panel-body" ng-show="!releaseHistories || releaseHistories.length == 0">
<h4 class="text-center empty-container">无发布历史信息</h4>
<div class="panel-body" ng-show="isConfigHidden || !releaseHistories || releaseHistories.length == 0">
<h4 class="text-center empty-container" ng-show="isConfigHidden">您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看发布历史</h4>
<h4 class="text-center empty-container" ng-show="!isConfigHidden">无发布历史信息</h4>
</div>
</section>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ function releaseHistoryController($scope, $location, AppUtil,
$scope.hasLoadAll = false;
$scope.selectedReleaseHistory = 0;
$scope.isTextNamespace = false;
// whether current user can view config
$scope.isConfigHidden = false;

$scope.showReleaseHistoryDetail = showReleaseHistoryDetail;
$scope.switchConfigViewType = switchConfigViewType;
Expand Down Expand Up @@ -99,6 +101,7 @@ function releaseHistoryController($scope, $location, AppUtil,
if ($scope.isTextNamespace) {
fixTextNamespaceViewType();
}
$scope.isConfigHidden = result.isConfigHidden;
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@
</header>

<div id="BODY{{namespace.branch.id}}" class="collapse in">
<div class="J_namespace-release-tip well well-sm no-radius text-center"
ng-show="namespace.isConfigHidden">
<span style="color: red">您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看配置信息。</span>
</div>

<!--second header-->
<header class="panel-heading second-panel-heading">
<header class="panel-heading second-panel-heading" ng-show="!namespace.isConfigHidden">
<div class="row">
<div class="col-md-12 pull-left">
<ul class="nav nav-tabs">
Expand Down Expand Up @@ -92,7 +97,7 @@
</div>
</header>
<!--namespace body-->
<section>
<section ng-show="!namespace.isConfigHidden">
<!--items-->
<div class="namespace-view-table" ng-show="namespace.branch.viewType == 'table'">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,16 @@
</div>
</header>



<div id="BODY{{namespace.id}}" class="collapse in">
<div class="J_namespace-release-tip well well-sm no-radius text-center"
ng-show="namespace.isConfigHidden">
<span style="color: red">您不是该项目的管理员,也没有该Namespace的编辑或发布权限,无法查看配置信息。</span>
</div>

<!--second header-->
<header class="panel-heading second-panel-heading">
<header class="panel-heading second-panel-heading" ng-show="!namespace.isConfigHidden">
<div class="row">
<div class="col-md-6 col-sm-6 pull-left">
<!--master branch nav tabs-->
Expand Down Expand Up @@ -182,7 +189,7 @@
</header>

<!--namespace body-->
<section>
<section ng-show="!namespace.isConfigHidden">
<!--table view-->
<div class="namespace-view-table" ng-show="namespace.viewType == 'table'">

Expand Down
3 changes: 2 additions & 1 deletion scripts/apollo-on-kubernetes/db/portal-db/apolloportaldb.sql
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ VALUES
('superAdmin', 'apollo', 'Portal超级管理员'),
('api.readTimeout', '10000', 'http接口read timeout'),
('consumer.token.salt', 'someSalt', 'consumer token salt'),
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace');
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'),
('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔');

INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`)
VALUES
Expand Down
4 changes: 3 additions & 1 deletion scripts/sql/apolloportaldb.sql
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,9 @@ VALUES
('superAdmin', 'apollo', 'Portal超级管理员'),
('api.readTimeout', '10000', 'http接口read timeout'),
('consumer.token.salt', 'someSalt', 'consumer token salt'),
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace');
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'),
('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔');


INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`)
VALUES
Expand Down

0 comments on commit 5c16097

Please sign in to comment.