This is an automated email from the ASF dual-hosted git repository. billyliu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/kylin.git
commit fde86c2d67bdc08b057ab31698a7b01986518b34 Author: Jiatao Tao <245915...@qq.com> AuthorDate: Thu Feb 8 20:56:36 2018 +0800 KYLIN-3248, add batch grant API for project ACL. minor, change the batch reqs. --- .../kylin/rest/controller/AccessController.java | 25 ++++++++++++++++++++ .../apache/kylin/rest/service/AccessService.java | 26 ++++++++++++++++++--- .../org/apache/kylin/rest/service/AclService.java | 11 +++++++++ .../kylin/rest/service/AccessServiceTest.java | 20 ++++++++++++++++ .../apache/kylin/rest/service/AclServiceTest.java | 27 ++++++++++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java index 56cae10..b9a00b3 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java +++ b/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java @@ -20,8 +20,11 @@ package org.apache.kylin.rest.controller; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import com.google.common.base.Preconditions; import org.apache.kylin.common.persistence.AclEntity; import org.apache.kylin.common.util.Pair; import org.apache.kylin.metadata.MetadataConstants; @@ -156,6 +159,28 @@ public class AccessController extends BasicController implements InitializingBea } /** + * Batch API.Grant a new access on a domain object to a user/role + */ + @RequestMapping(value = "batch/{type}/{uuid}", method = { RequestMethod.POST }, produces = { "application/json" }) + @ResponseBody + public void batchGrant(@PathVariable String type, @PathVariable String uuid, + @RequestBody List<Object[]> reqs) throws IOException { + Map<Sid, Permission> sidToPerm = new HashMap<>(); + AclEntity ae = accessService.getAclEntity(type, uuid); + for (Object[] req : reqs) { + Preconditions.checkArgument(req.length == 3, "error access requests."); + String name = (String) req[0]; + boolean isPrincipal = (boolean) req[1]; + validateUtil.checkIdentifiersExists(name, isPrincipal); + + Sid sid = accessService.getSid(name, isPrincipal); + Permission permission = AclPermissionFactory.getPermission((String) req[2]); + sidToPerm.put(sid, permission); + } + accessService.batchGrant(ae, sidToPerm); + } + + /** * Update a access on a domain object * * @param accessRequest diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/AccessService.java b/server-base/src/main/java/org/apache/kylin/rest/service/AccessService.java index 09a89c8..dfac275 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/AccessService.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/AccessService.java @@ -100,6 +100,29 @@ public class AccessService { @Transactional @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#ae, 'ADMINISTRATION')") + public void batchGrant(AclEntity ae, Map<Sid, Permission> sidToPerm) { + Message msg = MsgPicker.getMsg(); + + if (ae == null) + throw new BadRequestException(msg.getACL_DOMAIN_NOT_FOUND()); + if (sidToPerm == null) + throw new BadRequestException(msg.getACL_PERMISSION_REQUIRED()); + + MutableAclRecord acl; + try { + acl = aclService.readAcl(new ObjectIdentityImpl(ae)); + } catch (NotFoundException e) { + acl = init(ae, null); + } + + for (Sid sid : sidToPerm.keySet()) { + secureOwner(acl, sid); + } + aclService.batchUpsertAce(acl, sidToPerm); + } + + @Transactional + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#ae, 'ADMINISTRATION')") public MutableAclRecord grant(AclEntity ae, Permission permission, Sid sid) { Message msg = MsgPicker.getMsg(); @@ -304,9 +327,6 @@ public class AccessService { /** * Protect admin permission granted to acl owner. - * - * @param acl - * @param indexOfAce */ private void secureOwner(MutableAclRecord acl, Sid sid) { Message msg = MsgPicker.getMsg(); diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/AclService.java b/server-base/src/main/java/org/apache/kylin/rest/service/AclService.java index adc7c30..f3e2393 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/AclService.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/AclService.java @@ -243,6 +243,17 @@ public class AclService implements MutableAclService, InitializingBean { }); } + void batchUpsertAce(MutableAclRecord acl, final Map<Sid, Permission> sidToPerm) { + updateAclWithRetry(acl, new AclRecordUpdater() { + @Override + public void update(AclRecord record) { + for (Sid sid : sidToPerm.keySet()) { + record.upsertAce(sidToPerm.get(sid), sid); + } + } + }); + } + MutableAclRecord inherit(MutableAclRecord acl, final MutableAclRecord parentAcl) { return updateAclWithRetry(acl, new AclRecordUpdater() { @Override diff --git a/server/src/test/java/org/apache/kylin/rest/service/AccessServiceTest.java b/server/src/test/java/org/apache/kylin/rest/service/AccessServiceTest.java index 8f18ed1..52f5cd2 100644 --- a/server/src/test/java/org/apache/kylin/rest/service/AccessServiceTest.java +++ b/server/src/test/java/org/apache/kylin/rest/service/AccessServiceTest.java @@ -22,7 +22,9 @@ import static org.apache.kylin.rest.security.AclEntityType.PROJECT_INSTANCE; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.kylin.common.persistence.AclEntity; import org.apache.kylin.common.persistence.RootPersistentEntity; @@ -31,6 +33,7 @@ import org.apache.kylin.metadata.project.ProjectInstance; import org.apache.kylin.rest.response.AccessEntryResponse; import org.apache.kylin.rest.security.AclPermission; import org.apache.kylin.rest.security.AclPermissionFactory; +import org.apache.kylin.rest.security.springacl.MutableAclRecord; import org.apache.kylin.rest.service.AclServiceTest.MockAclEntity; import org.junit.Assert; import org.junit.Ignore; @@ -40,6 +43,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.acls.domain.PrincipalSid; import org.springframework.security.acls.model.AccessControlEntry; import org.springframework.security.acls.model.Acl; +import org.springframework.security.acls.model.Permission; import org.springframework.security.acls.model.Sid; import com.fasterxml.jackson.core.JsonProcessingException; @@ -148,6 +152,22 @@ public class AccessServiceTest extends ServiceTestBase { Assert.assertNull(attachedEntityAcl); } + @Test + public void testBatchGrant() { + AclEntity ae = new AclServiceTest.MockAclEntity("batch-grant"); + final Map<Sid, Permission> sidToPerm = new HashMap<>(); + for (int i = 0; i < 10; i++) { + sidToPerm.put(new PrincipalSid("u" + i), AclPermission.ADMINISTRATION); + } + accessService.batchGrant(ae, sidToPerm); + MutableAclRecord acl = accessService.getAcl(ae); + List<AccessControlEntry> e = acl.getEntries(); + Assert.assertEquals(10, e.size()); + for (int i = 0; i < e.size(); i++) { + Assert.assertEquals(new PrincipalSid("u" + i), e.get(i).getSid()); + } + } + @Ignore @Test public void test100000Entries() throws JsonProcessingException { diff --git a/server/src/test/java/org/apache/kylin/rest/service/AclServiceTest.java b/server/src/test/java/org/apache/kylin/rest/service/AclServiceTest.java index 875a2a1..4aabee1 100644 --- a/server/src/test/java/org/apache/kylin/rest/service/AclServiceTest.java +++ b/server/src/test/java/org/apache/kylin/rest/service/AclServiceTest.java @@ -18,7 +18,10 @@ package org.apache.kylin.rest.service; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.kylin.common.persistence.AclEntity; import org.apache.kylin.rest.security.AclPermission; @@ -33,8 +36,12 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.acls.domain.GrantedAuthoritySid; import org.springframework.security.acls.domain.PrincipalSid; import org.springframework.security.acls.model.AccessControlEntry; +import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.AlreadyExistsException; import org.springframework.security.acls.model.NotFoundException; +import org.springframework.security.acls.model.ObjectIdentity; +import org.springframework.security.acls.model.Permission; +import org.springframework.security.acls.model.Sid; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -132,6 +139,26 @@ public class AclServiceTest extends ServiceTestBase { } } + @Test + public void testBatchUpsertAce() { + switchToAdmin(); + ObjectIdentity oid = oid("acl"); + MutableAclRecord acl = (MutableAclRecord) aclService.createAcl(oid); + final Map<Sid, Permission> sidToPerm = new HashMap<>(); + for (int i = 0; i < 10; i++) { + sidToPerm.put(new PrincipalSid("u" + i), AclPermission.ADMINISTRATION); + } + aclService.batchUpsertAce(acl, sidToPerm); + + for (Acl a : aclService.readAclsById(Collections.singletonList(oid)).values()) { + List<AccessControlEntry> e = a.getEntries(); + Assert.assertEquals(10, e.size()); + for (int i = 0; i < e.size(); i++) { + Assert.assertEquals(new PrincipalSid("u" + i), e.get(i).getSid()); + } + } + } + private void switchToAdmin() { Authentication adminAuth = new TestingAuthenticationToken("ADMIN", "ADMIN", "ROLE_ADMIN"); SecurityContextHolder.getContext().setAuthentication(adminAuth); -- To stop receiving notification emails like this one, please contact billy...@apache.org.