You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by xx...@apache.org on 2023/01/06 11:10:15 UTC

[kylin] 10/12: KYLIN-5356 Backend configuration of users supports the project administrator role

This is an automated email from the ASF dual-hosted git repository.

xxyu pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git

commit be5e5fa209fb26f8f5747ca3469403a46c8c6a13
Author: Liang.Hua <36...@users.noreply.github.com>
AuthorDate: Mon Oct 31 15:50:44 2022 +0800

    KYLIN-5356 Backend configuration of users supports the project administrator role
---
 .../rest/response/OpenAccessGroupResponse.java     |  40 +++++++
 .../rest/response/OpenAccessUserResponse.java      |  40 +++++++
 .../rest/controller/v2/NAccessControllerV2.java    | 124 ++++++++++++++++++--
 .../rest/controller/NAccessControllerV2Test.java   | 125 ++++++++++++++++++++-
 4 files changed, 316 insertions(+), 13 deletions(-)

diff --git a/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessGroupResponse.java b/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessGroupResponse.java
new file mode 100644
index 0000000000..96042b432f
--- /dev/null
+++ b/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessGroupResponse.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.kylin.rest.response;
+
+import java.util.List;
+
+import org.apache.kylin.common.util.Pair;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OpenAccessGroupResponse {
+
+    @JsonProperty("groups")
+    private List<Pair<String, Integer>> groups;
+
+    @JsonProperty("size")
+    private int size;
+}
diff --git a/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessUserResponse.java b/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessUserResponse.java
new file mode 100644
index 0000000000..c7f046bc57
--- /dev/null
+++ b/src/common-service/src/main/java/org/apache/kylin/rest/response/OpenAccessUserResponse.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.kylin.rest.response;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import org.apache.kylin.metadata.user.ManagedUser;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OpenAccessUserResponse {
+
+    @JsonProperty("users")
+    private List<ManagedUser> users;
+
+    @JsonProperty("size")
+    private int size;
+}
diff --git a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/v2/NAccessControllerV2.java b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/v2/NAccessControllerV2.java
index 2b9f9d2f4b..e4465dd69f 100644
--- a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/v2/NAccessControllerV2.java
+++ b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/v2/NAccessControllerV2.java
@@ -17,8 +17,8 @@
  */
 package org.apache.kylin.rest.controller.v2;
 
-import static org.apache.kylin.common.exception.ServerErrorCode.USER_NOT_EXIST;
 import static org.apache.kylin.common.constant.HttpConstant.HTTP_VND_APACHE_KYLIN_V2_JSON;
+import static org.apache.kylin.common.exception.ServerErrorCode.USER_NOT_EXIST;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -26,22 +26,35 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.exception.KylinException;
 import org.apache.kylin.common.persistence.AclEntity;
+import org.apache.kylin.common.util.Pair;
 import org.apache.kylin.metadata.model.TableDesc;
+import org.apache.kylin.metadata.project.NProjectManager;
+import org.apache.kylin.metadata.project.ProjectInstance;
 import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.controller.NBasicController;
 import org.apache.kylin.rest.response.AccessEntryResponse;
 import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.OpenAccessGroupResponse;
+import org.apache.kylin.rest.response.OpenAccessUserResponse;
+import org.apache.kylin.rest.security.AclEntityType;
 import org.apache.kylin.rest.service.AccessService;
+import org.apache.kylin.rest.service.AclTCRService;
+import org.apache.kylin.rest.service.IUserGroupService;
 import org.apache.kylin.rest.service.UserService;
+import org.apache.kylin.rest.util.AclEvaluate;
 import org.apache.kylin.rest.util.PagingUtil;
-import org.apache.kylin.rest.controller.NBasicController;
-import org.apache.kylin.rest.service.AclTCRService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.acls.domain.GrantedAuthoritySid;
+import org.springframework.security.acls.domain.PrincipalSid;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -49,6 +62,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.apache.kylin.metadata.user.ManagedUser;
 import io.swagger.annotations.ApiOperation;
 
 @Controller
