Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(Auth): Authorization by Env Cluster #5302

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2c3923d
feat(auth): finish get/assign/remove web-api and some name generator
BlackBear2003 Dec 23, 2024
0535f95
feat(auth): permissionValidator and Initialization logic finished.
BlackBear2003 Dec 24, 2024
3a1e0f0
feat(auth): sift role initialize from controller to service
BlackBear2003 Dec 25, 2024
d37e949
feat(auth): add integration test for checking permission
BlackBear2003 Dec 25, 2024
976a0f5
feat(auth): add unit test for role initialization
BlackBear2003 Dec 25, 2024
c14aae7
feat(auth): rename
BlackBear2003 Dec 25, 2024
5998a68
feat(auth): finish Integration Test of Cluster roles management.
BlackBear2003 Dec 25, 2024
b677dab
feat(auth): add Licenses
BlackBear2003 Dec 26, 2024
6f40c22
feat(auth): add hasClusterPermission API
BlackBear2003 Dec 26, 2024
82d017a
feat(auth): finish front-end logic
BlackBear2003 Dec 26, 2024
73bf1d7
feat(auth): finish front-end logic
BlackBear2003 Dec 27, 2024
82458af
feat(auth): add i18n
BlackBear2003 Dec 27, 2024
6e2c952
feat(auth): fix unit test
BlackBear2003 Dec 27, 2024
31aed0f
feat(auth): fix unit test
BlackBear2003 Dec 27, 2024
90ffd8b
feat(auth):
BlackBear2003 Jan 1, 2025
0a2822a
feat(auth):
BlackBear2003 Jan 1, 2025
a6ccfcf
feat(auth):
BlackBear2003 Jan 1, 2025
b650484
chore(auth): rename NamespaceInCluster to NamespacesInCluster
BlackBear2003 Jan 3, 2025
1766f0c
chore(auth): fix some bugs and code style
BlackBear2003 Jan 3, 2025
38464fa
bugfix(auth): fix js call non-exist method
BlackBear2003 Jan 3, 2025
238859f
bugfix(auth): fix i18n ch wrong translation
BlackBear2003 Jan 5, 2025
142b9ef
feat(auth): add cluster_manage page
BlackBear2003 Jan 8, 2025
88ce290
feat(auth): fix some naming error and bugs
BlackBear2003 Jan 11, 2025
4c90c18
feat(auth): rename
BlackBear2003 Jan 12, 2025
e0f97fe
docs(auth): add docs for namespace permission management
BlackBear2003 Jan 12, 2025
14691d8
docs(auth): add en docs
BlackBear2003 Jan 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,42 +48,75 @@ public PermissionValidator(
this.systemRoleManagerService = systemRoleManagerService;
}

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

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

public boolean hasReleaseNamespacePermission(String appId, String namespaceName) {
private boolean hasModifyNamespacesInClusterPermission(String appId, String env, String clusterName) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.MODIFY_NAMESPACES_IN_CLUSTER,
RoleUtils.buildClusterTargetId(appId, env, clusterName));
}

public boolean hasModifyNamespacePermission(String appId, String env, String clusterName, String namespaceName) {
if (hasModifyNamespacePermission(appId, namespaceName)) {
return true;
}
if (hasModifyNamespacePermission(appId, namespaceName, env)) {
return true;
}
if (hasModifyNamespacesInClusterPermission(appId, env, clusterName)) {
return true;
}
return false;
}

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

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

private boolean hasReleaseNamespacesInClusterPermission(String appId, String env, String clusterName) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.RELEASE_NAMESPACES_IN_CLUSTER,
RoleUtils.buildClusterTargetId(appId, env, clusterName));
}

public boolean hasDeleteNamespacePermission(String appId) {
return hasAssignRolePermission(appId) || isSuperAdmin();
public boolean hasReleaseNamespacePermission(String appId, String env, String clusterName, String namespaceName) {
if (hasReleaseNamespacePermission(appId, namespaceName)) {
return true;
}
if (hasReleaseNamespacePermission(appId, namespaceName, env)) {
return true;
}
if (hasReleaseNamespacesInClusterPermission(appId, env, clusterName)) {
return true;
}
return false;
}

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

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

public boolean hasAssignRolePermission(String appId) {
Expand Down Expand Up @@ -124,7 +157,8 @@ public boolean isSuperAdmin() {
return rolePermissionService.isSuperAdmin(userInfoHolder.getUser().getUserId());
}

public boolean shouldHideConfigToCurrentUser(String appId, String env, String namespaceName) {
public boolean shouldHideConfigToCurrentUser(String appId, String env, String clusterName,
String namespaceName) {
// 1. check whether the current environment enables member only function
if (!portalConfig.isConfigViewMemberOnly(env)) {
return false;
Expand All @@ -137,7 +171,7 @@ public boolean shouldHideConfigToCurrentUser(String appId, String env, String na
}

// 3. check app admin and operate permissions
return !isAppAdmin(appId) && !hasOperateNamespacePermission(appId, namespaceName, env);
return !isAppAdmin(appId) && !hasOperateNamespacePermission(appId, env, clusterName, namespaceName);
}

public boolean hasCreateApplicationPermission() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@ public interface PermissionType {

String RELEASE_NAMESPACE = "ReleaseNamespace";

String MODIFY_NAMESPACES_IN_CLUSTER = "ModifyNamespacesInCluster";

String RELEASE_NAMESPACES_IN_CLUSTER = "ReleaseNamespacesInCluster";

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ public class RoleType {

public static final String RELEASE_NAMESPACE = "ReleaseNamespace";

public static final String MODIFY_NAMESPACES_IN_CLUSTER = "ModifyNamespacesInCluster";

public static final String RELEASE_NAMESPACES_IN_CLUSTER = "ReleaseNamespacesInCluster";

public static boolean isValidRoleType(String roleType) {
return MASTER.equals(roleType) || MODIFY_NAMESPACE.equals(roleType) || RELEASE_NAMESPACE.equals(roleType);
return MASTER.equals(roleType) || MODIFY_NAMESPACE.equals(roleType) || RELEASE_NAMESPACE.equals(
roleType) || MODIFY_NAMESPACES_IN_CLUSTER.equals(roleType) || RELEASE_NAMESPACES_IN_CLUSTER.equals(roleType);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public List<CommitDTO> find(@PathVariable String appId, @PathVariable String env
@RequestParam(required = false) String key,
@Valid @PositiveOrZero(message = "page should be positive or 0") @RequestParam(defaultValue = "0") int page,
@Valid @Positive(message = "size should be positive number") @RequestParam(defaultValue = "10") int size) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceName)) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName, namespaceName)) {
nobodyiam marked this conversation as resolved.
Show resolved Hide resolved
return Collections.emptyList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public ConfigsExportController(
* application.json
* </pre>
*/
@PreAuthorize(value = "!@permissionValidator.shouldHideConfigToCurrentUser(#appId, #env, #namespaceName)")
@PreAuthorize(value = "!@permissionValidator.shouldHideConfigToCurrentUser(#appId, #env, #clusterName, #namespaceName)")
@GetMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/export")
public void exportItems(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public ConfigsImportController(
* etc.
* @throws IOException
*/
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PostMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/import")
public void importConfigFile(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public ItemController(final ItemService configService, final UserInfoHolder user
this.namespaceService = namespaceService;
}

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

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PostMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item")
public ItemDTO createItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand All @@ -106,7 +106,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, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PutMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item")
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand All @@ -120,7 +120,7 @@ public void updateItem(@PathVariable String appId, @PathVariable String env,
}


@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env) ")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@DeleteMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}")
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
Expand All @@ -142,7 +142,7 @@ 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)) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName, namespaceName)) {
return Collections.emptyList();
}

Expand Down Expand Up @@ -183,9 +183,10 @@ public List<ItemDiffs> diff(@RequestBody NamespaceSyncModel model) {
}

if (permissionValidator
.shouldHideConfigToCurrentUser(namespace.getAppId(), namespace.getEnv().getName(), namespace.getNamespaceName())) {
.shouldHideConfigToCurrentUser(namespace.getAppId(), namespace.getEnv().getName(),
namespace.getClusterName(), namespace.getNamespaceName())) {
diff.setDiffs(new ItemChangeSets());
diff.setExtInfo("You are not this project's administrator, nor you have edit or release permission for the namespace in environment: " + namespace.getEnv());
diff.setExtInfo("You are not this project's administrator, nor you have edit or release permission for the namespace: " + namespace);
}
}

Expand All @@ -196,29 +197,30 @@ public List<ItemDiffs> diff(@RequestBody NamespaceSyncModel model) {
public ResponseEntity<Void> update(@PathVariable String appId, @PathVariable String namespaceName,
@RequestBody NamespaceSyncModel model) {
checkModel(!model.isInvalid() && model.syncToNamespacesValid(appId, namespaceName));
boolean hasPermission = permissionValidator.hasModifyNamespacePermission(appId, namespaceName);
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;
}
NamespaceIdentifier noPermissionNamespace = null;
// check if user has every namespace's ModifyNamespace permission
boolean hasPermission = true;
for (NamespaceIdentifier namespaceIdentifier : model.getSyncToNamespaces()) {
// once user has not one of the namespace's ModifyNamespace permission, then break the loop
hasPermission = permissionValidator.hasModifyNamespacePermission(
namespaceIdentifier.getAppId(),
namespaceIdentifier.getEnv().getName(),
namespaceIdentifier.getClusterName(),
namespaceIdentifier.getNamespaceName()
);
if (!hasPermission) {
noPermissionNamespace = namespaceIdentifier;
break;
}
}
if (hasPermission) {
configService.syncItems(model.getSyncToNamespaces(), model.getSyncItems());
return ResponseEntity.status(HttpStatus.OK).build();
}
throw new AccessDeniedException(String.format("You don't have the permission to modify environment: %s", envNoPermission));
throw new AccessDeniedException(String.format("You don't have the permission to modify namespace: %s", noPermissionNamespace));
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PostMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/syntax-check", consumes = {
"application/json"})
public ResponseEntity<Void> syntaxCheckText(@PathVariable String appId, @PathVariable String env,
Expand All @@ -229,7 +231,7 @@ public ResponseEntity<Void> syntaxCheckText(@PathVariable String appId, @PathVar
return ResponseEntity.ok().build();
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PutMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/revoke-items")
public void revokeItems(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ public NamespaceBO findBranch(@PathVariable String appId,
@PathVariable String namespaceName) {
NamespaceBO namespaceBO = namespaceBranchService.findBranch(appId, Env.valueOf(env), clusterName, namespaceName);

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

return namespaceBO;
}

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PostMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches")
@ApolloAuditLog(type = OpType.CREATE, name = "NamespaceBranch.create")
public NamespaceDTO createBranch(@PathVariable String appId,
Expand All @@ -97,9 +97,10 @@ public void deleteBranch(@PathVariable String appId,
@PathVariable String namespaceName,
@PathVariable String branchName) {

boolean canDelete = permissionValidator.hasReleaseNamespacePermission(appId, namespaceName, env) ||
(permissionValidator.hasModifyNamespacePermission(appId, namespaceName, env) &&
releaseService.loadLatestRelease(appId, Env.valueOf(env), branchName, namespaceName) == null);
boolean hasModifyPermission = permissionValidator.hasModifyNamespacePermission(appId, env, clusterName, namespaceName);
boolean hasReleasePermission = permissionValidator.hasReleaseNamespacePermission(appId, env, clusterName, namespaceName);
boolean canDelete = hasReleasePermission
|| (hasModifyPermission && releaseService.loadLatestRelease(appId, Env.valueOf(env), branchName, namespaceName) == null);


if (!canDelete) {
Expand All @@ -115,7 +116,7 @@ public void deleteBranch(@PathVariable String appId,



@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PostMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge")
@ApolloAuditLog(type = OpType.UPDATE, name = "NamespaceBranch.merge")
public ReleaseDTO merge(@PathVariable String appId, @PathVariable String env,
Expand Down Expand Up @@ -155,7 +156,7 @@ public GrayReleaseRuleDTO getBranchGrayRules(@PathVariable String appId, @PathVa
}


@PreAuthorize(value = "@permissionValidator.hasOperateNamespacePermission(#appId, #namespaceName, #env)")
@PreAuthorize(value = "@permissionValidator.hasOperateNamespacePermission(#appId, #env, #clusterName, #namespaceName)")
@PutMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules")
@ApolloAuditLog(type = OpType.UPDATE, name = "NamespaceBranch.updateBranchRules")
public void updateBranchRules(@PathVariable String appId, @PathVariable String env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public List<NamespaceBO> findNamespaces(@PathVariable String appId, @PathVariabl
List<NamespaceBO> namespaceBOs = namespaceService.findNamespaceBOs(appId, Env.valueOf(env), clusterName);

for (NamespaceBO namespaceBO : namespaceBOs) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, namespaceBO.getBaseInfo().getNamespaceName())) {
if (permissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName, namespaceBO.getBaseInfo().getNamespaceName())) {
namespaceBO.hideItems();
}
}
Expand All @@ -125,7 +125,7 @@ public NamespaceBO findNamespace(@PathVariable String appId, @PathVariable Strin

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

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

Expand Down
Loading
Loading