@@ -63,18 +80,26 @@ public class NAccessControllerV2 extends NBasicController {
     @Qualifier("userService")
     protected UserService userService;
 
+    @Autowired
+    @Qualifier("userGroupService")
+    private IUserGroupService userGroupService;
+
     @Autowired
     @Qualifier("aclTCRService")
     private AclTCRService aclTCRService;
 
+    @Autowired
+    private AclEvaluate aclEvaluate;
+
     private static final String PROJECT_NAME = "project_name";
     private static final String TABLE_NAME = "table_name";
 
-    private void checkUserName(String userName) {
+    private ManagedUser checkAndGetUser(String userName) {
         if (!userService.userExists(userName)) {
             throw new KylinException(USER_NOT_EXIST,
                     String.format(Locale.ROOT, "User '%s' does not exists.", userName));
         }
+        return (ManagedUser) userService.loadUserByUsername(userName);
     }
 
     /**
@@ -89,7 +114,7 @@ public class NAccessControllerV2 extends NBasicController {
     @ResponseBody
     @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
     public EnvelopeResponse getAllAccessEntitiesOfUser(@PathVariable("userName") String username) throws IOException {
-        checkUserName(username);
+        checkAndGetUser(username);
 
         List<Object> dataList = new ArrayList<>();
         List<String> projectList = accessService.getGrantedProjectsOfUser(username);
@@ -115,13 +140,92 @@ public class NAccessControllerV2 extends NBasicController {
             @RequestParam(value = "pageOffset", required = false, defaultValue = "0") Integer pageOffset,
             @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize)
             throws IOException {
-        AclEntity ae = accessService.getAclEntity(type, getProject(project).getUuid());
-        List<AccessEntryResponse> resultsAfterFuzzyMatching = this.accessService.generateAceResponsesByFuzzMatching(ae,
-                nameSeg, isCaseSensitive);
-        List<AccessEntryResponse> sublist = PagingUtil.cutPage(resultsAfterFuzzyMatching, pageOffset, pageSize);
+        List<AccessEntryResponse> accessList = getAccessList(type, project, nameSeg, isCaseSensitive);
+        List<AccessEntryResponse> sublist = PagingUtil.cutPage(accessList, pageOffset, pageSize);
         HashMap<String, Object> data = new HashMap<>();
         data.put("sids", sublist);
-        data.put("size", resultsAfterFuzzyMatching.size());
+        data.put("size", accessList.size());
         return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, data, "");
     }
+
+    @ApiOperation(value = "getAllAccessUsers", tags = { "MID" })
+    @GetMapping(value = "/all/users", produces = { HTTP_VND_APACHE_KYLIN_V2_JSON })
+    @ResponseBody
+    public EnvelopeResponse<OpenAccessUserResponse> getAllAccessUsers(
+            @RequestParam(value = "project", required = false) String project,
+            @RequestParam(value = "userName", required = false) String userName,
+            @RequestParam(value = "pageOffset", required = false, defaultValue = "0") Integer pageOffset,
+            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize)
+            throws IOException {
+        Set<ManagedUser> users = StringUtils.isNotEmpty(userName) ? Sets.newHashSet(checkAndGetUser(userName))
+                : getUsersOfProjects(getGrantedProjects(project));
+        return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, new OpenAccessUserResponse(
+                PagingUtil.cutPage(Lists.newArrayList(users), pageOffset, pageSize), users.size()), "");
+    }
+
+    @ApiOperation(value = "getAllAccessGroups", tags = { "MID" })
+    @GetMapping(value = "/all/groups", produces = { HTTP_VND_APACHE_KYLIN_V2_JSON })
+    @ResponseBody
+    public EnvelopeResponse<OpenAccessGroupResponse> getAllAccessGroups(
+            @RequestParam(value = "project", required = false) String project,
+            @RequestParam(value = "groupName", required = false) String groupName,
+            @RequestParam(value = "pageOffset", required = false, defaultValue = "0") Integer pageOffset,
+            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize)
+            throws IOException {
+        List<Pair<String, Integer>> result = StringUtils.isNotEmpty(groupName)
+                ? Lists.newArrayList(Pair.newPair(groupName, userGroupService.getGroupMembersByName(groupName).size()))
+                : getUserGroupsOfProjects(getGrantedProjects(project));
+        return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, new OpenAccessGroupResponse(
+                PagingUtil.cutPage(Lists.newArrayList(result), pageOffset, pageSize), result.size()), "");
+    }
+
+    private List<AccessEntryResponse> getAccessList(String type, String projectName, String nameSeg,
+            boolean isCaseSensitive) throws IOException {
+        AclEntity aclEntity = accessService.getAclEntity(type, getProject(projectName).getUuid());
+        return this.accessService.generateAceResponsesByFuzzMatching(aclEntity, nameSeg, isCaseSensitive);
+    }
+
+    private List<String> getGrantedProjects(String projectName) {
+        NProjectManager projectManager = NProjectManager.getInstance(KylinConfig.getInstanceFromEnv());
+        if (StringUtils.isBlank(projectName)) {
+            return projectManager.listAllProjects().stream().map(ProjectInstance::getName)
+                    .filter(name -> aclEvaluate.hasProjectAdminPermission(name)).collect(Collectors.toList());
+        } else if (aclEvaluate.hasProjectReadPermission(projectManager.getProject(projectName))) {
+            return Lists.newArrayList(projectName);
+        }
+        return Lists.newArrayList();
+    }
+    
+    private Set<ManagedUser> getUsersOfProjects(List<String> projects) throws IOException {
+        Set<ManagedUser> allUsers = Sets.newHashSet();
+        for (String projectName : projects) {
+            List<AccessEntryResponse> responses = getAccessList(AclEntityType.PROJECT_INSTANCE, projectName, null,
+                    false);
+            allUsers.addAll(responses.stream().filter(response -> response.getSid() instanceof PrincipalSid)
+                    .map(response -> (ManagedUser) userService
+                            .loadUserByUsername(((PrincipalSid) response.getSid()).getPrincipal()))
+                    .collect(Collectors.toSet()));
+        }
+        return allUsers;
+    }
+
+    private List<Pair<String, Integer>> getUserGroupsOfProjects(List<String> projects) throws IOException {
+        List<Pair<String, Integer>> allUserGroups = Lists.newArrayList();
+        List<String> grantedGroups = Lists.newArrayList();
+        for (String projectName : projects) {
+            List<AccessEntryResponse> responses = getAccessList(AclEntityType.PROJECT_INSTANCE, projectName, null,
+                    false);
+            for (AccessEntryResponse response : responses) {
+                if (response.getSid() instanceof GrantedAuthoritySid) {
+                    String grantedAuthority = ((GrantedAuthoritySid) response.getSid()).getGrantedAuthority();
+                    if (!grantedGroups.contains(grantedAuthority)) {
+                        grantedGroups.add(grantedAuthority);
+                        allUserGroups.add(Pair.newPair(grantedAuthority,
+                                userGroupService.getGroupMembersByName(grantedAuthority).size()));
+                    }
+                }
+            }
+        }
+        return allUserGroups;
+    }
 }
diff --git a/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NAccessControllerV2Test.java b/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NAccessControllerV2Test.java
index 6aae71d82b..526ab7251d 100644
--- a/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NAccessControllerV2Test.java
+++ b/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NAccessControllerV2Test.java
@@ -19,12 +19,30 @@ package org.apache.kylin.rest.controller;
 
 import static org.apache.kylin.common.constant.HttpConstant.HTTP_VND_APACHE_KYLIN_V2_JSON;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.kylin.common.persistence.AclEntity;
+import org.apache.kylin.common.persistence.RootPersistentEntity;
+import org.apache.kylin.common.util.NLocalFileMetadataTestCase;
+import org.apache.kylin.metadata.project.NProjectManager;
+import org.apache.kylin.metadata.project.ProjectInstance;
 import org.apache.kylin.rest.constant.Constant;
-import org.apache.kylin.rest.service.AccessService;
-import org.apache.kylin.rest.service.UserService;
 import org.apache.kylin.rest.controller.v2.NAccessControllerV2;
+import org.apache.kylin.rest.response.AccessEntryResponse;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.OpenAccessGroupResponse;
+import org.apache.kylin.rest.response.OpenAccessUserResponse;
+import org.apache.kylin.rest.security.AclEntityType;
+import org.apache.kylin.rest.service.AccessService;
 import org.apache.kylin.rest.service.AclTCRService;
+import org.apache.kylin.rest.service.IUserGroupService;
+import org.apache.kylin.rest.service.ProjectService;
+import org.apache.kylin.rest.service.UserService;
+import org.apache.kylin.rest.util.AclEvaluate;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InjectMocks;
@@ -32,8 +50,11 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.springframework.http.MediaType;
+import org.springframework.security.acls.domain.GrantedAuthoritySid;
+import org.springframework.security.acls.domain.PrincipalSid;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@@ -42,7 +63,9 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import com.google.common.collect.Lists;
 
-public class NAccessControllerV2Test {
+import org.apache.kylin.metadata.user.ManagedUser;
+
+public class NAccessControllerV2Test extends NLocalFileMetadataTestCase {
 
     private MockMvc mockMvc;
 
@@ -55,6 +78,15 @@ public class NAccessControllerV2Test {
     @Mock
     private AclTCRService aclTCRService;
 
+    @Mock
+    private AclEvaluate aclEvaluate;
+
+    @Mock
+    private ProjectService projectService;
+
+    @Mock
+    private IUserGroupService userGroupService;
+
     @InjectMocks
     private NAccessControllerV2 nAccessControllerV2 = Mockito.spy(new NAccessControllerV2());
 
@@ -67,10 +99,12 @@ public class NAccessControllerV2Test {
                 .defaultRequest(MockMvcRequestBuilders.get("/")).build();
 
         SecurityContextHolder.getContext().setAuthentication(authentication);
+        createTestMetadata();
     }
 
     @After
     public void tearDown() {
+        cleanupTestMetadata();
     }
 
     @Test
@@ -88,4 +122,89 @@ public class NAccessControllerV2Test {
         Mockito.verify(nAccessControllerV2).getAllAccessEntitiesOfUser(userName);
     }
 
+    @Test
+    public void testGetAllAccessUsers() throws Exception {
+        String project = "default";
+        String userName = "user01";
+        mockMvc.perform(MockMvcRequestBuilders.get("/api/access/all/users").contentType(MediaType.APPLICATION_JSON)
+                .accept(MediaType.parseMediaType(HTTP_VND_APACHE_KYLIN_V2_JSON)))
+                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
+
+        Mockito.verify(nAccessControllerV2).getAllAccessUsers(null, null, 0, 10);
+
+        Mockito.doNothing().when(aclEvaluate).checkProjectAdminPermission(project);
+        mockMvc.perform(MockMvcRequestBuilders.get("/api/access/all/users").param("project", project)
+                .param("userName", userName).contentType(MediaType.APPLICATION_JSON)
+                .accept(MediaType.parseMediaType(HTTP_VND_APACHE_KYLIN_V2_JSON)))
+                .andExpect(MockMvcResultMatchers.status().is5xxServerError()).andReturn();
+
+        Mockito.verify(nAccessControllerV2).getAllAccessUsers(project, userName, 0, 10);
+
+        List<GrantedAuthority> authorities = new ArrayList<>();
+        ManagedUser user = new ManagedUser(userName, "123", false, authorities);
+        Authentication authentication = new TestingAuthenticationToken(user, userName, Constant.ROLE_ADMIN);
+        SecurityContextHolder.getContext().setAuthentication(authentication);
+        Mockito.doReturn(user).when(userService).loadUserByUsername(userName);
+        try {
+            nAccessControllerV2.getAllAccessUsers(project, userName, 0, 10);
+        } catch (Exception e) {
+            Assert.assertEquals(String.format(Locale.ROOT, "User '%s' does not exists.", userName), e.getMessage());
+        }
+
+        ProjectInstance projectInstance = NProjectManager.getInstance(getTestConfig()).getProject(project);
+        Mockito.doReturn(Lists.newArrayList(projectInstance)).when(projectService).getReadableProjects(project, true);
+        AccessEntryResponse accessEntryResponse = Mockito.mock(AccessEntryResponse.class);
+        AclEntity aclEntity = Mockito.mock(RootPersistentEntity.class);
+        PrincipalSid principalSid = Mockito.mock(PrincipalSid.class);
+        Mockito.doReturn(principalSid).when(accessEntryResponse).getSid();
+        Mockito.doReturn(userName).when(principalSid).getPrincipal();
+        Mockito.doReturn(aclEntity).when(accessService).getAclEntity(AclEntityType.PROJECT_INSTANCE,
+                projectInstance.getUuid());
+        Mockito.doReturn(Lists.newArrayList(accessEntryResponse)).when(accessService)
+                .generateAceResponsesByFuzzMatching(aclEntity, null, false);
+        EnvelopeResponse<OpenAccessUserResponse> envelopeResponse1 = nAccessControllerV2.getAllAccessUsers(project,
+                null, 0, 10);
+        Assert.assertNotNull(envelopeResponse1.getData());
+    }
+
+    @Test
+    public void testGetAllAccessGroups() throws Exception {
+        String project = "default";
+        String groupName = "group01";
+        mockMvc.perform(MockMvcRequestBuilders.get("/api/access/all/groups").contentType(MediaType.APPLICATION_JSON)
+                .accept(MediaType.parseMediaType(HTTP_VND_APACHE_KYLIN_V2_JSON)))
+                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
+        Mockito.verify(nAccessControllerV2).getAllAccessGroups(null, null, 0, 10);
+
+        mockMvc.perform(MockMvcRequestBuilders.get("/api/access/all/groups").param("project", project)
+                .param("groupName", groupName).contentType(MediaType.APPLICATION_JSON)
+                .accept(MediaType.parseMediaType(HTTP_VND_APACHE_KYLIN_V2_JSON)))
+                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
+
+        Mockito.verify(nAccessControllerV2).getAllAccessGroups(project, groupName, 0, 10);
+
+        List<GrantedAuthority> authorities = new ArrayList<>();
+        ManagedUser user = new ManagedUser("user", "123", false, authorities);
+        Authentication authentication = new TestingAuthenticationToken(user, "user", Constant.ROLE_ADMIN);
+        Mockito.doReturn(Lists.newArrayList(user)).when(userGroupService).getGroupMembersByName(groupName);
+        EnvelopeResponse<OpenAccessGroupResponse> envelopeResponse = nAccessControllerV2.getAllAccessGroups(project,
+                groupName, 0, 10);
+        Assert.assertNotNull(envelopeResponse.getData());
+
+        ProjectInstance projectInstance = NProjectManager.getInstance(getTestConfig()).getProject(project);
+        Mockito.doReturn(Lists.newArrayList(projectInstance)).when(projectService).getReadableProjects(project, true);
+        AccessEntryResponse accessEntryResponse = Mockito.mock(AccessEntryResponse.class);
+        AclEntity aclEntity = Mockito.mock(RootPersistentEntity.class);
+        GrantedAuthoritySid grantedAuthoritySid = Mockito.mock(GrantedAuthoritySid.class);
+        Mockito.doReturn(grantedAuthoritySid).when(accessEntryResponse).getSid();
+        Mockito.doReturn(groupName).when(grantedAuthoritySid).getGrantedAuthority();
+        Mockito.doReturn(aclEntity).when(accessService).getAclEntity(AclEntityType.PROJECT_INSTANCE,
+                projectInstance.getUuid());
+        Mockito.doReturn(Lists.newArrayList(accessEntryResponse)).when(accessService)
+                .generateAceResponsesByFuzzMatching(aclEntity, null, false);
+        EnvelopeResponse<OpenAccessGroupResponse> envelopeResponse1 = nAccessControllerV2.getAllAccessGroups(project,
+                null, 0, 10);
+        Assert.assertNotNull(envelopeResponse1.getData());
+    }
+
 }